2 //////////////////////////////////////////////////////////////////////////////////
3 // This program is free software: you can redistribute it and/or modify //
4 // it under the terms of the version 3 of the GNU General Public License //
5 // as published by the Free Software Foundation. //
7 // This program is distributed in the hope that it will be useful, but //
8 // WITHOUT ANY WARRANTY; without even the implied warranty of //
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU //
10 // General Public License for more details. //
12 // You should have received a copy of the GNU General Public License //
13 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
15 // Written by Francois Fleuret //
16 // (C) Ecole Polytechnique Federale de Lausanne //
17 // Contact <pom@epfl.ch> for comments & bug reports //
18 //////////////////////////////////////////////////////////////////////////////////
25 #include <libpng/png.h>
27 #include "rgb_image.h"
29 void RGBImage::allocate() {
30 _bit_plans = new unsigned char **[RGB_DEPTH];
31 _bit_lines = new unsigned char *[RGB_DEPTH * _height];
32 _bit_map = new unsigned char [_width * _height * RGB_DEPTH];
33 for(int k = 0; k < RGB_DEPTH; k++) _bit_plans[k] = _bit_lines + k * _height;
34 for(int k = 0; k < RGB_DEPTH * _height; k++) _bit_lines[k] = _bit_map + k * _width;
37 void RGBImage::deallocate() {
43 RGBImage::RGBImage() : _bit_plans(0), _bit_lines(0), _bit_map(0) { }
45 RGBImage::RGBImage(int width, int height) : _width(width), _height(height) {
47 memset(_bit_map, 0, _width * _height * RGB_DEPTH * sizeof(unsigned char));
50 RGBImage::~RGBImage() {
54 void RGBImage::write_ppm(const char *filename) {
57 if ((outfile = fopen (filename, "wb")) == 0) {
58 fprintf (stderr, "Can't open %s for reading\n", filename);
62 fprintf(outfile, "P6\n%d %d\n255\n", _width, _height);
64 char *raw = new char[_width * _height * 3];
67 for(int y = 0; y < _height; y++) for(int x = 0; x < _width; x++) {
68 raw[k++] = _bit_map[x + _width * (y + _height * RED)];
69 raw[k++] = _bit_map[x + _width * (y + _height * GREEN)];
70 raw[k++] = _bit_map[x + _width * (y + _height * BLUE)];
73 fwrite((void *) raw, sizeof(unsigned char), _width * _height * 3, outfile);
79 void RGBImage::read_ppm(const char *filename) {
80 const int buffer_size = 1024;
82 char buffer[buffer_size];
87 if((infile = fopen (filename, "r")) == 0) {
88 fprintf (stderr, "Can't open %s for reading\n", filename);
92 fgets(buffer, buffer_size, infile);
94 if(strncmp(buffer, "P6", 2) == 0) {
97 fgets(buffer, buffer_size, infile);
98 } while((buffer[0] < '0') || (buffer[0] > '9'));
99 sscanf(buffer, "%d %d", &_width, &_height);
100 fgets(buffer, buffer_size, infile);
101 sscanf(buffer, "%d", &max);
105 unsigned char *raw = new unsigned char[_width * _height * RGB_DEPTH];
106 fread(raw, sizeof(unsigned char), _width * _height * RGB_DEPTH, infile);
109 for(int y = 0; y < _height; y++) for(int x = 0; x < _width; x++) {
110 _bit_plans[RED][y][x] = raw[k++];
111 _bit_plans[GREEN][y][x] = raw[k++];
112 _bit_plans[BLUE][y][x] = raw[k++];
117 } else if(strncmp(buffer, "P5", 2) == 0) {
120 fgets(buffer, buffer_size, infile);
121 } while((buffer[0] < '0') || (buffer[0] > '9'));
122 sscanf(buffer, "%d %d", &_width, &_height);
123 fgets(buffer, buffer_size, infile);
124 sscanf(buffer, "%d", &max);
128 unsigned char *pixbuf = new unsigned char[_width * _height];
129 fread(buffer, sizeof(unsigned char), _width * _height, infile);
132 for(int y = 0; y < _height; y++) for(int x = 0; x < _width; x++) {
133 unsigned char c = pixbuf[k++];
142 cerr << "Can not read ppm of type [" << buffer << "] from " << filename << ".\n";
147 void RGBImage::read_png(const char* filename) {
148 // This is the number of bytes the read_png routine will read to
149 // decide if the file is a PNG or not. According to the png
150 // documentation, it can be 1 to 8 bytes, 8 being the max and the
153 const int header_size = 8;
155 png_byte header[header_size];
156 png_bytep *row_pointers;
161 FILE *fp = fopen(filename, "rb");
163 cerr << "Unable to open file " << filename << " for reading.\n";
168 fread(header, 1, header_size, fp);
169 if (png_sig_cmp(header, 0, header_size)) {
170 cerr << "File " << filename << " does not look like PNG.\n";
175 // create png pointer
176 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
178 cerr << "png_create_read_struct failed\n";
183 // create png info struct
184 png_infop info_ptr = png_create_info_struct(png_ptr);
186 png_destroy_read_struct(&png_ptr, (png_infopp) 0, (png_infopp) 0);
187 cerr << "png_create_info_struct failed\n";
193 png_init_io(png_ptr, fp);
194 png_set_sig_bytes(png_ptr, header_size);
195 png_read_info(png_ptr, info_ptr);
197 _width = info_ptr->width;
198 _height = info_ptr->height;
200 png_byte bit_depth, color_type, channels;
201 color_type = info_ptr->color_type;
202 bit_depth = info_ptr->bit_depth;
203 channels = info_ptr->channels;
206 cerr << "Can only read 8-bits PNG images." << endl;
210 // allocate image pointer
211 row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * _height);
212 for (int y = 0; y < _height; y++)
213 row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes);
218 png_read_image(png_ptr, row_pointers);
220 // send image to red, green and blue buffers
221 switch (color_type) {
222 case PNG_COLOR_TYPE_GRAY:
224 unsigned char pixel = 0;
225 for (int y = 0; y < _height; y++) for (int x = 0; x < _width; x++) {
226 pixel = row_pointers[y][x];
227 _bit_plans[RED][y][x] = pixel;
228 _bit_plans[GREEN][y][x] = pixel;
229 _bit_plans[BLUE][y][x] = pixel;
234 case PNG_COLOR_TYPE_GRAY_ALPHA:
235 cerr << "PNG type GRAY_ALPHA not supported.\n";
239 case PNG_COLOR_TYPE_PALETTE:
240 cerr << "PNG type PALETTE not supported.\n";
244 case PNG_COLOR_TYPE_RGB:
246 if(channels != RGB_DEPTH) {
247 cerr << "Unsupported number of channels for RGB type\n";
251 for (int y = 0; y < _height; y++) {
253 for (int x = 0; x < _width; x++) {
254 _bit_plans[RED][y][x] = row_pointers[y][k++];
255 _bit_plans[GREEN][y][x] = row_pointers[y][k++];
256 _bit_plans[BLUE][y][x] = row_pointers[y][k++];
262 case PNG_COLOR_TYPE_RGB_ALPHA:
263 cerr << "PNG type RGB_ALPHA not supported.\n";
268 cerr << "Unknown PNG type\n";
273 png_destroy_read_struct(&png_ptr, &info_ptr, 0);
275 for (int y = 0; y < _height; y++) free(row_pointers[y]);
281 void RGBImage::write_png(const char *filename) {
282 png_bytep *row_pointers;
285 FILE *fp = fopen(filename, "wb");
288 cerr << "Unable to create image '" << filename << "'\n";
292 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
295 cerr << "png_create_write_struct failed\n";
300 png_infop info_ptr = png_create_info_struct(png_ptr);
302 cerr << "png_create_info_struct failed\n";
307 png_init_io(png_ptr, fp);
309 png_set_IHDR(png_ptr, info_ptr, _width, _height,
310 8, 2, PNG_INTERLACE_NONE,
311 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
313 png_write_info(png_ptr, info_ptr);
316 row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * _height);
317 for (int y = 0; y < _height; y++)
318 row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes);
321 for (int y = 0; y < _height; y++) {
323 for (int x = 0; x < _width; x++) {
324 row_pointers[y][k++] = _bit_map[x + _width * (y + _height * RED)];
325 row_pointers[y][k++] = _bit_map[x + _width * (y + _height * GREEN)];
326 row_pointers[y][k++] = _bit_map[x + _width * (y + _height * BLUE)];
330 png_write_image(png_ptr, row_pointers);
331 png_write_end(png_ptr, 0);
333 png_destroy_write_struct(&png_ptr, &info_ptr);
335 // cleanup heap allocation
336 for (int y = 0; y < _height; y++) free(row_pointers[y]);