/* * imageio.cpp Copyright (C) 2009-2010 Paolo Medici * * This library is free software; you can redistribute it and/or modify it under the terms of the * GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License along with this library; if not, * write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <fstream> #include <iostream> /** color format */ enum ColorFormat { AUTO, ///< reserved GREY8, ///< 1 BYTE per PIXEL RGB24 ///< 3 BYTE per PIXEL }; /** Image class */ class Image { /** The image format */ ColorFormat m_format; /** The Image Geomtry */ unsigned int m_width, m_height; /** Image stride */ long m_stride; /** The inner buffer */ unsigned char *m_buffer; private: static void pnm_skip_comments(std::istream & i) { while (isspace(i.peek())) { while (isspace(i.peek())) i.get(); if (i.peek() == '#') while (i.peek()!='\r' && i.peek()!='\n') { i.get(); } } } static char pnm_read_header(std::istream &iss, unsigned int & width, unsigned int &height) { char h, t; int max_val; // check pnm header h = iss.get(); t = iss.get(); if(!((h=='P') && ((t=='5')||(t=='6')))) return '\0'; pnm_skip_comments(iss); iss>>width; pnm_skip_comments(iss); iss>>height; pnm_skip_comments(iss); iss>>max_val; iss.get(); // TODO: use a getline fn return t; } /// private costructor to avoid copy Image(const Image & prv) { } public: Image() : m_width(0), m_height(0), m_buffer(0) { } ~Image() { delete [] m_buffer; } /// destroy image and realloc buffer bool alloc(unsigned int width, unsigned int height, ColorFormat format) { delete [] m_buffer; // buffer size m_width = width; m_height = height; m_format = format; m_stride = m_width * bytes_per_pixel(); m_buffer = new unsigned char [m_stride * m_height]; } /** return the bytes per pixel */ inline unsigned int bytes_per_pixel() const { return (m_format==GREY8)?1:(m_format==RGB24)?3:0; } /** return the image size in bytes */ inline unsigned int memsize() const { return m_stride * m_height; } /** return the image size in pixels */ inline unsigned int size() const { return m_width * m_height; } /** image width */ inline unsigned int width() const { return m_width; } /** image height */ inline unsigned int height() const { return m_height; } /** color format */ inline ColorFormat format() const { return m_format; } /** data access */ inline const unsigned char *data() const { return m_buffer; } inline unsigned char *data() { return m_buffer; } /** data access */ inline unsigned char operator [] (int i) const { return m_buffer[i]; } inline unsigned char & operator [] (int i) { return m_buffer[i]; } /** data access (column, row) */ inline unsigned char operator () (int i, int j) const { return m_buffer[i + j * m_stride ]; } inline unsigned char & operator () (int i, int j) { return m_buffer[i + j * m_stride ]; } /// Load a PGM/PPM image, reserve memory with new and return geometry /// @param [in] file filename /// @return true if image is loaded correctly bool load(const char *file, ColorFormat format = AUTO ) { std::ifstream istr(file); if(!istr) { std::cerr << "cannot access " << file << std::endl; return false; } unsigned int width, height; char header = pnm_read_header(istr, width, height); if(header != '5' && header != '6') { std::cerr << file << " is not a PNM RawBits file: Format " << header << " and only 5 or 6 are allowed" << std::endl; return false; } if(header=='5' && ( (format == GREY8) || (format == AUTO) ) ) { alloc(width, height, GREY8); istr.read(reinterpret_cast<char *>(m_buffer), m_stride * m_height); return true; } else if(header=='6' && ( (format == RGB24) || (format == AUTO) ) ) { alloc(width, height, RGB24); istr.read(reinterpret_cast<char *>(m_buffer), m_stride * m_height); return true; } else return false; } /** Write a PGM/PPM file * @param filename a file * @return true if file is created */ bool save(const char *filename) const { if(m_format == RGB24) { std::ofstream out(filename, std::ios::out | std::ios::binary); if(out) { out << "P6\n" << m_width << ' ' << m_height << "\n255\n"; out.write(reinterpret_cast<const char *>(m_buffer), m_width*m_height*3); return true; } else return false; } else if(m_format == GREY8) { std::ofstream out(filename, std::ios::out | std::ios::binary); if(out) { out << "P5\n" << m_width << ' ' << m_height << "\n255\n"; out.write(reinterpret_cast<const char *>(m_buffer), m_width*m_height); return true; } else return false; } } }; ////////////////////////////// Example of uses ////////////////////////// int main() { Image img; if(!img.load("test.pgm")) std::cerr << "cannot load image" << std::endl; else { std::cout << img.width() << 'x' << img.height() << std::endl; // todo.. elaborate for(int i = 0;i<img.size(); ++i) img[i] = 255 - img[i]; img.save("test2.pgm"); } return 0; }