X-Git-Url: http://www.fmaj7b5.info/git?p=cuda.git;a=blobdiff_plain;f=libutils%2FImageIO.cpp;fp=libutils%2FImageIO.cpp;h=309e8ea87c7e7d2a89c6675fdf7f9f36e1fa4dbe;hp=0000000000000000000000000000000000000000;hb=8b2c111ed060599c6bc93b48732d36f8aa48eb2b;hpb=3b1cd69345c4ba6a4357dba81e988ebc66665392 diff --git a/libutils/ImageIO.cpp b/libutils/ImageIO.cpp new file mode 100644 index 0000000..309e8ea --- /dev/null +++ b/libutils/ImageIO.cpp @@ -0,0 +1,262 @@ +/* + Copyright (C) 2012 fmaj7b5.info + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "stdafx.h" +#include "ImageIO.h" + +using namespace FM7b5; + +struct PbmHeader +{ + char magic[3]; + int width; + int height; + int depth; + + PbmHeader() + : width(0), height(0), depth(0) + { + magic[0] = magic[1] = magic[2] = '\0'; + } +}; + +/* declarations for static functions */ +static bool read_header(FILE* fp, PbmHeader* header); +static bool read_magic(FILE* fp, char magic[3]); +static bool read_digit(FILE* fp, int* val); +static bool read_whitespace(FILE* fp); +static bool skip_comment(FILE* fp); +static bool read_end_of_line(FILE* fp); + + +Image +FM7b5::loadPGM(const std::string& filename) +{ + FILE* fp(nullptr); + + if (fopen_s(&fp, filename.c_str(), "rb") != 0) { + throw std::runtime_error(__FUNCTION__ ": could not open a file."); + } + + try { + PbmHeader header; + read_header(fp, &header); + + printf("--- header ---\n"); + printf("magic: %s\n", header.magic); + printf("size : %dx%d\n", header.width, header.height); + printf("depth: %d\n", header.depth); + + /* check if the color format is supported */ + if (header.magic[1] != '2' && header.magic[1] != '5') { + throw std::runtime_error(__FUNCTION__ ": non support format."); + } + if (header.depth != 255) { + throw std::runtime_error(__FUNCTION__ ": supported depth is 255 only."); + } + + Image img(header.width, header.height); + + switch (header.magic[1]) { + case '2': // Gray ASCII format + for (size_t h = 0; h < img.height(); ++h) { + for (size_t w = 0; w < img.width(); ++w) { + while (read_whitespace(fp)); + + int val; + if (!read_digit(fp, &val)) { + throw std::runtime_error(__FUNCTION__ ": invalid data."); + } + + img(w, h) = static_cast(val); + } + } + break; + + case '5': // Gray binary format + { + const size_t size(header.width * header.height); + size_t ret = fread(img.data(), sizeof(std::uint8_t), size, fp); + if (ret != size) { + throw std::runtime_error(__FUNCTION__ ": insufficient data."); + } + } + break; + + default: + throw std::runtime_error(__FUNCTION__ ": unexpected format was specified."); + } + + printf("successfully read (^^\n"); + + return img; + } + catch (...) + { + fclose(fp); + throw; + } +} + + +bool +read_header(FILE* fp, PbmHeader* header) +{ + if (!read_magic(fp, header->magic) || !read_whitespace(fp)) { + throw std::runtime_error(__FUNCTION__ ": not a netpbm file."); + } + + while (read_whitespace(fp)); // skip comments and white spaces + + if (!read_digit(fp, &header->width) || !read_whitespace(fp)) { + throw std::runtime_error(__FUNCTION__ ": invalid width."); + } + + if (!read_digit(fp, &header->height) || !read_whitespace(fp)) { + throw std::runtime_error(__FUNCTION__ ": invalid height."); + } + + if (!read_digit(fp, &header->depth)) { + throw std::runtime_error(__FUNCTION__ ": invalid depth."); + } + + if (!read_whitespace(fp)) { + throw std::runtime_error(__FUNCTION__ ": just one white space is required right after the depth value."); + } + + return true; +} + +bool +read_magic(FILE* fp, char magic[3]) +{ + size_t pos(0); + + magic[pos++] = fgetc(fp); + if (magic[0] != 'P') { + goto on_error; + } + + magic[pos++] = fgetc(fp); + if (!isdigit(magic[1])) { + goto on_error; + } + magic[2] = '\0'; + + return true; + +on_error: + for (size_t i = 0; i < pos; ++i) { + ungetc(magic[i], fp); + magic[i] = '\0'; + } + return false; +} + +bool +read_digit(FILE* fp, int* val) +{ + static const size_t buf_size(16); + + char buf[buf_size]; + size_t pos(0); + for (pos = 0; pos < buf_size; ++pos) { + buf[pos] = fgetc(fp); + if (!isdigit(buf[pos])) { + break; + } + } + if (pos == 0) { + ungetc(buf[0], fp); + return false; + } + if (pos == buf_size) { // too long digits + for (size_t i = 0; i < buf_size; ++i) { + ungetc(buf[i], fp); + return false; + } + } + + // push back the next char + ungetc(buf[pos], fp); + + // read a number + buf[pos] = '\0'; + *val = atoi(buf); + + return true; +} + +bool +read_whitespace(FILE* fp) +{ + while (skip_comment(fp)); + + char ch = fgetc(fp); + + if (!isspace(ch)) { + ungetc(ch, fp); + return false; + } + + // check CR+LF + if (ch == '\r') { + ch = fgetc(fp); + if (ch != '\n') { + ungetc(ch, fp); + } + } + + return true; +} + +bool +skip_comment(FILE* fp) +{ + char ch = fgetc(fp); + + if (ch != '#') { + ungetc(ch, fp); + return false; + } + + // skip to eol + while (!read_end_of_line(fp)) { + ch = fgetc(fp); + } + + return true; +} + +bool +read_end_of_line(FILE* fp) +{ + char ch = fgetc(fp); + + if (ch == '\r') { + ch = fgetc(fp); + if (ch != '\n') { + ungetc(ch, fp); + } + } + else if (ch != '\n') { // not an end_of_line + ungetc(ch, fp); + return false; + } + + return true; +} \ No newline at end of file