3 // PNGDIB - a mini PNG<->DIB (BMP) image conversion library for Win32
5 // This software may be used without restriction.
15 #include "..\..\libpng\png.h"
17 #define PNGDIB_INTERNALS
21 #define PNGDIB_SRC_VERSION 30001
22 #define PNGDIB_SRC_VERSION_STRING _T("3.0.1")
25 #if PNGDIB_SRC_VERSION != PNGDIB_HEADER_VERSION
26 #error Wrong PNGDIB header file version
29 #if (PNG_LIBPNG_VER<10202) || \
30 (PNG_LIBPNG_VER==10202 && PNG_LIBPNG_BUILD_TYPE<2) || \
31 (PNG_LIBPNG_VER==10202 && PNG_LIBPNG_BUILD_TYPE==2 && PNG_LIBPNG_VER_BUILD<5)
32 #error libpng 1.2.2b5 or higher is recommended
33 /* You can comment out the previous line if you aren't using gamma
34 * correction, or don't care about a few obscure gamma correction
35 * problems that exist in earlier versions of libpng. */
39 // This is basically a Windows-only utility with a simple-as-possible
40 // interface, so I'm not too concerned about allowing a
41 // user-configurable screen gamma.
42 //static const double screen_gamma = 2.2;
44 #define MAX_ERRMSGLEN 100
51 static void pngd_get_error_message(int rv
,TCHAR
*e
)
54 case PNGD_E_ERROR
: lstrcpy(e
,_T("Unknown error")); break;
55 case PNGD_E_VERSION
: lstrcpy(e
,_T("Incompatible library version")); break;
56 case PNGD_E_NOMEM
: lstrcpy(e
,_T("Unable to allocate memory")); break;
57 case PNGD_E_UNSUPP
: lstrcpy(e
,_T("Invalid or unsupported image")); break;
58 case PNGD_E_LIBPNG
: lstrcpy(e
,_T("libpng reported an error")); break;
59 case PNGD_E_BADBMP
: lstrcpy(e
,_T("Invalid BMP image")); break;
60 case PNGD_E_BADPNG
: lstrcpy(e
,_T("Invalid PNG image")); break;
61 case PNGD_E_READ
: lstrcpy(e
,_T("Unable to read file")); break;
62 case PNGD_E_WRITE
: lstrcpy(e
,_T("Unable to write file")); break;
66 static unsigned char* uncompress_dib(LPBITMAPINFO lpbmi1
, int infosize
, void *lpbits1
)
68 LPBITMAPINFOHEADER lpdib2
;
69 unsigned char *lpbits2
;
71 int linesize
, bitssize
;
77 LPBITMAPINFOHEADER lpdib1
;
79 lpdib1
=(LPBITMAPINFOHEADER
)lpbmi1
;
80 width
=lpdib1
->biWidth
;
81 height
=lpdib1
->biHeight
;
83 linesize
= (((width
* lpdib1
->biBitCount
)+31)/32)*4;
84 bitssize
= linesize
*height
;
86 lpdib2
= (LPBITMAPINFOHEADER
)malloc(infosize
);
87 if(!lpdib2
) return NULL
;
89 // create a header for the new uncompressed DIB
90 CopyMemory((void*)lpdib2
,(void*)lpdib1
,infosize
);
91 lpdib2
->biCompression
=BI_RGB
;
92 lpdib2
->biSizeImage
=0;
94 lpbits2
= (unsigned char*)malloc(bitssize
);
95 if(!lpbits2
) { free((void*)lpdib2
); return NULL
; }
98 // Windows bitmap handling functions are not exactly convenient,
99 // especially when trying to deal with DIBs. Every function wants
100 // to convert them into DDBs. We have to play stupid games and
101 // convert back and forth. This probably uses too much memory,
102 // and I'm not 100% sure it is exactly correct, but it seems to
105 hb
=CreateDIBSection(NULL
,(LPBITMAPINFO
)lpdib2
,DIB_RGB_COLORS
,&whatever
,NULL
,0);
107 hdc
=CreateCompatibleDC(NULL
);
108 rvgdi
=SelectObject(hdc
,hb
);
109 //SetStretchBltMode(hdc,COLORONCOLOR);
110 rvi
=StretchDIBits(hdc
,
113 lpbits1
, (LPBITMAPINFO
)lpdib1
,
114 DIB_RGB_COLORS
,SRCCOPY
);
115 rvi
=GetDIBits(hdc
,hb
,0,height
, (LPVOID
)lpbits2
,
116 (LPBITMAPINFO
)lpdib2
,DIB_RGB_COLORS
);
126 static void my_png_error_fn(png_structp png_ptr
, const char *err_msg
)
128 struct errstruct
*errinfop
;
131 errinfop
= (struct errstruct
*)png_get_error_ptr(png_ptr
);
135 _snwprintf(errinfop
->errmsg
,MAX_ERRMSGLEN
,_T("[libpng] %S"),err_msg
);
137 _snprintf(errinfop
->errmsg
,MAX_ERRMSGLEN
,"[libpng] %s",err_msg
);
140 errinfop
->errmsg
[MAX_ERRMSGLEN
-1]='\0';
145 static void my_png_warning_fn(png_structp png_ptr
, const char *warn_msg
)
150 // A callback function used when reading memory-mapped PNG files.
151 static void my_png_read_fn(png_structp png_ptr
,
152 png_bytep data
, png_size_t length
)
154 struct p2d_struct
*p2d
;
156 p2d
= (struct p2d_struct
*)png_get_io_ptr(png_ptr
);
158 if(p2d
->input_memblk_size
>0) {
159 if((int)length
> (p2d
->input_memblk_size
- p2d
->input_memblk_curpos
)) {
160 png_error(png_ptr
, "read error: unexpected end of file");
165 CopyMemory((void*)data
,(void*)&p2d
->input_memblk
[p2d
->input_memblk_curpos
],length
);
166 p2d
->input_memblk_curpos
+=length
;
170 // This function should perform identically to libpng's gamma correction.
171 // I'd prefer to have libpng do all gamma correction itself,
172 // but I can't figure out how to do that efficiently.
173 static void gamma_correct(double screen_gamma
,double file_gamma
,
174 unsigned char *red
, unsigned char *green
, unsigned char *blue
)
178 #ifndef PNG_GAMMA_THRESHOLD
179 # define PNG_GAMMA_THRESHOLD 0.05
182 if(fabs(screen_gamma
*file_gamma
-1.0)<=PNG_GAMMA_THRESHOLD
) return;
184 if (screen_gamma
>0.000001)
185 g
=1.0/(file_gamma
*screen_gamma
);
189 (*red
) = (unsigned char)(pow((double)(*red
)/255.0,g
)*255.0+0.5);
190 (*green
) = (unsigned char)(pow((double)(*green
)/255.0,g
)*255.0+0.5);
191 (*blue
) = (unsigned char)(pow((double)(*blue
)/255.0,g
)*255.0+0.5);
195 int PNGDIB_DECL
pngdib_p2d_run(PNGDIB
*qq
)
197 struct p2d_struct
*p2d
;
202 struct errstruct errinfo
;
203 png_uint_32 width
, height
;
204 int png_bit_depth
, color_type
, interlace_type
;
205 png_colorp png_palette
;
206 png_uint_32 res_x
, res_y
;
207 int has_phys
, has_gama
;
211 unsigned char **row_pointers
;
212 unsigned char *lpdib
;
213 unsigned char *dib_palette
;
214 unsigned char *dib_bits
;
215 unsigned char *tmprow
;
216 int dib_bpp
, dib_bytesperrow
;
219 png_color_16 bkgd
; // used with png_set_background
220 int has_trns
, trns_color
;
221 int has_bkgd
; // ==1 if there a bkgd chunk, and USE_BKGD flag
222 png_color_16p temp_colorp
;
223 png_color_16p bg_colorp
; // background color (if has_bkgd)
224 png_bytep trns_trans
;
227 struct PNGD_COLOR_struct bkgd_color
;
228 int is_grayscale
,has_alpha_channel
;
233 p2d
=(struct p2d_struct
*)qq
;
248 lstrcpy(p2d
->common
.errmsg
,_T(""));
250 if(p2d
->use_custom_bg_flag
) {
251 bkgd_color
.red
= p2d
->bgcolor
.red
;
252 bkgd_color
.green
= p2d
->bgcolor
.green
;
253 bkgd_color
.blue
= p2d
->bgcolor
.blue
;
256 bkgd_color
.red
= 255; // Should never get used. If the
257 bkgd_color
.green
= 128; // background turns orange, it's a bug.
261 // Set the user-defined pointer to point to our jmp_buf. This will
262 // hopefully protect against potentially different sized jmp_buf's in
263 // libpng, while still allowing this library to be threadsafe.
264 errinfo
.jbufp
= &jbuf
;
265 errinfo
.errmsg
= p2d
->common
.errmsg
;
267 png_ptr
= png_create_read_struct(PNG_LIBPNG_VER_STRING
,(void*)(&errinfo
),
268 my_png_error_fn
, my_png_warning_fn
);
269 if(!png_ptr
) { rv
=PNGD_E_NOMEM
; goto abort
; }
272 info_ptr
= png_create_info_struct(png_ptr
);
274 //png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
275 rv
=PNGD_E_NOMEM
; goto abort
;
279 // we'll get here if an error occurred in any of the following
286 if(p2d
->input_method
==0) {
287 // reading from a filename
288 if(!p2d
->input_filename
) {
289 wsprintf(p2d
->common
.errmsg
,_T("Input filename not set"));
290 rv
=PNGD_E_ERROR
; goto abort
;
293 if((fp
= _tfopen(p2d
->input_filename
,_T("rb"))) == NULL
) {
297 png_init_io(png_ptr
, fp
);
299 else if(p2d
->input_method
==1) {
300 // reading from a memory block
301 p2d
->input_memblk_curpos
=0;
302 png_set_read_fn(png_ptr
, (void*)p2d
, my_png_read_fn
);
306 png_read_info(png_ptr
, info_ptr
);
308 png_get_IHDR(png_ptr
, info_ptr
, &width
, &height
, &png_bit_depth
, &color_type
,
309 &interlace_type
, NULL
, NULL
);
311 p2d
->color_type
=color_type
;
312 p2d
->bits_per_sample
=png_bit_depth
;
313 p2d
->interlace
=interlace_type
;
315 case PNG_COLOR_TYPE_RGB
: p2d
->bits_per_pixel
=png_bit_depth
*3; break;
316 case PNG_COLOR_TYPE_RGB_ALPHA
: p2d
->bits_per_pixel
=png_bit_depth
*4; break;
317 case PNG_COLOR_TYPE_GRAY_ALPHA
: p2d
->bits_per_pixel
=png_bit_depth
*2; break;
318 default: p2d
->bits_per_pixel
=png_bit_depth
;
321 is_grayscale
= !(color_type
&PNG_COLOR_MASK_COLOR
);
322 has_alpha_channel
= (color_type
&PNG_COLOR_MASK_ALPHA
)?1:0;
324 has_trns
= png_get_valid(png_ptr
,info_ptr
,PNG_INFO_tRNS
);
326 if(p2d
->common
.dib_alpha32
&& (has_trns
|| has_alpha_channel
)) {
327 // Fixme - if trns(for palette) has no transparent entries,
328 // we could skip this.
332 if (!(color_type
&PNG_COLOR_MASK_COLOR
)) {
333 png_set_gray_to_rgb(png_ptr
);
335 else if(color_type
==PNG_COLOR_TYPE_PALETTE
) {
336 png_set_palette_to_rgb(png_ptr
);
339 if (has_trns
) png_set_tRNS_to_alpha(png_ptr
);
344 // look for bKGD chunk, and process if applicable
345 if(p2d
->use_file_bg_flag
) {
346 if(png_get_bKGD(png_ptr
, info_ptr
, &bg_colorp
)) {
347 // process the background, store 8-bit RGB in bkgd_color
350 if(is_grayscale
&& png_bit_depth
<8) {
354 (unsigned char) ( (bg_colorp
->gray
*255)/( (1<<png_bit_depth
)-1 ) );
356 else if(png_bit_depth
<=8) {
357 bkgd_color
.red
=(unsigned char)(bg_colorp
->red
);
358 bkgd_color
.green
=(unsigned char)(bg_colorp
->green
);
359 bkgd_color
.blue
=(unsigned char)(bg_colorp
->blue
);
362 bkgd_color
.red
=(unsigned char)(bg_colorp
->red
>>8);
363 bkgd_color
.green
=(unsigned char)(bg_colorp
->green
>>8);
364 bkgd_color
.blue
=(unsigned char)(bg_colorp
->blue
>>8);
369 if( !(color_type
& PNG_COLOR_MASK_ALPHA
) && !has_trns
) {
370 // If no transparency, we can skip this whole background-color mess.
374 if(has_bkgd
&& (png_bit_depth
>8 || !is_grayscale
|| has_alpha_channel
)) {
375 png_set_background(png_ptr
, bg_colorp
,
376 PNG_BACKGROUND_GAMMA_FILE
, 1, 1.0);
378 else if(is_grayscale
&& has_trns
&& png_bit_depth
<=8
379 && (has_bkgd
|| (p2d
->use_custom_bg_flag
)) )
381 // grayscale binarytrans,<=8bpp: transparency is handle manually
382 // by modifying a palette entry (later)
383 png_get_tRNS(png_ptr
,info_ptr
,&trns_trans
, &i
, &temp_colorp
);
385 trns_color
= temp_colorp
->gray
; // corresponds to a palette entry
389 else if(!has_bkgd
&& (has_trns
|| has_alpha_channel
) &&
390 (p2d
->use_custom_bg_flag
) )
391 { // process most CUSTOM background colors
392 bkgd
.index
= 0; // unused
393 bkgd
.red
= p2d
->bgcolor
.red
;
394 bkgd
.green
= p2d
->bgcolor
.green
;
395 bkgd
.blue
= p2d
->bgcolor
.blue
;
397 // libpng may use bkgd.gray if bkgd.red==bkgd.green==bkgd.blue.
398 // Not sure if that's a libpng bug or not.
399 bkgd
.gray
= p2d
->bgcolor
.red
;
401 if(png_bit_depth
>8) {
402 bkgd
.red
= (bkgd
.red
<<8)|bkgd
.red
;
403 bkgd
.green
= (bkgd
.green
<<8)|bkgd
.green
;
404 bkgd
.blue
= (bkgd
.blue
<<8)|bkgd
.blue
;
405 bkgd
.gray
= (bkgd
.gray
<<8)|bkgd
.gray
;
409 /* assert(png_bit_depth>8); */
411 /* Need to expand to full RGB if unless background is pure gray */
412 if(bkgd
.red
!=bkgd
.green
|| bkgd
.red
!=bkgd
.blue
) {
413 png_set_gray_to_rgb(png_ptr
);
415 // png_set_tRNS_to_alpha() is called here because otherwise
416 // binary transparency for 16-bps grayscale images doesn't
417 // work. Libpng will think black pixels are transparent.
418 // I don't know exactly why it works. It does *not* add an
419 // alpha channel, as you might think (adding an alpha
420 // channnel makes no sense if you are using
421 // png_set_background).
423 // Here's an alternate hack that also seems to work, but
424 // uses direct structure access:
426 // png_ptr->trans_values.red =
427 // png_ptr->trans_values.green =
428 // png_ptr->trans_values.blue = png_ptr->trans_values.gray;
430 png_set_tRNS_to_alpha(png_ptr
);
432 png_set_background(png_ptr
, &bkgd
,
433 PNG_BACKGROUND_GAMMA_SCREEN
, 0, 1.0);
436 else { // gray custom background
437 png_set_background(png_ptr
, &bkgd
,
438 PNG_BACKGROUND_GAMMA_SCREEN
, 1, 1.0);
443 png_set_background(png_ptr
, &bkgd
,
444 PNG_BACKGROUND_GAMMA_SCREEN
, 0, 1.0);
450 // If we don't have any background color at all that we can use,
451 // strip the alpha channel.
452 if(!dib_alpha32
&& has_alpha_channel
&& !has_bkgd
&&
453 !(p2d
->use_custom_bg_flag
) )
455 png_set_strip_alpha(png_ptr
);
459 png_set_strip_16(png_ptr
);
461 if (png_get_sRGB(png_ptr
, info_ptr
, &i
)) {
463 file_gamma
= 0.45455;
465 else if(png_get_gAMA(png_ptr
, info_ptr
, &file_gamma
)) {
470 file_gamma
= 0.45455;
473 if(/*imginfo && */ has_gama
) {
474 p2d
->file_gamma
=file_gamma
;
475 p2d
->gamma_returned
=1;
479 if(p2d
->gamma_correction
) {
481 if(!is_grayscale
|| png_bit_depth
>8 || has_alpha_channel
) {
482 png_set_gamma(png_ptr
, p2d
->screen_gamma
, file_gamma
);
483 //png_ptr->transformations |= 0x2000; // hack for old libpng versions
488 // Gamma correct the background color (if we got it from the file)
489 // before returning it to the app.
490 gamma_correct(p2d
->screen_gamma
,file_gamma
,&bkgd_color
.red
,&bkgd_color
.green
,&bkgd_color
.blue
);
494 png_read_update_info(png_ptr
, info_ptr
);
496 // color type may have changed, due to our transformations
497 color_type
= png_get_color_type(png_ptr
,info_ptr
);
501 case PNG_COLOR_TYPE_RGB_ALPHA
:
505 png_set_bgr(png_ptr
);
507 case PNG_COLOR_TYPE_RGB
:
510 png_set_bgr(png_ptr
);
512 case PNG_COLOR_TYPE_PALETTE
:
513 dib_bpp
=png_bit_depth
;
514 png_get_PLTE(png_ptr
,info_ptr
,&png_palette
,&palette_entries
);
516 case PNG_COLOR_TYPE_GRAY
:
517 case PNG_COLOR_TYPE_GRAY_ALPHA
:
518 dib_bpp
=png_bit_depth
;
519 if(png_bit_depth
>8) dib_bpp
=8;
520 palette_entries
= 1<<dib_bpp
;
521 // we'll construct a grayscale palette later
528 if(dib_bpp
==2) dib_bpp
=4;
530 has_phys
=png_get_valid(png_ptr
,info_ptr
,PNG_INFO_pHYs
);
532 png_get_pHYs(png_ptr
,info_ptr
,&res_x
,&res_y
,&res_unit_type
);
533 if(res_x
>0 && res_y
>0) {
536 p2d
->res_units
=res_unit_type
;
541 // DIB scanlines are padded to 4-byte boundaries.
542 dib_bytesperrow
= (((width
* dib_bpp
)+31)/32)*4;
544 p2d
->bitssize
= height
*dib_bytesperrow
;
546 p2d
->dibsize
=sizeof(BITMAPINFOHEADER
) + 4*palette_entries
+
547 (write_bitfields
?12:0) + p2d
->bitssize
;;
549 if(p2d
->common
.malloc_function
) {
550 lpdib
= (unsigned char*)(*(p2d
->common
.malloc_function
))(p2d
->common
.userdata
,p2d
->dibsize
);
553 lpdib
= (unsigned char*)calloc(p2d
->dibsize
,1);
557 if(!lpdib
) { rv
=PNGD_E_NOMEM
; goto abort
; }
558 p2d
->pdib
= (LPBITMAPINFOHEADER
)lpdib
;
560 row_pointers
=(unsigned char**)malloc(height
*sizeof(unsigned char*));
561 if(!row_pointers
) { rv
=PNGD_E_NOMEM
; goto abort
; }
563 // there is some redundancy here...
564 p2d
->palette_offs
=sizeof(BITMAPINFOHEADER
);
565 p2d
->bits_offs
=sizeof(BITMAPINFOHEADER
) + 4*palette_entries
+ (write_bitfields
?12:0);
566 dib_palette
= &lpdib
[p2d
->palette_offs
];
567 p2d
->palette
= (RGBQUAD
*)dib_palette
;
568 dib_bits
= &lpdib
[p2d
->bits_offs
];
569 p2d
->pbits
= (VOID
*)dib_bits
;
570 p2d
->palette_colors
= palette_entries
;
572 // set up the DIB palette, if needed
574 case PNG_COLOR_TYPE_PALETTE
:
575 for(i
=0;i
<palette_entries
;i
++) {
576 p2d
->palette
[i
].rgbRed
= png_palette
[i
].red
;
577 p2d
->palette
[i
].rgbGreen
= png_palette
[i
].green
;
578 p2d
->palette
[i
].rgbBlue
= png_palette
[i
].blue
;
581 case PNG_COLOR_TYPE_GRAY
:
582 case PNG_COLOR_TYPE_GRAY_ALPHA
:
583 for(i
=0;i
<palette_entries
;i
++) {
584 p2d
->palette
[i
].rgbRed
=
585 p2d
->palette
[i
].rgbGreen
=
586 p2d
->palette
[i
].rgbBlue
= (i
*255)/(palette_entries
-1);
588 gamma_correct(p2d
->screen_gamma
,file_gamma
,
589 &(p2d
->palette
[i
].rgbRed
),
590 &(p2d
->palette
[i
].rgbGreen
),
591 &(p2d
->palette
[i
].rgbBlue
));
595 p2d
->palette
[trns_color
].rgbRed
= bkgd_color
.red
;
596 p2d
->palette
[trns_color
].rgbGreen
= bkgd_color
.green
;
597 p2d
->palette
[trns_color
].rgbBlue
= bkgd_color
.blue
;
602 // set up BITFIELDS, if needed
604 static const unsigned char bf_data
[12] = {
611 lpdib
[p2d
->palette_offs
+i
]=bf_data
[i
];
616 for(j
=0;j
<(int)height
;j
++) {
617 row_pointers
[height
-1-j
]= &dib_bits
[j
*dib_bytesperrow
];
620 png_read_image(png_ptr
, row_pointers
);
622 // special handling for this bit depth, since it doesn't exist in DIBs
623 // expand 2bpp to 4bpp
624 if(png_bit_depth
==2) {
625 tmprow
= (unsigned char*)malloc((width
+3)/4 );
626 if(!tmprow
) { rv
=PNGD_E_NOMEM
; goto abort
; }
628 for(j
=0;j
<(int)height
;j
++) {
629 CopyMemory(tmprow
, row_pointers
[j
], (width
+3)/4 );
630 ZeroMemory(row_pointers
[j
], (width
+1)/2 );
632 for(i
=0;i
<(int)width
;i
++) {
633 row_pointers
[j
][i
/2] |=
634 ( ((tmprow
[i
/4] >> (2*(3-i
%4)) ) & 0x03)<< (4*(1-i
%2)) );
640 free((void*)row_pointers
);
643 png_read_end(png_ptr
, info_ptr
);
645 png_destroy_read_struct(&png_ptr
, &info_ptr
, (png_infopp
)NULL
);
648 if(p2d
->input_method
==0) {
653 // fill in the DIB header fields
654 p2d
->pdib
->biSize
= sizeof(BITMAPINFOHEADER
);
655 p2d
->pdib
->biWidth
= width
;
656 p2d
->pdib
->biHeight
= height
;
657 p2d
->pdib
->biPlanes
= 1;
658 p2d
->pdib
->biBitCount
= dib_bpp
;
659 p2d
->pdib
->biCompression
= write_bitfields
?BI_BITFIELDS
:BI_RGB
;
660 // biSizeImage can also be 0 in uncompressed bitmaps
661 p2d
->pdib
->biSizeImage
= height
*dib_bytesperrow
;
664 if(res_unit_type
==1) {
665 p2d
->pdib
->biXPelsPerMeter
= res_x
;
666 p2d
->pdib
->biYPelsPerMeter
= res_y
;
669 p2d
->pdib
->biClrUsed
= palette_entries
;
670 p2d
->pdib
->biClrImportant
= 0;
672 if(has_bkgd
|| (p2d
->use_custom_bg_flag
)) {
673 // return the background color if one was used
674 p2d
->bgcolor
.red
= bkgd_color
.red
;
675 p2d
->bgcolor
.green
= bkgd_color
.green
;
676 p2d
->bgcolor
.blue
= bkgd_color
.blue
;
677 p2d
->bgcolor_returned
=1;
680 return PNGD_E_SUCCESS
;
684 if(png_ptr
) png_destroy_read_struct(&png_ptr
, &info_ptr
, (png_infopp
)NULL
);
685 if(p2d
->input_method
==0 && fp
) fclose(fp
);
686 if(row_pointers
) free((void*)row_pointers
);
688 pngdib_p2d_free_dib((PNGDIB
*)p2d
,NULL
);
691 // If we don't have an error message yet, use a
692 // default one based on the code
693 if(!lstrlen(p2d
->common
.errmsg
)) {
694 pngd_get_error_message(rv
,p2d
->common
.errmsg
);
700 void PNGDIB_DECL
pngdib_p2d_free_dib(PNGDIB
*qq
, BITMAPINFOHEADER
* pdib
)
702 struct p2d_struct
*p2d
;
705 if(pdib
) free((void*)pdib
);
709 p2d
=(struct p2d_struct
*)qq
;
711 // DIB not explicitly given; use the one from the PNGDIB object.
712 // (this is the normal case)
717 if(p2d
->common
.free_function
) {
718 (*(p2d
->common
.free_function
))(p2d
->common
.userdata
,(void*)pdib
);
726 int PNGDIB_DECL
pngdib_d2p_run(PNGDIB
*qq
)
728 struct d2p_struct
*d2p
;
732 struct errstruct errinfo
;
733 png_text text_ptr
[1];
735 unsigned char *newimage
;
736 RGBQUAD
* dib_palette
;
737 int headersize
, dib_bpp
;
739 png_uint_32 res_x
, res_y
;
747 png_color png_palette
[256];
748 unsigned char **row_pointers
;
752 int bf_format
; // bitfields format identifier
754 int bfsize
; // bytes in "bitfields" section
755 int palsize
; // bytes in palette
757 int palentsize
; // bytes in a palette entry: 3 or 4;
758 BITMAPCOREHEADER
*lpolddib
;
759 int rv
; // return code
762 d2p
=(struct d2p_struct
*)qq
;
764 rv
=PNGD_E_ERROR
; // this should always get changed before returning
772 lstrcpy(d2p
->common
.errmsg
,_T(""));
774 if(!d2p
->output_filename
) {
775 wsprintf(d2p
->common
.errmsg
,_T("Output filename not set"));
776 rv
=PNGD_E_ERROR
; goto abort
;
780 wsprintf(d2p
->common
.errmsg
,_T("Input DIB not set"));
781 rv
=PNGD_E_ERROR
; goto abort
;
785 headersize
= d2p
->pdib
->biSize
;
787 if(headersize
<40 && headersize
!=12) {
788 wsprintf(d2p
->common
.errmsg
,_T("Unexpected BMP header size (%d)"),headersize
);
789 rv
=PNGD_E_BADBMP
; goto abort
;
793 // This is to support an old kind of DIBs (OS/2) that aren't really
796 lpolddib
= (BITMAPCOREHEADER
*) d2p
->pdib
;
797 width
= lpolddib
->bcWidth
;
798 height
= lpolddib
->bcHeight
;
799 dib_bpp
= lpolddib
->bcBitCount
;
800 compression
= BI_RGB
;
803 // This will get adjusted later if there is a palette.
804 // Not sure it's right, though. Do old DIBs always have a
805 // full-sized palette?
810 width
= d2p
->pdib
->biWidth
;
811 height
= d2p
->pdib
->biHeight
;
812 dib_bpp
= d2p
->pdib
->biBitCount
;
813 compression
= d2p
->pdib
->biCompression
;
814 res_x
= d2p
->pdib
->biXPelsPerMeter
;
815 res_y
= d2p
->pdib
->biYPelsPerMeter
;
816 palette_entries
= d2p
->pdib
->biClrUsed
;
819 // supposedly, if the height is negative, the top scanline is stored first
827 if(height
<1 || height
>1000000 || width
<1 || width
>1000000) {
828 wsprintf(d2p
->common
.errmsg
,_T("Unreasonable image dimensions (%dx%d)"),width
,height
);
829 rv
=PNGD_E_BADBMP
; goto abort
;
832 if(dib_bpp
==32 && (d2p
->common
.dib_alpha32
)) {
836 // only certain combinations of compression and bpp are allowed
837 switch(compression
) {
839 if(dib_bpp
!=1 && dib_bpp
!=4 && dib_bpp
!=8 && dib_bpp
!=16
840 && dib_bpp
!=24 && dib_bpp
!=32)
842 wsprintf(d2p
->common
.errmsg
,_T("Unsupported bit depth (%d)"),dib_bpp
);
843 rv
=PNGD_E_UNSUPP
; goto abort
;
848 rv
=PNGD_E_UNSUPP
; goto abort
;
853 rv
=PNGD_E_UNSUPP
; goto abort
;
857 if(dib_bpp
!=16 && dib_bpp
!=32) {
858 rv
=PNGD_E_UNSUPP
; goto abort
;
862 wsprintf(d2p
->common
.errmsg
,_T("Unsupported compression scheme"));
863 return PNGD_E_UNSUPP
;
866 iscompressed
= (compression
==BI_RLE4
|| compression
==BI_RLE8
);
868 // uncompressed dibs are padded to 4-byte bondaries
869 dib_bytesperrow
= (((width
* dib_bpp
)+31)/32)*4;
872 if(palette_entries
==0) palette_entries
= 1<<dib_bpp
;
875 bfsize
= (compression
==BI_BITFIELDS
)?12:0;
877 palsize
=palentsize
*palette_entries
;
880 size
= headersize
+ bfsize
+ palsize
;
882 if(size
>d2p
->dibsize
) {
883 rv
=PNGD_E_BADBMP
; goto abort
;
888 if(d2p
->bitssize
&& !iscompressed
) { // bounds check
889 size
=dib_bytesperrow
*height
;
890 if(size
>d2p
->bitssize
) { rv
=PNGD_E_BADBMP
; goto abort
; }
893 bits
=(unsigned char*)d2p
->pbits
;
896 // If not provided by user, assume the bits immediately
897 // follow the palette.
899 if(d2p
->dibsize
&& !iscompressed
) { // bounds check
900 size
= headersize
+bfsize
+palsize
+dib_bytesperrow
*height
;
901 if(size
>d2p
->dibsize
) { rv
=PNGD_E_BADBMP
; goto abort
; }
904 bits
= &((unsigned char*)(d2p
->pdib
))[headersize
+bfsize
+palsize
];
907 bitfields
= (DWORD
*) ( &((unsigned char*)(d2p
->pdib
))[headersize
] );
908 dib_palette
= (RGBQUAD
*) ( &((unsigned char*)(d2p
->pdib
))[headersize
+bfsize
] );
911 if(compression
==BI_BITFIELDS
) {
913 if (bitfields
[0]==0x00007c00 && bitfields
[1]==0x000003e0 &&
914 bitfields
[2]==0x0000001f) bf_format
=11; // 555
915 else if(bitfields
[0]==0x0000f800 && bitfields
[1]==0x000007e0 &&
916 bitfields
[2]==0x0000001f) bf_format
=12; // 565
917 else { rv
=PNGD_E_UNSUPP
; goto abort
; }
920 if (bitfields
[0]==0x00ff0000 && bitfields
[1]==0x0000ff00 &&
921 bitfields
[2]==0x000000ff) bf_format
=21;
922 else { rv
=PNGD_E_UNSUPP
; goto abort
; }
926 if(bf_format
==0 && dib_bpp
==16) bf_format
=10;
927 if(bf_format
==0 && dib_bpp
==32) bf_format
=20;
930 // Done analyzing the DIB, now time to convert it to PNG
932 // FIXME: this probably isn't quite right
933 // jbuf: see comments in read_png_to_dib()
934 errinfo
.jbufp
= &jbuf
;
935 errinfo
.errmsg
= d2p
->common
.errmsg
;
936 png_ptr
= png_create_write_struct(PNG_LIBPNG_VER_STRING
, (void*)(&errinfo
),
937 my_png_error_fn
, my_png_warning_fn
);
938 if (!png_ptr
) { rv
=PNGD_E_NOMEM
; goto abort
; }
941 info_ptr
= png_create_info_struct(png_ptr
);
943 //png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
944 rv
=PNGD_E_NOMEM
; goto abort
;
948 // we'll get here if an error occurred in any of the following
954 fp
= _tfopen(d2p
->output_filename
,_T("wb"));
960 png_init_io(png_ptr
, fp
);
963 png_color_type
= PNG_COLOR_TYPE_RGB_ALPHA
;
966 png_color_type
= (dib_bpp
>8)?PNG_COLOR_TYPE_RGB
:PNG_COLOR_TYPE_PALETTE
;
969 png_set_IHDR(png_ptr
, info_ptr
, width
, height
, (dib_bpp
>8)?8:dib_bpp
,
971 (d2p
->interlaced
)?PNG_INTERLACE_ADAM7
:PNG_INTERLACE_NONE
,
972 PNG_COMPRESSION_TYPE_BASE
, PNG_FILTER_TYPE_BASE
);
974 // write sRGB and gAMA chunks
975 if(d2p
->file_gamma_valid
) {
976 if(d2p
->file_gamma
>0.454539 && d2p
->file_gamma
<0.454551) {
977 png_set_sRGB(png_ptr
, info_ptr
, PNG_sRGB_INTENT_RELATIVE
);
979 png_set_gAMA(png_ptr
, info_ptr
, d2p
->file_gamma
);
982 // For 16-bit DIBs, we get to write an sBIT chunk.
983 if(bf_format
==10 || bf_format
==11) {
984 pngc8
.red
= 5; pngc8
.green
= 5; pngc8
.blue
= 5;
985 png_set_sBIT(png_ptr
, info_ptr
, &pngc8
);
988 pngc8
.red
= 5; pngc8
.green
= 6; pngc8
.blue
= 5;
989 png_set_sBIT(png_ptr
, info_ptr
, &pngc8
);
993 if(res_x
>0 && res_y
>0)
994 png_set_pHYs(png_ptr
, info_ptr
, res_x
, res_y
, 1);
997 if(palette_entries
>0) {
998 for(i
=0;i
<palette_entries
;i
++) {
1000 png_palette
[i
].red
= ((RGBTRIPLE
*)dib_palette
)[i
].rgbtRed
;
1001 png_palette
[i
].green
= ((RGBTRIPLE
*)dib_palette
)[i
].rgbtGreen
;
1002 png_palette
[i
].blue
= ((RGBTRIPLE
*)dib_palette
)[i
].rgbtBlue
;
1005 png_palette
[i
].red
= dib_palette
[i
].rgbRed
;
1006 png_palette
[i
].green
= dib_palette
[i
].rgbGreen
;
1007 png_palette
[i
].blue
= dib_palette
[i
].rgbBlue
;
1010 png_set_PLTE(png_ptr
, info_ptr
, png_palette
, palette_entries
);
1014 png_set_bgr(png_ptr
);
1016 png_write_info(png_ptr
, info_ptr
);
1018 row_pointers
=(unsigned char**)malloc(height
*sizeof(unsigned char*));
1019 if(!row_pointers
) { rv
=PNGD_E_NOMEM
; goto abort
; }
1022 if(dib_bpp
==16 || (dib_bpp
==32 && !dib_alpha32
)) {
1024 // Special handling for these bit depths.
1025 // This uses a lot of memory, and could be improved by processing
1026 // one line at a time (but that makes it tricky to write interlaced
1029 newimage
=(unsigned char*)malloc(height
*width
*3);
1030 if(!newimage
) { rv
=PNGD_E_NOMEM
; goto abort
; }
1032 for(y
=0;y
<height
;y
++) {
1033 for(x
=0;x
<width
;x
++) {
1035 case 10: case 11: // 16-bit, format 555 (xRRRRRGG GGGBBBBB)
1036 v
= bits
[y
*dib_bytesperrow
+x
*2+0] | (bits
[y
*dib_bytesperrow
+x
*2+1]<<8);
1037 newimage
[(y
*width
+x
)*3+0]= (v
& 0x0000001f)<<3 | (v
& 0x0000001f)>>2; // blue
1038 newimage
[(y
*width
+x
)*3+1]= (v
& 0x000003e0)>>2 | (v
& 0x000003e0)>>7; // green
1039 newimage
[(y
*width
+x
)*3+2]= (v
& 0x00007c00)>>7 | (v
& 0x00007c00)>>12; // red
1041 case 12: // 16-bit, format 565 (RRRRRGGG GGGBBBBB)
1042 v
= bits
[y
*dib_bytesperrow
+x
*2+0] | (bits
[y
*dib_bytesperrow
+x
*2+1]<<8);
1043 newimage
[(y
*width
+x
)*3+0]= (v
& 0x0000001f)<<3 | (v
& 0x0000001f)>>2; // blue
1044 newimage
[(y
*width
+x
)*3+1]= (v
& 0x000007e0)>>3 | (v
& 0x000007e0)>>9; // green
1045 newimage
[(y
*width
+x
)*3+2]= (v
& 0x0000f800)>>8 | (v
& 0x0000f800)>>13; // red
1047 case 20: case 21: // 32-bit, every 4th byte wasted (b g r x)
1048 newimage
[(y
*width
+x
)*3+0]= bits
[y
*dib_bytesperrow
+x
*4+0]; // blue
1049 newimage
[(y
*width
+x
)*3+1]= bits
[y
*dib_bytesperrow
+x
*4+1]; // green
1050 newimage
[(y
*width
+x
)*3+2]= bits
[y
*dib_bytesperrow
+x
*4+2]; // red
1056 for(i
=0;i
<height
;i
++) {
1058 row_pointers
[i
]= &newimage
[i
*width
*3];
1060 row_pointers
[height
-1-i
]= &newimage
[i
*width
*3];
1062 png_write_image(png_ptr
, row_pointers
);
1067 else if(iscompressed
) {
1068 newimage
= uncompress_dib((LPBITMAPINFO
)d2p
->pdib
, headersize
+bfsize
+palsize
, bits
);
1069 if(!newimage
) { rv
=PNGD_E_NOMEM
; goto abort
; }
1070 for(i
=0;i
<height
;i
++) {
1072 row_pointers
[i
]= &newimage
[i
*dib_bytesperrow
];
1074 row_pointers
[height
-1-i
]= &newimage
[i
*dib_bytesperrow
];
1076 png_write_image(png_ptr
, row_pointers
);
1082 for(i
=0;i
<height
;i
++) {
1084 row_pointers
[i
]= &bits
[i
*dib_bytesperrow
];
1086 row_pointers
[height
-1-i
]= &bits
[i
*dib_bytesperrow
];
1088 png_write_image(png_ptr
, row_pointers
);
1091 free((VOID
*)row_pointers
);
1094 if(d2p
->software_id_string
) {
1095 text_ptr
[0].key
= "Software";
1096 text_ptr
[0].text
= d2p
->software_id_string
;
1097 text_ptr
[0].compression
= PNG_TEXT_COMPRESSION_NONE
;
1098 png_set_text(png_ptr
, info_ptr
, text_ptr
, 1);
1101 png_write_end(png_ptr
, info_ptr
);
1106 if(png_ptr
) png_destroy_write_struct(&png_ptr
, &info_ptr
);
1108 if(row_pointers
) free(row_pointers
);
1109 if(newimage
) free(newimage
);
1111 // If we don't have an error message yet, use a
1112 // default one based on the code
1113 if(!lstrlen(d2p
->common
.errmsg
)) {
1114 pngd_get_error_message(rv
,d2p
->common
.errmsg
);
1119 TCHAR
* PNGDIB_DECL
pngdib_get_version_string(void)
1121 return PNGDIB_SRC_VERSION_STRING
;
1124 int PNGDIB_DECL
pngdib_get_version(void)
1126 return PNGDIB_SRC_VERSION
;
1130 PNGDIB
* PNGDIB_DECL
_pngdib_init(int structtype
, int caller_header_vers
)
1134 if(structtype
==PNGD_ST_D2P
) {
1135 struct d2p_struct
*d2p
;
1137 d2p
= (struct d2p_struct
*)calloc(sizeof(struct d2p_struct
),1);
1139 d2p
->common
.structtype
= PNGD_ST_D2P
;
1140 d2p
->file_gamma_valid
= 1;
1141 d2p
->file_gamma
= PNGDIB_DEFAULT_FILE_GAMMA
;
1146 else if(structtype
==PNGD_ST_P2D
) {
1147 struct p2d_struct
*p2d
;
1149 p2d
= (struct p2d_struct
*)calloc(sizeof(struct p2d_struct
),1);
1151 p2d
->common
.structtype
= PNGD_ST_P2D
;
1156 // initialize common fields:
1158 qq
->errmsg
= calloc(PNGDIB_ERRMSG_MAX
,sizeof(TCHAR
));
1165 int PNGDIB_DECL
pngdib_d2p_set_dib(PNGDIB
*qq
,
1166 const BITMAPINFOHEADER
* lpdib
, int dibsize
,
1167 const void* lpbits
, int bitssize
)
1169 struct d2p_struct
*d2p
;
1170 if(qq
->structtype
!=PNGD_ST_D2P
) return 0;
1171 d2p
=(struct d2p_struct
*)qq
;
1174 d2p
->dibsize
= dibsize
;
1175 d2p
->pbits
= lpbits
;
1176 d2p
->bitssize
= bitssize
;
1180 void PNGDIB_DECL
pngdib_d2p_set_interlace(PNGDIB
*qq
, int interlaced
)
1182 struct d2p_struct
*d2p
;
1183 d2p
=(struct d2p_struct
*)qq
;
1184 d2p
->interlaced
= interlaced
;
1187 int PNGDIB_DECL
pngdib_d2p_set_png_filename(PNGDIB
*qq
, const TCHAR
*fn
)
1189 struct d2p_struct
*d2p
;
1190 d2p
=(struct d2p_struct
*)qq
;
1191 d2p
->output_filename
= _tcsdup(fn
);
1192 return (d2p
->output_filename
)?1:0;
1195 int PNGDIB_DECL
pngdib_d2p_set_software_id(PNGDIB
*qq
, const TCHAR
*s
)
1197 struct d2p_struct
*d2p
;
1200 d2p
=(struct d2p_struct
*)qq
;
1203 // The software id is never stored as UNICODE.
1205 d2p
->software_id_string
= calloc(len
+10,1);
1206 _snprintf(d2p
->software_id_string
,len
+10,"%S",s
);
1208 d2p
->software_id_string
= _strdup(s
);
1211 return (d2p
->output_filename
)?1:0;
1215 void PNGDIB_DECL
pngdib_d2p_set_gamma_label(PNGDIB
*qq
, int flag
, double file_gamma
)
1217 struct d2p_struct
*d2p
;
1218 d2p
=(struct d2p_struct
*)qq
;
1219 d2p
->file_gamma_valid
= flag
;
1220 d2p
->file_gamma
= file_gamma
;
1223 int PNGDIB_DECL
pngdib_done(PNGDIB
*qq
)
1225 struct d2p_struct
*d2p
;
1226 struct p2d_struct
*p2d
;
1230 if(qq
->errmsg
) free(qq
->errmsg
);
1232 switch(qq
->structtype
) {
1234 d2p
=(struct d2p_struct
*)qq
;
1235 if(d2p
->output_filename
) free(d2p
->output_filename
);
1236 if(d2p
->software_id_string
) free(d2p
->software_id_string
);
1240 p2d
=(struct p2d_struct
*)qq
;
1241 if(p2d
->input_filename
) free(p2d
->input_filename
);
1248 void PNGDIB_DECL
pngdib_setcallback_malloc(PNGDIB
*qq
,
1249 pngdib_malloc_cb_type mallocfunc
,
1250 pngdib_free_cb_type freefunc
,
1251 pngdib_realloc_cb_type reallocfunc
)
1253 qq
->malloc_function
= mallocfunc
;
1254 qq
->free_function
= freefunc
;
1255 qq
->realloc_function
= reallocfunc
;
1259 TCHAR
* PNGDIB_DECL
pngdib_get_error_msg(PNGDIB
*qq
)
1264 void PNGDIB_DECL
pngdib_set_userdata(PNGDIB
* qq
, void* userdata
)
1266 qq
->userdata
= userdata
;
1269 void* PNGDIB_DECL
pngdib_get_userdata(PNGDIB
* qq
)
1271 return qq
->userdata
;
1275 int PNGDIB_DECL
pngdib_p2d_set_png_filename(PNGDIB
*qq
, const TCHAR
*fn
)
1277 struct p2d_struct
*p2d
;
1278 p2d
=(struct p2d_struct
*)qq
;
1279 p2d
->input_filename
= _tcsdup(fn
);
1280 p2d
->input_method
= 0;
1281 return (p2d
->input_filename
)?1:0;
1284 void PNGDIB_DECL
pngdib_p2d_set_png_memblk(PNGDIB
*qq
, const void *mem
, int memsize
)
1286 struct p2d_struct
*p2d
;
1287 p2d
=(struct p2d_struct
*)qq
;
1288 p2d
->input_memblk
= (unsigned char*)mem
;
1289 p2d
->input_method
= 1;
1291 p2d
->input_memblk_size
= memsize
;
1294 void PNGDIB_DECL
pngdib_p2d_set_use_file_bg(PNGDIB
*qq
, int flag
)
1296 struct p2d_struct
*p2d
;
1297 p2d
=(struct p2d_struct
*)qq
;
1298 p2d
->use_file_bg_flag
= flag
;
1302 void PNGDIB_DECL
pngdib_p2d_set_custom_bg(PNGDIB
*qq
, unsigned char r
,
1303 unsigned char g
, unsigned char b
)
1305 struct p2d_struct
*p2d
;
1306 p2d
=(struct p2d_struct
*)qq
;
1307 p2d
->bgcolor
.red
= r
;
1308 p2d
->bgcolor
.green
= g
;
1309 p2d
->bgcolor
.blue
= b
;
1310 p2d
->use_custom_bg_flag
= 1;
1313 void PNGDIB_DECL
pngdib_p2d_set_gamma_correction(PNGDIB
*qq
, int flag
, double screen_gamma
)
1315 struct p2d_struct
*p2d
;
1316 p2d
=(struct p2d_struct
*)qq
;
1317 p2d
->screen_gamma
= screen_gamma
;
1318 p2d
->gamma_correction
= flag
;
1322 int PNGDIB_DECL
pngdib_p2d_get_dib(PNGDIB
*qq
,
1323 BITMAPINFOHEADER
**ppdib
, int *pdibsize
)
1325 struct p2d_struct
*p2d
;
1326 p2d
=(struct p2d_struct
*)qq
;
1328 if(pdibsize
) *pdibsize
= p2d
->dibsize
;
1332 int PNGDIB_DECL
pngdib_p2d_get_dibbits(PNGDIB
*qq
, void **ppbits
, int *pbitsoffset
, int *pbitssize
)
1334 struct p2d_struct
*p2d
;
1335 p2d
=(struct p2d_struct
*)qq
;
1336 *ppbits
= p2d
->pbits
;
1337 if(pbitsoffset
) *pbitsoffset
= p2d
->bits_offs
;
1338 if(pbitssize
) *pbitssize
= p2d
->bitssize
;
1342 int PNGDIB_DECL
pngdib_p2d_get_palette(PNGDIB
*qq
, RGBQUAD
**ppal
, int *ppaloffset
, int *ppalnumcolors
)
1344 struct p2d_struct
*p2d
;
1345 p2d
=(struct p2d_struct
*)qq
;
1346 if(ppal
) *ppal
= p2d
->palette
;
1347 if(ppaloffset
) *ppaloffset
= p2d
->palette_offs
;
1348 if(ppalnumcolors
) *ppalnumcolors
= p2d
->palette_colors
;
1352 int PNGDIB_DECL
pngdib_p2d_get_colortype(PNGDIB
*qq
)
1354 struct p2d_struct
*p2d
;
1355 p2d
=(struct p2d_struct
*)qq
;
1356 return p2d
->color_type
;
1359 int PNGDIB_DECL
pngdib_p2d_get_bitspersample(PNGDIB
*qq
)
1361 struct p2d_struct
*p2d
;
1362 p2d
=(struct p2d_struct
*)qq
;
1363 return p2d
->bits_per_sample
;
1366 int PNGDIB_DECL
pngdib_p2d_get_bitsperpixel(PNGDIB
*qq
)
1368 struct p2d_struct
*p2d
;
1369 p2d
=(struct p2d_struct
*)qq
;
1370 return p2d
->bits_per_pixel
;
1373 int PNGDIB_DECL
pngdib_p2d_get_samplesperpixel(PNGDIB
*qq
)
1375 struct p2d_struct
*p2d
;
1376 p2d
=(struct p2d_struct
*)qq
;
1377 return p2d
->bits_per_pixel
/p2d
->bits_per_sample
;
1380 int PNGDIB_DECL
pngdib_p2d_get_interlace(PNGDIB
*qq
)
1382 struct p2d_struct
*p2d
;
1383 p2d
=(struct p2d_struct
*)qq
;
1384 return p2d
->interlace
;
1387 int PNGDIB_DECL
pngdib_p2d_get_density(PNGDIB
*qq
, int *pres_x
, int *pres_y
, int *pres_units
)
1389 struct p2d_struct
*p2d
;
1390 p2d
=(struct p2d_struct
*)qq
;
1391 if(p2d
->res_valid
) {
1392 *pres_x
= p2d
->res_x
;
1393 *pres_y
= p2d
->res_y
;
1394 *pres_units
= p2d
->res_units
;
1403 int PNGDIB_DECL
pngdib_p2d_get_file_gamma(PNGDIB
*qq
, double *pgamma
)
1405 struct p2d_struct
*p2d
;
1406 p2d
=(struct p2d_struct
*)qq
;
1407 if(p2d
->gamma_returned
) {
1408 *pgamma
= p2d
->file_gamma
;
1414 int PNGDIB_DECL
pngdib_p2d_get_bgcolor(PNGDIB
*qq
, unsigned char *pr
, unsigned char *pg
, unsigned char *pb
)
1416 struct p2d_struct
*p2d
;
1417 p2d
=(struct p2d_struct
*)qq
;
1419 if(p2d
->bgcolor_returned
) {
1420 *pr
= p2d
->bgcolor
.red
;
1421 *pg
= p2d
->bgcolor
.green
;
1422 *pb
= p2d
->bgcolor
.blue
;
1428 void PNGDIB_DECL
pngdib_set_dibalpha32(PNGDIB
*qq
, int flag
)
1430 qq
->dib_alpha32
= flag
;
1434 ////////////////////////////////////
1435 ////////////////////////////////////
1437 #if PNGDIB_V2COMPATIBLE
1439 static void* PNGDIB_DECL
globalalloc_callback(void *userdata
, int memblksize
)
1441 return (void*)GlobalAlloc(GPTR
,memblksize
);
1444 static void PNGDIB_DECL
globalfree_callback(void *userdata
, void *memblk
)
1446 GlobalFree((HGLOBAL
)memblk
);
1450 static void* PNGDIB_DECL
heapalloc_callback(void *userdata
, int memblksize
)
1452 return HeapAlloc((HANDLE
)userdata
,HEAP_ZERO_MEMORY
,memblksize
);
1455 static void PNGDIB_DECL
heapfree_callback(void *userdata
, void *memblk
)
1457 HeapFree((HANDLE
)userdata
,0,memblk
);
1461 int read_png_to_dib(PNGD_P2DINFO
*p2dp
)
1474 qq
=pngdib_p2d_init();
1475 if(!qq
) return PNGD_E_NOMEM
;
1478 // fields through errmsg must exist
1479 if(p2dp
->structsize
<48) return PNGD_E_VERSION
;
1481 // try to be somewhat backward-compatible
1482 if(p2dp
->structsize
>=88) {
1486 if(p2dp
->structsize
>=96) {
1487 if(p2dp
->flags
& PNGD_USE_HEAPALLOC
) {
1490 if(!heap
) heap
= GetProcessHeap();
1495 pngdib_set_userdata(qq
,(void*)heap
);
1496 pngdib_setcallback_malloc(qq
,heapalloc_callback
,heapfree_callback
,NULL
);
1499 pngdib_setcallback_malloc(qq
,globalalloc_callback
,globalfree_callback
,NULL
);
1502 pngdib_p2d_set_png_filename(qq
,p2dp
->pngfn
);
1504 pngdib_p2d_set_gamma_correction(qq
,(p2dp
->flags
&PNGD_GAMMA_CORRECTION
)?1:0,PNGDIB_DEFAULT_SCREEN_GAMMA
);
1506 if(p2dp
->flags
&PNGD_USE_BKGD
)
1507 pngdib_p2d_set_use_file_bg(qq
,1);
1510 if(p2dp
->flags
&PNGD_USE_CUSTOM_BG
) {
1511 pngdib_p2d_set_custom_bg(qq
,p2dp
->bgcolor
.red
,
1512 p2dp
->bgcolor
.green
,p2dp
->bgcolor
.blue
);
1515 if(p2dp
->flags
&PNGD_DIB_ALPHA32
)
1516 pngdib_set_dibalpha32(qq
,1);
1518 errcode
=pngdib_p2d_run(qq
);
1522 pngdib_p2d_get_dib(qq
,&p2dp
->lpdib
, &p2dp
->dibsize
);
1523 pngdib_p2d_get_dibbits(qq
,&p2dp
->lpbits
, &p2dp
->bits_offs
, NULL
);
1524 pngdib_p2d_get_palette(qq
,&p2dp
->palette
, &p2dp
->palette_offs
, &p2dp
->palette_colors
);
1527 p2dp
->color_type
= pngdib_p2d_get_colortype(qq
);
1528 p2dp
->bits_per_sample
= pngdib_p2d_get_bitspersample(qq
);
1529 p2dp
->interlace
= pngdib_p2d_get_interlace(qq
);
1530 p2dp
->bits_per_pixel
= pngdib_p2d_get_bitsperpixel(qq
);
1531 if(pngdib_p2d_get_file_gamma(qq
, &p2dp
->file_gamma
)) {
1532 p2dp
->flags
|= PNGD_GAMMA_RETURNED
;
1534 if(pngdib_p2d_get_density(qq
, &p2dp
->res_x
, &p2dp
->res_y
, &p2dp
->res_units
)) {
1535 p2dp
->flags
|= PNGD_RES_RETURNED
;
1537 if(pngdib_p2d_get_bgcolor(qq
, &p2dp
->bgcolor
.red
, &p2dp
->bgcolor
.green
,
1538 &p2dp
->bgcolor
.blue
))
1540 p2dp
->flags
|= PNGD_BG_RETURNED
;
1546 msg
=pngdib_get_error_msg(qq
);
1547 lstrcpyn(p2dp
->errmsg
,msg
,100);
1555 int write_dib_to_png(PNGD_D2PINFO
*d2pp
)
1561 if(d2pp
->structsize
!= sizeof(PNGD_D2PINFO
)) return PNGD_E_VERSION
;
1563 qq
=pngdib_d2p_init();
1564 if(!qq
) return PNGD_E_NOMEM
;
1565 pngdib_d2p_set_dib(qq
,d2pp
->lpdib
,d2pp
->dibsize
,
1566 d2pp
->lpbits
,d2pp
->bitssize
);
1567 if(d2pp
->flags
&PNGD_INTERLACED
)
1568 pngdib_d2p_set_interlace(qq
,1);
1570 if(d2pp
->flags
&PNGD_NO_GAMMA_LABEL
)
1571 pngdib_d2p_set_gamma_label(qq
,0,0.0);
1573 pngdib_d2p_set_gamma_label(qq
,1,PNGDIB_DEFAULT_FILE_GAMMA
);
1575 pngdib_d2p_set_png_filename(qq
,d2pp
->pngfn
);
1578 pngdib_d2p_set_software_id(qq
, d2pp
->software
);
1580 if(d2pp
->flags
&PNGD_DIB_ALPHA32
)
1581 pngdib_set_dibalpha32(qq
,1);
1583 errcode
=pngdib_d2p_run(qq
);
1586 msg
=pngdib_get_error_msg(qq
);
1587 lstrcpyn(d2pp
->errmsg
,msg
,100);
1594 #endif // PNGDIB_V2COMPATIBLE