The Conley-Morse Graphs Software
pngimage.h
Go to the documentation of this file.
1/////////////////////////////////////////////////////////////////////////////
2///
3/// @file pngimage.h
4///
5/// Writing PNG images.
6/// This file contains the definition of a simple class "PngImage"
7/// which allows one to create an RGB bitmap image of a prescribed size,
8/// set the color of individual pixels, and save the image to a PNG file.
9/// This class also allows to read a PNG image which is automatically
10/// converted to an RGB bitmap.
11///
12/// @author Pawel Pilarczyk
13///
14/////////////////////////////////////////////////////////////////////////////
15
16// Copyright (C) 1997-2020 by Pawel Pilarczyk.
17//
18// This file is part of my research software package. This is free software:
19// you can redistribute it and/or modify it under the terms of the GNU
20// General Public License as published by the Free Software Foundation,
21// either version 3 of the License, or (at your option) any later version.
22//
23// This software is distributed in the hope that it will be useful,
24// but WITHOUT ANY WARRANTY; without even the implied warranty of
25// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26// GNU General Public License for more details.
27//
28// You should have received a copy of the GNU General Public License
29// along with this software; see the file "license.txt". If not,
30// please, see <https://www.gnu.org/licenses/>.
31
32// Started on February 13, 2007. Last revision: February 17, 2013.
33
34
35#ifndef _PWP_PNGIMAGE_H_
36#define _PWP_PNGIMAGE_H_
37
38
39#ifndef WITHOUT_PNG
40#include <png.h>
41#endif
42#include <cstdlib>
43
44
45// --------------------------------------------------
46// ------------------- PNG Image --------------------
47// --------------------------------------------------
48
49/// An interface to the PNG library. Supports creating a 24-bit image,
50/// writing individual pixels, and saving the image to a PNG file.
52{
53public:
54 /// The constructor of an empty 24-bit PNG image.
55 /// The default background color is white.
56 PngImage (int _width, int _height, int _bgcolor = 0xFFFFFF);
57
58 /// The constructor which reads a PNG image from a file.
59 /// Throws an error text message (const char *) in case of failure.
60 PngImage (const char *filename);
61
62 /// The destructor.
63 ~PngImage ();
64
65 /// Plots a pixel in the image with the given RGB color.
66 /// The color is encoded as 0xRRGGBB. Black by default.
67 void putPixel (int x, int y, int color = 0x000000);
68
69 /// Returns the 0xRRGGBB color value of the given pixel
70 /// or -1 if the pixel is outside the image.
71 int getPixel (int x, int y) const;
72
73 /// Returns the width of the image.
74 int width () const;
75
76 /// Returns the height of the image.
77 int height () const;
78
79 /// Writes the image to a PNG file.
80 /// Throws an error text message (const char *) in case of failure.
81 void save (const char *filename) const;
82
83private:
84 /// The copy constructor is not allowed.
85 PngImage (const PngImage &src);
86
87 /// The assignment operator is not allowed.
88 PngImage &operator = (const PngImage &src);
89
90 /// The width of the image in pixels.
92
93 /// The height of the image in pixels.
95
96 /// The buffer of the picture in RGB byte sequences.
97 unsigned char *buffer;
98
99}; /* PngImage */
100
101// --------------------------------------------------
102
103inline PngImage::PngImage (int _width, int _height, int _bgcolor):
104 imgWidth (_width), imgHeight (_height), buffer (0)
105{
106 if ((imgWidth <= 0) || (imgHeight <= 0))
107 throw "Wrong size of a PNG image requested.";
108
109 buffer = new unsigned char [3 * imgWidth * imgHeight];
110
111 unsigned char red =
112 static_cast<unsigned char> ((_bgcolor >> 16) & 0xFF);
113 unsigned char green =
114 static_cast<unsigned char> ((_bgcolor >> 8) & 0xFF);
115 unsigned char blue =
116 static_cast<unsigned char> (_bgcolor & 0xFF);
117 unsigned char *buf = buffer;
118 for (int i = imgWidth * imgHeight; i > 0; -- i)
119 {
120 *(buf ++) = red;
121 *(buf ++) = green;
122 *(buf ++) = blue;
123 }
124 return;
125} /* PngImage::PngImage */
126
128{
129 if (buffer)
130 delete [] buffer;
131 return;
132} /* PngImage::~PngImage */
133
135{
136 return;
137} /* PngImage::PngImage */
138
140{
141 return *this;
142} /* PngImage::operator = */
143
144inline void PngImage::putPixel (int x, int y, int color)
145{
146 if ((x < 0) || (x >= imgWidth) || (y < 0) || (y >= imgHeight))
147 return;
148 unsigned char *buf = buffer + 3 * (imgWidth * y + x);
149 *(buf ++) = static_cast<unsigned char> ((color >> 16) & 0xFF); // R
150 *(buf ++) = static_cast<unsigned char> ((color >> 8) & 0xFF); // G
151 *(buf ++) = static_cast<unsigned char> (color & 0xFF); // B
152 return;
153} /* PngImage::putPixel */
154
155inline int PngImage::getPixel (int x, int y) const
156{
157 if ((x < 0) || (x >= imgWidth) || (y < 0) || (y >= imgHeight))
158 return -1;
159 unsigned char *buf = buffer + 3 * (imgWidth * y + x);
160 return (buf [0] << 16) | (buf [1] << 8) | buf [2];
161} /* PngImage::getPixel */
162
163inline int PngImage::width () const
164{
165 return imgWidth;
166} /* PngImage::width */
167
168inline int PngImage::height () const
169{
170 return imgHeight;
171} /* PngImage::height */
172
173// --------------------------------------------------
174
175inline PngImage::PngImage (const char *filename):
176 imgWidth (0), imgHeight (0), buffer (0)
177{
178#ifndef WITHOUT_PNG
179 using namespace std;
180
181 FILE *fp = fopen (filename, "rb");
182 if (!fp)
183 throw "Unable to open a PNG file.";
184
185 png_byte header [8];
186 for (int i = 0; i < 8; ++ i)
187 header [i] = 0;
188 fread (header, 1, 8, fp);
189 if (png_sig_cmp (header, 0, 8))
190 throw "The file does not contain a PNG image.";
191
192 png_structp png_ptr = png_create_read_struct
193 (PNG_LIBPNG_VER_STRING, 0, 0, 0);
194 // (PNG_LIBPNG_VER_STRING, png_voidp_NULL,
195 // png_error_ptr_NULL, png_error_ptr_NULL);
196 if (!png_ptr)
197 throw "Unable to create a PNG write struct.";
198
199 png_infop info_ptr = png_create_info_struct (png_ptr);
200 if (!info_ptr)
201 {
202 png_destroy_read_struct (&png_ptr, 0, 0);
203 throw "Unable to create a PNG info struct.";
204 }
205
206 if (setjmp (png_jmpbuf (png_ptr)))
207 {
208 png_destroy_read_struct (&png_ptr, &info_ptr, 0);
209 fclose (fp);
210 throw "An error occurred while reading the PNG file.";
211 }
212
213 png_init_io (png_ptr, fp);
214 png_set_sig_bytes (png_ptr, 8);
215
216 int png_transforms = PNG_TRANSFORM_STRIP_16 |
217 PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_PACKING |
218 PNG_TRANSFORM_EXPAND | //PNG_TRANSFORM_GRAY_TO_RGB |
219 PNG_TRANSFORM_SHIFT;
220 png_read_png (png_ptr, info_ptr, png_transforms, 0);
221
222 unsigned width = png_get_image_width (png_ptr, info_ptr);
223 unsigned height = png_get_image_height (png_ptr, info_ptr);
224
225 unsigned rowbytes = png_get_rowbytes (png_ptr, info_ptr);
226 bool gray_image = (rowbytes == width);
227 if (!gray_image && (rowbytes != 3 * width))
228 {
229 throw "Wrong number of bytes per row in a PNG file.";
230 }
231
232 png_bytep *row_pointers = png_get_rows (png_ptr, info_ptr);
233 buffer = new unsigned char [3 * width * height];
234 for (unsigned row = 0; row < height; ++ row)
235 {
236 unsigned char *rowBuffer = buffer + 3 * row * width;
237 unsigned char *rowSource = row_pointers [row];
238 if (gray_image)
239 {
240 for (int i = width; i > 0; -- i)
241 {
242 unsigned char byte = *(rowSource ++);
243 *(rowBuffer ++) = byte;
244 *(rowBuffer ++) = byte;
245 *(rowBuffer ++) = byte;
246 }
247 }
248 else
249 {
250 for (int i = 3 * width; i > 0; -- i)
251 *(rowBuffer ++) = *(rowSource ++);
252 }
253 }
254
255 png_destroy_read_struct (&png_ptr, &info_ptr, 0);
256 fclose (fp);
257
258 imgWidth = width;
260#else
261 if (!filename)
262 return;
263#endif
264 return;
265} /* PngImage::PngImage */
266
267inline void PngImage::save (const char *filename) const
268{
269#ifndef WITHOUT_PNG
270 using namespace std;
271
272 FILE *fp = fopen (filename, "wb");
273 if (!fp)
274 throw "Unable to create a PNG file.";
275
276 png_structp png_ptr = png_create_write_struct
277 (PNG_LIBPNG_VER_STRING, 0, 0, 0);
278 // (PNG_LIBPNG_VER_STRING, png_voidp_NULL,
279 // png_error_ptr_NULL, png_error_ptr_NULL);
280 if (!png_ptr)
281 throw "Unable to create a PNG write struct.";
282
283 png_infop info_ptr = png_create_info_struct (png_ptr);
284 if (!info_ptr)
285 {
286 png_destroy_write_struct (&png_ptr, (png_infopp) 0);
287 throw "Unable to create a PNG info struct.";
288 }
289
290 png_bytep *row_pointers = new png_bytep [imgHeight];
291 for (int i = 0; i < imgHeight; ++ i)
292 row_pointers [i] = buffer + 3 * i * imgWidth;
293
294 if (setjmp (png_jmpbuf (png_ptr)))
295 {
296 png_destroy_write_struct (&png_ptr, &info_ptr);
297 delete [] row_pointers;
298 fclose (fp);
299 throw "An error occurred while writing the PNG file.";
300 }
301
302 png_init_io (png_ptr, fp);
303 png_set_rows (png_ptr, info_ptr, row_pointers);
304 png_set_IHDR (png_ptr, info_ptr, imgWidth, imgHeight,
305 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
306 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
307
308 png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, 0);
309
310 png_destroy_write_struct (&png_ptr, &info_ptr);
311 delete [] row_pointers;
312 fclose (fp);
313#else
314 if (!filename)
315 return;
316#endif
317 return;
318} /* PngImage::save */
319
320
321#endif // _PWP_PNGIMAGE_H_
322
An interface to the PNG library.
Definition: pngimage.h:52
int imgHeight
The height of the image in pixels.
Definition: pngimage.h:94
PngImage(int _width, int _height, int _bgcolor=0xFFFFFF)
The constructor of an empty 24-bit PNG image.
Definition: pngimage.h:103
int width() const
Returns the width of the image.
Definition: pngimage.h:163
PngImage & operator=(const PngImage &src)
The assignment operator is not allowed.
Definition: pngimage.h:139
int height() const
Returns the height of the image.
Definition: pngimage.h:168
int imgWidth
The width of the image in pixels.
Definition: pngimage.h:91
void putPixel(int x, int y, int color=0x000000)
Plots a pixel in the image with the given RGB color.
Definition: pngimage.h:144
void save(const char *filename) const
Writes the image to a PNG file.
Definition: pngimage.h:267
unsigned char * buffer
The buffer of the picture in RGB byte sequences.
Definition: pngimage.h:97
~PngImage()
The destructor.
Definition: pngimage.h:127
int getPixel(int x, int y) const
Returns the 0xRRGGBB color value of the given pixel or -1 if the pixel is outside the image.
Definition: pngimage.h:155