2 Copyright (C) 2012 fmaj7b5.info
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 using namespace FM7b5;
31 : width(0), height(0), depth(0)
33 magic[0] = magic[1] = magic[2] = '\0';
37 /* declarations for static functions */
38 static bool read_header(FILE* fp, PbmHeader* header);
39 static bool read_magic(FILE* fp, char magic[3]);
40 static bool read_digit(FILE* fp, int* val);
41 static bool read_whitespace(FILE* fp);
42 static bool skip_comment(FILE* fp);
43 static bool read_end_of_line(FILE* fp);
47 FM7b5::loadPGM(const std::string& filename)
51 if (fopen_s(&fp, filename.c_str(), "rb") != 0) {
52 throw std::runtime_error(__FUNCTION__ ": could not open a file.");
57 read_header(fp, &header);
59 printf("--- header ---\n");
60 printf("magic: %s\n", header.magic);
61 printf("size : %dx%d\n", header.width, header.height);
62 printf("depth: %d\n", header.depth);
64 /* check if the color format is supported */
65 if (header.magic[1] != '2' && header.magic[1] != '5') {
66 throw std::runtime_error(__FUNCTION__ ": non support format.");
68 if (header.depth != 255) {
69 throw std::runtime_error(__FUNCTION__ ": supported depth is 255 only.");
72 Image<std::uint8_t> img(header.width, header.height);
74 switch (header.magic[1]) {
75 case '2': // Gray ASCII format
76 for (size_t h = 0; h < img.height(); ++h) {
77 for (size_t w = 0; w < img.width(); ++w) {
78 while (read_whitespace(fp));
81 if (!read_digit(fp, &val)) {
82 throw std::runtime_error(__FUNCTION__ ": invalid data.");
85 img(w, h) = static_cast<std::uint8_t>(val);
90 case '5': // Gray binary format
92 const size_t size(header.width * header.height);
93 size_t ret = fread(img.data(), sizeof(std::uint8_t), size, fp);
95 throw std::runtime_error(__FUNCTION__ ": insufficient data.");
101 throw std::runtime_error(__FUNCTION__ ": unexpected format was specified.");
104 printf("successfully read (^^\n");
117 read_header(FILE* fp, PbmHeader* header)
119 if (!read_magic(fp, header->magic) || !read_whitespace(fp)) {
120 throw std::runtime_error(__FUNCTION__ ": not a netpbm file.");
123 while (read_whitespace(fp)); // skip comments and white spaces
125 if (!read_digit(fp, &header->width) || !read_whitespace(fp)) {
126 throw std::runtime_error(__FUNCTION__ ": invalid width.");
129 if (!read_digit(fp, &header->height) || !read_whitespace(fp)) {
130 throw std::runtime_error(__FUNCTION__ ": invalid height.");
133 if (!read_digit(fp, &header->depth)) {
134 throw std::runtime_error(__FUNCTION__ ": invalid depth.");
137 if (!read_whitespace(fp)) {
138 throw std::runtime_error(__FUNCTION__ ": just one white space is required right after the depth value.");
145 read_magic(FILE* fp, char magic[3])
149 magic[pos++] = fgetc(fp);
150 if (magic[0] != 'P') {
154 magic[pos++] = fgetc(fp);
155 if (!isdigit(magic[1])) {
163 for (size_t i = 0; i < pos; ++i) {
164 ungetc(magic[i], fp);
171 read_digit(FILE* fp, int* val)
173 static const size_t buf_size(16);
177 for (pos = 0; pos < buf_size; ++pos) {
178 buf[pos] = fgetc(fp);
179 if (!isdigit(buf[pos])) {
187 if (pos == buf_size) { // too long digits
188 for (size_t i = 0; i < buf_size; ++i) {
194 // push back the next char
195 ungetc(buf[pos], fp);
205 read_whitespace(FILE* fp)
207 while (skip_comment(fp));
228 skip_comment(FILE* fp)
238 while (!read_end_of_line(fp)) {
246 read_end_of_line(FILE* fp)
256 else if (ch != '\n') { // not an end_of_line