00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #ifndef _PWP_PNGIMAGE_H_
00037 #define _PWP_PNGIMAGE_H_
00038
00039
00040 #ifndef WITHOUT_PNG
00041 #include <png.h>
00042 #endif
00043 #include <cstdlib>
00044
00045
00046
00047
00048
00049
00050
00051
00052 class PngImage
00053 {
00054 public:
00055
00056
00057 PngImage (int _width, int _height, int _bgcolor = 0xFFFFFF);
00058
00059
00060
00061 PngImage (const char *filename);
00062
00063
00064 ~PngImage ();
00065
00066
00067
00068 void putPixel (int x, int y, int color = 0x000000);
00069
00070
00071
00072 int getPixel (int x, int y) const;
00073
00074
00075 int width () const;
00076
00077
00078 int height () const;
00079
00080
00081
00082 void save (const char *filename) const;
00083
00084 private:
00085
00086 PngImage (const PngImage &src);
00087
00088
00089 PngImage &operator = (const PngImage &src);
00090
00091
00092 int imgWidth;
00093
00094
00095 int imgHeight;
00096
00097
00098 unsigned char *buffer;
00099
00100 };
00101
00102
00103
00104 inline PngImage::PngImage (int _width, int _height, int _bgcolor):
00105 imgWidth (_width), imgHeight (_height), buffer (0)
00106 {
00107 if ((imgWidth <= 0) || (imgHeight <= 0))
00108 throw "Wrong size of a PNG image requested.";
00109
00110 buffer = new unsigned char [3 * imgWidth * imgHeight];
00111
00112 unsigned char red =
00113 static_cast<unsigned char> ((_bgcolor >> 16) & 0xFF);
00114 unsigned char green =
00115 static_cast<unsigned char> ((_bgcolor >> 8) & 0xFF);
00116 unsigned char blue =
00117 static_cast<unsigned char> (_bgcolor & 0xFF);
00118 unsigned char *buf = buffer;
00119 for (int i = imgWidth * imgHeight; i > 0; -- i)
00120 {
00121 *(buf ++) = red;
00122 *(buf ++) = green;
00123 *(buf ++) = blue;
00124 }
00125 return;
00126 }
00127
00128 inline PngImage::~PngImage ()
00129 {
00130 if (buffer)
00131 delete [] buffer;
00132 return;
00133 }
00134
00135 inline PngImage::PngImage (const PngImage &)
00136 {
00137 return;
00138 }
00139
00140 inline PngImage &PngImage::operator = (const PngImage &)
00141 {
00142 return *this;
00143 }
00144
00145 inline void PngImage::putPixel (int x, int y, int color)
00146 {
00147 if ((x < 0) || (x >= imgWidth) || (y < 0) || (y >= imgHeight))
00148 return;
00149 unsigned char *buf = buffer + 3 * (imgWidth * y + x);
00150 *(buf ++) = static_cast<unsigned char> ((color >> 16) & 0xFF);
00151 *(buf ++) = static_cast<unsigned char> ((color >> 8) & 0xFF);
00152 *(buf ++) = static_cast<unsigned char> (color & 0xFF);
00153 return;
00154 }
00155
00156 inline int PngImage::getPixel (int x, int y) const
00157 {
00158 if ((x < 0) || (x >= imgWidth) || (y < 0) || (y >= imgHeight))
00159 return -1;
00160 unsigned char *buf = buffer + 3 * (imgWidth * y + x);
00161 return (buf [0] << 16) | (buf [1] << 8) | buf [2];
00162 }
00163
00164 inline int PngImage::width () const
00165 {
00166 return imgWidth;
00167 }
00168
00169 inline int PngImage::height () const
00170 {
00171 return imgHeight;
00172 }
00173
00174
00175
00176 inline PngImage::PngImage (const char *filename):
00177 imgWidth (0), imgHeight (0), buffer (0)
00178 {
00179 #ifndef WITHOUT_PNG
00180 using namespace std;
00181
00182 FILE *fp = fopen (filename, "rb");
00183 if (!fp)
00184 throw "Unable to open a PNG file.";
00185
00186 png_byte header [8];
00187 fread (header, 1, 8, fp);
00188 if (png_sig_cmp (header, 0, 8))
00189 throw "The file does not contain a PNG image.";
00190
00191 png_structp png_ptr = png_create_read_struct
00192 (PNG_LIBPNG_VER_STRING, png_voidp_NULL,
00193 png_error_ptr_NULL, png_error_ptr_NULL);
00194 if (!png_ptr)
00195 throw "Unable to create a PNG write struct.";
00196
00197 png_infop info_ptr = png_create_info_struct (png_ptr);
00198 if (!info_ptr)
00199 {
00200 png_destroy_read_struct (&png_ptr, 0, 0);
00201 throw "Unable to create a PNG info struct.";
00202 }
00203
00204 if (setjmp (png_jmpbuf (png_ptr)))
00205 {
00206 png_destroy_read_struct (&png_ptr, &info_ptr, 0);
00207 fclose (fp);
00208 throw "An error occurred while reading the PNG file.";
00209 }
00210
00211 png_init_io (png_ptr, fp);
00212 png_set_sig_bytes (png_ptr, 8);
00213
00214 int png_transforms = PNG_TRANSFORM_STRIP_16 |
00215 PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_PACKING |
00216 PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_SHIFT;
00217 png_read_png (png_ptr, info_ptr, png_transforms, 0);
00218
00219 unsigned width = png_get_image_width (png_ptr, info_ptr);
00220 unsigned height = png_get_image_height (png_ptr, info_ptr);
00221
00222 if (png_get_rowbytes (png_ptr, info_ptr) != 3 * width)
00223 throw "Wrong number of bytes per row in a PNG file.";
00224
00225 png_bytep *row_pointers = png_get_rows (png_ptr, info_ptr);
00226 buffer = new unsigned char [3 * width * height];
00227 for (unsigned row = 0; row < height; ++ row)
00228 {
00229 unsigned char *rowBuffer = buffer + 3 * row * width;
00230 unsigned char *rowSource = row_pointers [row];
00231 for (int i = 3 * width; i > 0; -- i)
00232 *(rowBuffer ++) = *(rowSource ++);
00233 }
00234
00235 png_destroy_read_struct (&png_ptr, &info_ptr, 0);
00236 fclose (fp);
00237
00238 imgWidth = width;
00239 imgHeight = height;
00240 #else
00241 if (!filename)
00242 return;
00243 #endif
00244 return;
00245 }
00246
00247 inline void PngImage::save (const char *filename) const
00248 {
00249 #ifndef WITHOUT_PNG
00250 using namespace std;
00251
00252 FILE *fp = fopen (filename, "wb");
00253 if (!fp)
00254 throw "Unable to create a PNG file.";
00255
00256 png_structp png_ptr = png_create_write_struct
00257 (PNG_LIBPNG_VER_STRING, png_voidp_NULL,
00258 png_error_ptr_NULL, png_error_ptr_NULL);
00259 if (!png_ptr)
00260 throw "Unable to create a PNG write struct.";
00261
00262 png_infop info_ptr = png_create_info_struct (png_ptr);
00263 if (!info_ptr)
00264 {
00265 png_destroy_write_struct (&png_ptr, (png_infopp) 0);
00266 throw "Unable to create a PNG info struct.";
00267 }
00268
00269 png_bytep *row_pointers = new png_bytep [imgHeight];
00270 for (int i = 0; i < imgHeight; ++ i)
00271 row_pointers [i] = buffer + 3 * i * imgWidth;
00272
00273 if (setjmp (png_jmpbuf (png_ptr)))
00274 {
00275 png_destroy_write_struct (&png_ptr, &info_ptr);
00276 delete [] row_pointers;
00277 fclose (fp);
00278 throw "An error occurred while writing the PNG file.";
00279 }
00280
00281 png_init_io (png_ptr, fp);
00282 png_set_rows (png_ptr, info_ptr, row_pointers);
00283 png_set_IHDR (png_ptr, info_ptr, imgWidth, imgHeight,
00284 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
00285 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00286
00287 png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, 0);
00288
00289 png_destroy_write_struct (&png_ptr, &info_ptr);
00290 delete [] row_pointers;
00291 fclose (fp);
00292 #else
00293 if (!filename)
00294 return;
00295 #endif
00296 return;
00297 }
00298
00299
00300 #endif // _PWP_PNGIMAGE_H_
00301