1 //------------------------------------- 2 // PNGFILE.C -- Image File Functions 3 //------------------------------------- 4 5 // Copyright 2000, Willem van Schaik. 6 // 7 // This code is released under the libpng license. 8 // For conditions of distribution and use, see the disclaimer 9 // and license in png.h 10 11 #include <windows.h> 12 #include <commdlg.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 16 #include "png.h" 17 #include "pngfile.h" 18 #include "cexcept.h" 19 20 define_exception_type(const char *); 21 extern struct exception_context the_exception_context[1]; 22 struct exception_context the_exception_context[1]; 23 png_const_charp msg; 24 25 static OPENFILENAME ofn; 26 27 static png_structp png_ptr = NULL; 28 static png_infop info_ptr = NULL; 29 30 31 // cexcept interface 32 33 static void 34 png_cexcept_error(png_structp png_ptr, png_const_charp msg) 35 { 36 if(png_ptr) 37 ; 38 #ifndef PNG_NO_CONSOLE_IO 39 fprintf(stderr, "libpng error: %s\n", msg); 40 #endif 41 { 42 Throw msg; 43 } 44 } 45 46 // Windows open-file functions 47 48 void PngFileInitialize (HWND hwnd) 49 { 50 static TCHAR szFilter[] = TEXT ("PNG Files (*.PNG)\0*.png\0") 51 TEXT ("All Files (*.*)\0*.*\0\0"); 52 53 ofn.lStructSize = sizeof (OPENFILENAME); 54 ofn.hwndOwner = hwnd; 55 ofn.hInstance = NULL; 56 ofn.lpstrFilter = szFilter; 57 ofn.lpstrCustomFilter = NULL; 58 ofn.nMaxCustFilter = 0; 59 ofn.nFilterIndex = 0; 60 ofn.lpstrFile = NULL; // Set in Open and Close functions 61 ofn.nMaxFile = MAX_PATH; 62 ofn.lpstrFileTitle = NULL; // Set in Open and Close functions 63 ofn.nMaxFileTitle = MAX_PATH; 64 ofn.lpstrInitialDir = NULL; 65 ofn.lpstrTitle = NULL; 66 ofn.Flags = 0; // Set in Open and Close functions 67 ofn.nFileOffset = 0; 68 ofn.nFileExtension = 0; 69 ofn.lpstrDefExt = TEXT ("png"); 70 ofn.lCustData = 0; 71 ofn.lpfnHook = NULL; 72 ofn.lpTemplateName = NULL; 73 } 74 75 BOOL PngFileOpenDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName) 76 { 77 ofn.hwndOwner = hwnd; 78 ofn.lpstrFile = pstrFileName; 79 ofn.lpstrFileTitle = pstrTitleName; 80 ofn.Flags = OFN_HIDEREADONLY; 81 82 return GetOpenFileName (&ofn); 83 } 84 85 BOOL PngFileSaveDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName) 86 { 87 ofn.hwndOwner = hwnd; 88 ofn.lpstrFile = pstrFileName; 89 ofn.lpstrFileTitle = pstrTitleName; 90 ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; 91 92 return GetSaveFileName (&ofn); 93 } 94 95 // PNG image handler functions 96 97 BOOL PngLoadImage (PTSTR pstrFileName, png_byte **ppbImageData, 98 int *piWidth, int *piHeight, int *piChannels, png_color *pBkgColor) 99 { 100 static FILE *pfFile; 101 png_byte pbSig[8]; 102 int iBitDepth; 103 int iColorType; 104 double dGamma; 105 png_color_16 *pBackground; 106 png_uint_32 ulChannels; 107 png_uint_32 ulRowBytes; 108 png_byte *pbImageData = *ppbImageData; 109 static png_byte **ppbRowPointers = NULL; 110 int i; 111 112 // open the PNG input file 113 114 if (!pstrFileName) 115 { 116 *ppbImageData = pbImageData = NULL; 117 return FALSE; 118 } 119 120 if (!(pfFile = fopen(pstrFileName, "rb"))) 121 { 122 *ppbImageData = pbImageData = NULL; 123 return FALSE; 124 } 125 126 // first check the eight byte PNG signature 127 128 fread(pbSig, 1, 8, pfFile); 129 if (png_sig_cmp(pbSig, 0, 8)) 130 { 131 *ppbImageData = pbImageData = NULL; 132 return FALSE; 133 } 134 135 // create the two png(-info) structures 136 137 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, 138 (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL); 139 if (!png_ptr) 140 { 141 *ppbImageData = pbImageData = NULL; 142 return FALSE; 143 } 144 145 info_ptr = png_create_info_struct(png_ptr); 146 if (!info_ptr) 147 { 148 png_destroy_read_struct(&png_ptr, NULL, NULL); 149 *ppbImageData = pbImageData = NULL; 150 return FALSE; 151 } 152 153 Try 154 { 155 156 // initialize the png structure 157 158 #if !defined(PNG_NO_STDIO) 159 png_init_io(png_ptr, pfFile); 160 #else 161 png_set_read_fn(png_ptr, (png_voidp)pfFile, png_read_data); 162 #endif 163 164 png_set_sig_bytes(png_ptr, 8); 165 166 // read all PNG info up to image data 167 168 png_read_info(png_ptr, info_ptr); 169 170 // get width, height, bit-depth and color-type 171 172 png_get_IHDR(png_ptr, info_ptr, piWidth, piHeight, &iBitDepth, 173 &iColorType, NULL, NULL, NULL); 174 175 // expand images of all color-type and bit-depth to 3x8 bit RGB images 176 // let the library process things like alpha, transparency, background 177 178 if (iBitDepth == 16) 179 png_set_strip_16(png_ptr); 180 if (iColorType == PNG_COLOR_TYPE_PALETTE) 181 png_set_expand(png_ptr); 182 if (iBitDepth < 8) 183 png_set_expand(png_ptr); 184 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) 185 png_set_expand(png_ptr); 186 if (iColorType == PNG_COLOR_TYPE_GRAY || 187 iColorType == PNG_COLOR_TYPE_GRAY_ALPHA) 188 png_set_gray_to_rgb(png_ptr); 189 190 // set the background color to draw transparent and alpha images over. 191 if (png_get_bKGD(png_ptr, info_ptr, &pBackground)) 192 { 193 png_set_background(png_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); 194 pBkgColor->red = (byte) pBackground->red; 195 pBkgColor->green = (byte) pBackground->green; 196 pBkgColor->blue = (byte) pBackground->blue; 197 } 198 else 199 { 200 pBkgColor = NULL; 201 } 202 203 // if required set gamma conversion 204 if (png_get_gAMA(png_ptr, info_ptr, &dGamma)) 205 png_set_gamma(png_ptr, (double) 2.2, dGamma); 206 207 // after the transformations have been registered update info_ptr data 208 209 png_read_update_info(png_ptr, info_ptr); 210 211 // get again width, height and the new bit-depth and color-type 212 213 png_get_IHDR(png_ptr, info_ptr, piWidth, piHeight, &iBitDepth, 214 &iColorType, NULL, NULL, NULL); 215 216 217 // row_bytes is the width x number of channels 218 219 ulRowBytes = png_get_rowbytes(png_ptr, info_ptr); 220 ulChannels = png_get_channels(png_ptr, info_ptr); 221 222 *piChannels = ulChannels; 223 224 // now we can allocate memory to store the image 225 226 if (pbImageData) 227 { 228 free (pbImageData); 229 pbImageData = NULL; 230 } 231 if ((pbImageData = (png_byte *) malloc(ulRowBytes * (*piHeight) 232 * sizeof(png_byte))) == NULL) 233 { 234 png_error(png_ptr, "Visual PNG: out of memory"); 235 } 236 *ppbImageData = pbImageData; 237 238 // and allocate memory for an array of row-pointers 239 240 if ((ppbRowPointers = (png_bytepp) malloc((*piHeight) 241 * sizeof(png_bytep))) == NULL) 242 { 243 png_error(png_ptr, "Visual PNG: out of memory"); 244 } 245 246 // set the individual row-pointers to point at the correct offsets 247 248 for (i = 0; i < (*piHeight); i++) 249 ppbRowPointers[i] = pbImageData + i * ulRowBytes; 250 251 // now we can go ahead and just read the whole image 252 253 png_read_image(png_ptr, ppbRowPointers); 254 255 // read the additional chunks in the PNG file (not really needed) 256 257 png_read_end(png_ptr, NULL); 258 259 // and we're done 260 261 free (ppbRowPointers); 262 ppbRowPointers = NULL; 263 264 // yepp, done 265 } 266 267 Catch (msg) 268 { 269 png_destroy_read_struct(&png_ptr, &info_ptr, NULL); 270 271 *ppbImageData = pbImageData = NULL; 272 273 if(ppbRowPointers) 274 free (ppbRowPointers); 275 276 fclose(pfFile); 277 278 return FALSE; 279 } 280 281 fclose (pfFile); 282 283 return TRUE; 284 } 285 286 287 BOOL PngSaveImage (PTSTR pstrFileName, png_byte *pDiData, 288 int iWidth, int iHeight, png_color bkgColor) 289 { 290 const int ciBitDepth = 8; 291 const int ciChannels = 3; 292 293 static FILE *pfFile; 294 png_uint_32 ulRowBytes; 295 static png_byte **ppbRowPointers = NULL; 296 int i; 297 298 // open the PNG output file 299 300 if (!pstrFileName) 301 return FALSE; 302 303 if (!(pfFile = fopen(pstrFileName, "wb"))) 304 return FALSE; 305 306 // prepare the standard PNG structures 307 308 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, 309 (png_error_ptr)png_cexcept_error, (png_error_ptr)NULL); 310 if (!png_ptr) 311 { 312 fclose(pfFile); 313 return FALSE; 314 } 315 316 info_ptr = png_create_info_struct(png_ptr); 317 if (!info_ptr) { 318 fclose(pfFile); 319 png_destroy_write_struct(&png_ptr, (png_infopp) NULL); 320 return FALSE; 321 } 322 323 Try 324 { 325 // initialize the png structure 326 327 #if !defined(PNG_NO_STDIO) 328 png_init_io(png_ptr, pfFile); 329 #else 330 png_set_write_fn(png_ptr, (png_voidp)pfFile, png_write_data, png_flush); 331 #endif 332 333 // we're going to write a very simple 3x8 bit RGB image 334 335 png_set_IHDR(png_ptr, info_ptr, iWidth, iHeight, ciBitDepth, 336 PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, 337 PNG_FILTER_TYPE_BASE); 338 339 // write the file header information 340 341 png_write_info(png_ptr, info_ptr); 342 343 // swap the BGR pixels in the DiData structure to RGB 344 345 png_set_bgr(png_ptr); 346 347 // row_bytes is the width x number of channels 348 349 ulRowBytes = iWidth * ciChannels; 350 351 // we can allocate memory for an array of row-pointers 352 353 if ((ppbRowPointers = (png_bytepp) malloc(iHeight * sizeof(png_bytep))) == NULL) 354 Throw "Visualpng: Out of memory"; 355 356 // set the individual row-pointers to point at the correct offsets 357 358 for (i = 0; i < iHeight; i++) 359 ppbRowPointers[i] = pDiData + i * (((ulRowBytes + 3) >> 2) << 2); 360 361 // write out the entire image data in one call 362 363 png_write_image (png_ptr, ppbRowPointers); 364 365 // write the additional chunks to the PNG file (not really needed) 366 367 png_write_end(png_ptr, info_ptr); 368 369 // and we're done 370 371 free (ppbRowPointers); 372 ppbRowPointers = NULL; 373 374 // clean up after the write, and free any memory allocated 375 376 png_destroy_write_struct(&png_ptr, (png_infopp) NULL); 377 378 // yepp, done 379 } 380 381 Catch (msg) 382 { 383 png_destroy_write_struct(&png_ptr, (png_infopp) NULL); 384 385 if(ppbRowPointers) 386 free (ppbRowPointers); 387 388 fclose(pfFile); 389 390 return FALSE; 391 } 392 393 fclose (pfFile); 394 395 return TRUE; 396 } 397 398 #ifdef PNG_NO_STDIO 399 400 static void 401 png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) 402 { 403 png_size_t check; 404 405 /* fread() returns 0 on error, so it is OK to store this in a png_size_t 406 * instead of an int, which is what fread() actually returns. 407 */ 408 check = (png_size_t)fread(data, (png_size_t)1, length, 409 (FILE *)png_ptr->io_ptr); 410 411 if (check != length) 412 { 413 png_error(png_ptr, "Read Error"); 414 } 415 } 416 417 static void 418 png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) 419 { 420 png_uint_32 check; 421 422 check = fwrite(data, 1, length, (FILE *)(png_ptr->io_ptr)); 423 if (check != length) 424 { 425 png_error(png_ptr, "Write Error"); 426 } 427 } 428 429 static void 430 png_flush(png_structp png_ptr) 431 { 432 FILE *io_ptr; 433 io_ptr = (FILE *)CVT_PTR((png_ptr->io_ptr)); 434 if (io_ptr != NULL) 435 fflush(io_ptr); 436 } 437 438 #endif 439 440 //----------------- 441 // end of source 442 //----------------- 443