automatic commit
[pom.git] / rgb_image.cc
1
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.                                //
6 //                                                                              //
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.                                     //
11 //                                                                              //
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/>.         //
14 //                                                                              //
15 // Written by Francois Fleuret                                                  //
16 // (C) Ecole Polytechnique Federale de Lausanne                                 //
17 // Contact <pom@epfl.ch> for comments & bug reports                             //
18 //////////////////////////////////////////////////////////////////////////////////
19
20 #include <iostream>
21 #include <stdio.h>
22 #include <stdlib.h>
23
24 using namespace std;
25
26 #include <libpng/png.h>
27
28 #include "rgb_image.h"
29
30 void RGBImage::allocate() {
31   _bit_plans = new unsigned char **[RGB_DEPTH];
32   _bit_lines = new unsigned char *[RGB_DEPTH * _height];
33   _bit_map = new unsigned char [_width * _height * RGB_DEPTH];
34   for(int k = 0; k < RGB_DEPTH; k++) _bit_plans[k] = _bit_lines + k * _height;
35   for(int k = 0; k < RGB_DEPTH * _height; k++) _bit_lines[k] = _bit_map + k * _width;
36 }
37
38 void RGBImage::deallocate() {
39   delete[] _bit_plans;
40   delete[] _bit_lines;
41   delete[] _bit_map;
42 }
43
44 RGBImage::RGBImage() : _bit_plans(0), _bit_lines(0), _bit_map(0) { }
45
46 RGBImage::RGBImage(int width, int height) : _width(width), _height(height) {
47   allocate();
48   memset(_bit_map, 0, _width * _height * RGB_DEPTH * sizeof(unsigned char));
49 }
50
51 RGBImage::~RGBImage() {
52   deallocate();
53 }
54
55 void RGBImage::write_ppm(const char *filename) {
56   FILE *outfile;
57
58   if ((outfile = fopen (filename, "wb")) == 0) {
59     fprintf (stderr, "Can't open %s for reading\n", filename);
60     exit(1);
61   }
62
63   fprintf(outfile, "P6\n%d %d\n255\n", _width, _height);
64
65   char *raw = new char[_width * _height * 3];
66
67   int k = 0;
68   for(int y = 0; y < _height; y++) for(int x = 0; x < _width; x++) {
69     raw[k++] = _bit_map[x + _width * (y + _height * RED)];
70     raw[k++] = _bit_map[x + _width * (y + _height * GREEN)];
71     raw[k++] = _bit_map[x + _width * (y + _height * BLUE)];
72   }
73
74   fwrite((void *) raw, sizeof(unsigned char), _width * _height * 3, outfile);
75   fclose(outfile);
76
77   delete[] raw;
78 }
79
80 void RGBImage::read_ppm(const char *filename) {
81   const int buffer_size = 1024;
82   FILE *infile;
83   char buffer[buffer_size];
84   int max;
85
86   deallocate();
87
88   if((infile = fopen (filename, "r")) == 0) {
89     fprintf (stderr, "Can't open %s for reading\n", filename);
90     exit(1);
91   }
92
93   fgets(buffer, buffer_size, infile);
94
95   if(strncmp(buffer, "P6", 2) == 0) {
96
97     do {
98       fgets(buffer, buffer_size, infile);
99     } while((buffer[0] < '0') || (buffer[0] > '9'));
100     sscanf(buffer, "%d %d", &_width, &_height);
101     fgets(buffer, buffer_size, infile);
102     sscanf(buffer, "%d", &max);
103
104     allocate();
105
106     unsigned char *raw = new unsigned char[_width * _height * RGB_DEPTH];
107     fread(raw, sizeof(unsigned char), _width * _height * RGB_DEPTH, infile);
108
109     int k = 0;
110     for(int y = 0; y < _height; y++) for(int x = 0; x < _width; x++) {
111       _bit_plans[RED][y][x] = raw[k++];
112       _bit_plans[GREEN][y][x] = raw[k++];
113       _bit_plans[BLUE][y][x] = raw[k++];
114     }
115
116     delete[] raw;
117
118   } else if(strncmp(buffer, "P5", 2) == 0) {
119
120     do {
121       fgets(buffer, buffer_size, infile);
122     } while((buffer[0] < '0') || (buffer[0] > '9'));
123     sscanf(buffer, "%d %d", &_width, &_height);
124     fgets(buffer, buffer_size, infile);
125     sscanf(buffer, "%d", &max);
126
127     allocate();
128
129     unsigned char *pixbuf = new unsigned char[_width * _height];
130     fread(buffer, sizeof(unsigned char), _width * _height, infile);
131
132     int k = 0, l = 0;
133     for(int y = 0; y < _height; y++) for(int x = 0; x < _width; x++) {
134       unsigned char c = pixbuf[k++];
135       _bit_map[l++] = c;
136       _bit_map[l++] = c;
137       _bit_map[l++] = c;
138     }
139
140     delete[] pixbuf;
141
142   } else {
143     cerr << "Can not read ppm of type [" << buffer << "] from " << filename << ".\n";
144     exit(1);
145   }
146 }
147
148 void RGBImage::read_png(const char* filename) {
149   // This is the number of bytes the read_png routine will read to
150   // decide if the file is a PNG or not. According to the png
151   // documentation, it can be 1 to 8 bytes, 8 being the max and the
152   // best.
153
154   const int header_size = 8;
155
156   png_byte header[header_size];
157   png_bytep *row_pointers;
158
159   deallocate();
160
161   // open file
162   FILE *fp = fopen(filename, "rb");
163   if (!fp) {
164     cerr << "Unable to open file " << filename << " for reading.\n";
165     exit(1);
166   }
167
168   // read header
169   fread(header, 1, header_size, fp);
170   if (png_sig_cmp(header, 0, header_size)) {
171     cerr << "File " << filename << " does not look like PNG.\n";
172     fclose(fp);
173     exit(1);
174   }
175
176   // create png pointer
177   png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
178   if (!png_ptr) {
179     cerr << "png_create_read_struct failed\n";
180     fclose(fp);
181     exit(1);
182   }
183
184   // create png info struct
185   png_infop info_ptr = png_create_info_struct(png_ptr);
186   if (!info_ptr) {
187     png_destroy_read_struct(&png_ptr, (png_infopp) 0, (png_infopp) 0);
188     cerr << "png_create_info_struct failed\n";
189     fclose(fp);
190     exit(1);
191   }
192
193   // get image info
194   png_init_io(png_ptr, fp);
195   png_set_sig_bytes(png_ptr, header_size);
196   png_read_info(png_ptr, info_ptr);
197
198   _width = info_ptr->width;
199   _height = info_ptr->height;
200
201   png_byte bit_depth, color_type, channels;
202   color_type = info_ptr->color_type;
203   bit_depth = info_ptr->bit_depth;
204   channels = info_ptr->channels;
205
206   if(bit_depth != 8) {
207     cerr << "Can only read 8-bits PNG images." << endl;
208     exit(1);
209   }
210
211   // allocate image pointer
212   row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * _height);
213   for (int y = 0; y < _height; y++)
214     row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes);
215
216   allocate();
217
218   // read image
219   png_read_image(png_ptr, row_pointers);
220
221   // send image to red, green and blue buffers
222   switch (color_type) {
223   case PNG_COLOR_TYPE_GRAY:
224     {
225       unsigned char pixel = 0;
226       for (int y = 0; y < _height; y++) for (int x = 0; x < _width; x++) {
227         pixel = row_pointers[y][x];
228         _bit_plans[RED][y][x] = pixel;
229         _bit_plans[GREEN][y][x] = pixel;
230         _bit_plans[BLUE][y][x] = pixel;
231       }
232     }
233     break;
234
235   case PNG_COLOR_TYPE_GRAY_ALPHA:
236     cerr << "PNG type GRAY_ALPHA not supported.\n";
237     exit(1);
238     break;
239
240   case PNG_COLOR_TYPE_PALETTE:
241     cerr << "PNG type PALETTE not supported.\n";
242     exit(1);
243     break;
244
245   case PNG_COLOR_TYPE_RGB:
246     {
247       if(channels != RGB_DEPTH) {
248         cerr << "Unsupported number of channels for RGB type\n";
249         break;
250       }
251       int k;
252       for (int y = 0; y < _height; y++) {
253         k = 0;
254         for (int x = 0; x < _width; x++) {
255           _bit_plans[RED][y][x] = row_pointers[y][k++];
256           _bit_plans[GREEN][y][x] = row_pointers[y][k++];
257           _bit_plans[BLUE][y][x] = row_pointers[y][k++];
258         }
259       }
260     }
261     break;
262
263   case PNG_COLOR_TYPE_RGB_ALPHA:
264     cerr << "PNG type RGB_ALPHA not supported.\n";
265     exit(1);
266     break;
267
268   default:
269     cerr << "Unknown PNG type\n";
270     exit(1);
271   }
272
273   // release memory
274   png_destroy_read_struct(&png_ptr, &info_ptr, 0);
275
276   for (int y = 0; y < _height; y++) free(row_pointers[y]);
277   free(row_pointers);
278
279   fclose(fp);
280 }
281
282 void RGBImage::write_png(const char *filename) {
283   png_bytep *row_pointers;
284
285   // create file
286   FILE *fp = fopen(filename, "wb");
287
288   if (!fp) {
289     cerr << "Unable to create image '" << filename << "'\n";
290     exit(1);
291   }
292
293   png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
294
295   if (!png_ptr) {
296     cerr << "png_create_write_struct failed\n";
297     fclose(fp);
298     exit(1);
299   }
300
301   png_infop info_ptr = png_create_info_struct(png_ptr);
302   if (!info_ptr) {
303     cerr << "png_create_info_struct failed\n";
304     fclose(fp);
305     exit(1);
306   }
307
308   png_init_io(png_ptr, fp);
309
310   png_set_IHDR(png_ptr, info_ptr, _width, _height,
311                8, 2, PNG_INTERLACE_NONE,
312                PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
313
314   png_write_info(png_ptr, info_ptr);
315
316   // allocate memory
317   row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * _height);
318   for (int y = 0; y < _height; y++)
319     row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes);
320
321   int k;
322   for (int y = 0; y < _height; y++) {
323     k = 0;
324     for (int x = 0; x < _width; x++) {
325       row_pointers[y][k++] = _bit_map[x + _width * (y + _height * RED)];
326       row_pointers[y][k++] = _bit_map[x + _width * (y + _height * GREEN)];
327       row_pointers[y][k++] = _bit_map[x + _width * (y + _height * BLUE)];
328     }
329   }
330
331   png_write_image(png_ptr, row_pointers);
332   png_write_end(png_ptr, 0);
333
334   png_destroy_write_struct(&png_ptr, &info_ptr);
335
336   // cleanup heap allocation
337   for (int y = 0; y < _height; y++) free(row_pointers[y]);
338   free(row_pointers);
339
340   fclose(fp);
341 }