]> git.saurik.com Git - wxWidgets.git/blame - src/common/imagpng.cpp
When saving the editable state, use the real state (m_editable)
[wxWidgets.git] / src / common / imagpng.cpp
CommitLineData
e9c4b1a2 1/////////////////////////////////////////////////////////////////////////////
27bb2b7c 2// Name: src/common/imagepng.cpp
e9c4b1a2
JS
3// Purpose: wxImage PNG handler
4// Author: Robert Roebling
5// RCS-ID: $Id$
6// Copyright: (c) Robert Roebling
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
27bb2b7c
VZ
10// ============================================================================
11// declarations
12// ============================================================================
13
8f493002
VS
14#ifdef __GNUG__
15#pragma implementation "imagpng.h"
16#endif
e9c4b1a2 17
27bb2b7c
VZ
18// ----------------------------------------------------------------------------
19// headers
20// ----------------------------------------------------------------------------
21
e9c4b1a2
JS
22// For compilers that support precompilation, includes "wx.h".
23#include "wx/wxprec.h"
24
25#ifdef __BORLANDC__
ce4169a4
RR
26 #pragma hdrstop
27#endif
28
29#ifndef WX_PRECOMP
30 #include "wx/defs.h"
e9c4b1a2
JS
31#endif
32
c96ea657 33#if wxUSE_IMAGE && wxUSE_LIBPNG
ce4169a4 34
8f493002 35#include "wx/imagpng.h"
e9c4b1a2
JS
36#include "wx/bitmap.h"
37#include "wx/debug.h"
38#include "wx/log.h"
39#include "wx/app.h"
ce4169a4 40#include "png.h"
e9c4b1a2
JS
41#include "wx/filefn.h"
42#include "wx/wfstream.h"
43#include "wx/intl.h"
44#include "wx/module.h"
45
46// For memcpy
47#include <string.h>
48
49#ifdef __SALFORDC__
50#ifdef FAR
51#undef FAR
52#endif
53#endif
54
27bb2b7c
VZ
55// ----------------------------------------------------------------------------
56// constants
57// ----------------------------------------------------------------------------
58
59// image can not have any transparent pixels at all, have only 100% opaque
60// and/or 100% transparent pixels in which case a simple mask is enough to
61// store this information in wxImage or have a real alpha channel in which case
62// we need to have it in wxImage as well
63enum Transparency
64{
65 Transparency_None,
66 Transparency_Mask,
67 Transparency_Alpha
68};
69
70// ----------------------------------------------------------------------------
71// local functions
72// ----------------------------------------------------------------------------
73
74// return the kind of transparency needed for this image assuming that it does
75// have transparent pixels, i.e. either Transparency_Alpha or Transparency_Mask
76static Transparency
77CheckTransparency(const unsigned char *ptr,
f7155274
VZ
78 png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h,
79 size_t numColBytes);
27bb2b7c
VZ
80
81// init the alpha channel for the image and fill it with 1s up to (x, y)
82static unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y);
83
84// find a free colour for the mask in the PNG data array
85static void
86FindMaskColour(unsigned char **lines, png_uint_32 width, png_uint_32 height,
87 unsigned char& rMask, unsigned char& gMask, unsigned char& bMask);
e9c4b1a2 88
27bb2b7c
VZ
89// ============================================================================
90// wxPNGHandler implementation
91// ============================================================================
e9c4b1a2 92
e9c4b1a2 93IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler,wxImageHandler)
e9c4b1a2 94
e30285ab 95#if wxUSE_STREAMS
9ab6ee85 96
0729bd19 97#ifndef PNGLINKAGEMODE
30e0e251
VZ
98 #ifdef __WATCOMC__
99 // we need an explicit cdecl for Watcom, at least according to
100 //
101 // http://sf.net/tracker/index.php?func=detail&aid=651492&group_id=9863&atid=109863
102 //
103 // more testing is needed for this however, please remove this comment
104 // if you can confirm that my fix works with Watcom 11
105 #define PNGLINKAGEMODE cdecl
106 #else
107 #define PNGLINKAGEMODE LINKAGEMODE
108 #endif
717b9bf2
DW
109#endif
110
bdffd806
VS
111
112// VS: wxPNGInfoStruct declared below is a hack that needs some explanation.
27bb2b7c
VZ
113// First, let me describe what's the problem: libpng uses jmp_buf in
114// its png_struct structure. Unfortunately, this structure is
115// compiler-specific and may vary in size, so if you use libpng compiled
bdffd806 116// as DLL with another compiler than the main executable, it may not work
27bb2b7c 117// (this is for example the case with wxMGL port and SciTech MGL library
bdffd806 118// that provides custom runtime-loadable libpng implementation with jmpbuf
27bb2b7c 119// disabled altogether). Luckily, it is still possible to use setjmp() &
bdffd806
VS
120// longjmp() as long as the structure is not part of png_struct.
121//
122// Sadly, there's no clean way to attach user-defined data to png_struct.
123// There is only one customizable place, png_struct.io_ptr, which is meant
27bb2b7c 124// only for I/O routines and is set with png_set_read_fn or
bdffd806
VS
125// png_set_write_fn. The hacky part is that we use io_ptr to store
126// a pointer to wxPNGInfoStruct that holds I/O structures _and_ jmp_buf.
127
128struct wxPNGInfoStruct
129{
130 jmp_buf jmpbuf;
131 bool verbose;
27bb2b7c 132
bdffd806
VS
133 union
134 {
135 wxInputStream *in;
136 wxOutputStream *out;
137 } stream;
138};
139
140#define WX_PNG_INFO(png_ptr) ((wxPNGInfoStruct*)png_get_io_ptr(png_ptr))
141
27bb2b7c
VZ
142// ----------------------------------------------------------------------------
143// helper functions
144// ----------------------------------------------------------------------------
bdffd806 145
90350682
VZ
146extern "C"
147{
148
149void PNGLINKAGEMODE _PNG_stream_reader( png_structp png_ptr, png_bytep data, png_size_t length )
e9c4b1a2 150{
bdffd806 151 WX_PNG_INFO(png_ptr)->stream.in->Read(data, length);
e9c4b1a2
JS
152}
153
90350682 154void PNGLINKAGEMODE _PNG_stream_writer( png_structp png_ptr, png_bytep data, png_size_t length )
e9c4b1a2 155{
bdffd806 156 WX_PNG_INFO(png_ptr)->stream.out->Write(data, length);
e9c4b1a2
JS
157}
158
deb2fec0
SB
159// from pngerror.c
160// so that the libpng doesn't send anything on stderr
161void
bdffd806 162PNGLINKAGEMODE wx_png_error(png_structp png_ptr, png_const_charp message)
deb2fec0 163{
bdffd806 164 wxPNGInfoStruct *info = WX_PNG_INFO(png_ptr);
2b5f62a0
VZ
165 if (info->verbose)
166 wxLogError( wxString::FromAscii(message) );
bdffd806 167
deb2fec0 168#ifdef USE_FAR_KEYWORD
bdffd806
VS
169 {
170 jmp_buf jmpbuf;
171 png_memcpy(jmpbuf,info->jmpbuf,sizeof(jmp_buf));
172 longjmp(jmpbuf, 1);
173 }
deb2fec0 174#else
bdffd806 175 longjmp(info->jmpbuf, 1);
deb2fec0
SB
176#endif
177}
178
179void
bdffd806 180PNGLINKAGEMODE wx_png_warning(png_structp png_ptr, png_const_charp message)
deb2fec0 181{
bdffd806 182 wxPNGInfoStruct *info = WX_PNG_INFO(png_ptr);
2b5f62a0
VZ
183 if (info->verbose)
184 wxLogWarning( wxString::FromAscii(message) );
deb2fec0
SB
185}
186
90350682
VZ
187} // extern "C"
188
27bb2b7c
VZ
189// ----------------------------------------------------------------------------
190// LoadFile() helpers
191// ----------------------------------------------------------------------------
192
d26d9754
VZ
193// determine the kind of transparency we need for this image: if the only alpha
194// values it has are 0 and 0xff then we can simply create a mask for it, we
195// should be ok with a simple mask but otherwise we need a full blown alpha
196// channel in wxImage
197//
198// parameters:
199// ptr the start of the data to examine
200// x, y starting position
201// w, h size of the image
202// numColBytes number of colour bytes (1 for grey scale, 3 for RGB)
203// (NB: alpha always follows the colour bytes)
27bb2b7c
VZ
204Transparency
205CheckTransparency(const unsigned char *ptr,
d26d9754
VZ
206 png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h,
207 size_t numColBytes)
27bb2b7c 208{
d26d9754
VZ
209 // suppose that a mask will suffice and check all the remaining alpha
210 // values to see if it does
27bb2b7c
VZ
211 unsigned char a2;
212 unsigned const char *ptr2 = ptr;
213 for ( png_uint_32 y2 = y; y2 < h; y2++ )
214 {
215 for ( png_uint_32 x2 = x + 1; x2 < w; x2++ )
216 {
217 // skip the grey byte
d26d9754
VZ
218 ptr2 += numColBytes;
219 a2 = *ptr2++;
27bb2b7c
VZ
220
221 if ( a2 && a2 != 0xff )
222 {
d26d9754
VZ
223 // not fully opaque nor fully transparent, hence need alpha
224 return Transparency_Alpha;
27bb2b7c 225 }
27bb2b7c
VZ
226 }
227 }
228
d26d9754
VZ
229 // mask will be enough
230 return Transparency_Mask;
27bb2b7c
VZ
231}
232
233unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y)
234{
235 // create alpha channel
236 image->SetAlpha();
237
238 unsigned char *alpha = image->GetAlpha();
239
240 // set alpha for the pixels we had so far
241 for ( png_uint_32 y2 = 0; y2 <= y; y2++ )
242 {
243 for ( png_uint_32 x2 = 0; x2 < x; x2++ )
244 {
245 // all the previous pixels were opaque
246 *alpha++ = 0xff;
247 }
248 }
249
250 return alpha;
251}
252
253void
254FindMaskColour(unsigned char **lines, png_uint_32 width, png_uint_32 height,
255 unsigned char& rMask, unsigned char& gMask, unsigned char& bMask)
256{
257 // choosing the colour for the mask is more
258 // difficult: we need to iterate over the entire
259 // image for this in order to choose an unused
260 // colour (this is not very efficient but what else
261 // can we do?)
262 wxImageHistogram h;
263 unsigned nentries = 0;
264 unsigned char r2, g2, b2;
265 for ( png_uint_32 y2 = 0; y2 < height; y2++ )
266 {
267 const unsigned char *p = lines[y2];
268 for ( png_uint_32 x2 = 0; x2 < width; x2++ )
269 {
270 r2 = *p++;
271 g2 = *p++;
272 b2 = *p++;
273
274 wxImageHistogramEntry&
275 entry = h[wxImageHistogram:: MakeKey(r2, g2, b2)];
276
277 if ( entry.value++ == 0 )
278 entry.index = nentries++;
279 }
280 }
281
282 if ( !h.FindFirstUnusedColour(&rMask, &gMask, &bMask) )
283 {
284 wxLogWarning(_("Too many colours in PNG, the image may be slightly blurred."));
285
286 // use a fixed mask colour and we'll fudge
287 // the real pixels with this colour (see
288 // below)
289 rMask = 0xfe;
290 gMask = 0;
291 bMask = 0xff;
292 }
293}
294
295// ----------------------------------------------------------------------------
296// reading PNGs
297// ----------------------------------------------------------------------------
298
299bool wxPNGHandler::DoCanRead( wxInputStream& stream )
300{
301 unsigned char hdr[4];
302
303 if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
304 return FALSE;
305
306 return memcmp(hdr, "\211PNG", WXSIZEOF(hdr)) == 0;
307}
308
309// convert data from RGB to wxImage format
310static
311void CopyDataFromPNG(wxImage *image,
312 unsigned char **lines,
313 png_uint_32 width,
314 png_uint_32 height,
315 int color_type)
316{
317 Transparency transparency = Transparency_None;
318
319 // only non NULL if transparency == Transparency_Alpha
320 unsigned char *alpha = NULL;
321
322 // RGB of the mask colour if transparency == Transparency_Mask
323 // (but init them anyhow to avoid compiler warnings)
324 unsigned char rMask = 0,
325 gMask = 0,
326 bMask = 0;
327
328 unsigned char *ptrDst = image->GetData();
329 if ( !(color_type & PNG_COLOR_MASK_COLOR) )
330 {
331 // grey image: GAGAGA... where G == grey component and A == alpha
332 for ( png_uint_32 y = 0; y < height; y++ )
333 {
334 const unsigned char *ptrSrc = lines[y];
335 for ( png_uint_32 x = 0; x < width; x++ )
336 {
337 unsigned char g = *ptrSrc++;
338 unsigned char a = *ptrSrc++;
339
340 // the first time we encounter a transparent pixel we must
341 // decide about what to do about them
342 if ( a != 0xff && transparency == Transparency_None )
343 {
344 // we'll need at least the mask for this image and
345 // maybe even full alpha channel info: the former is
346 // only enough if we have alpha values of 0 and 0xff
347 // only, otherwisewe need the latter
d26d9754
VZ
348 transparency = CheckTransparency
349 (
350 ptrSrc,
351 x, y,
352 width, height,
353 1
354 );
27bb2b7c
VZ
355
356 if ( transparency == Transparency_Mask )
357 {
358 // let's choose this colour for the mask: this is
359 // not a problem here as all the other pixels are
360 // grey, i.e. R == G == B which is not the case for
361 // this one so no confusion is possible
362 rMask = 0xff;
363 gMask = 0;
364 bMask = 0xff;
365 }
366 else // transparency == Transparency_Alpha
367 {
368 alpha = InitAlpha(image, x, y);
369 }
370 }
371
372 switch ( transparency )
373 {
374 case Transparency_Alpha:
375 *alpha++ = a;
376 // fall through
377
378 case Transparency_None:
379 *ptrDst++ = g;
380 *ptrDst++ = g;
381 *ptrDst++ = g;
382 break;
383
384 case Transparency_Mask:
385 *ptrDst++ = rMask;
386 *ptrDst++ = bMask;
387 *ptrDst++ = gMask;
388 }
389 }
390 }
391 }
392 else // colour image: RGBRGB...
393 {
394 for ( png_uint_32 y = 0; y < height; y++ )
395 {
396 const unsigned char *ptrSrc = lines[y];
397 for ( png_uint_32 x = 0; x < width; x++ )
398 {
399 unsigned char r = *ptrSrc++;
400 unsigned char g = *ptrSrc++;
401 unsigned char b = *ptrSrc++;
402 unsigned char a = *ptrSrc++;
403
404 // the logic here is the same as for the grey case except
405 // where noted
406 if ( a != 0xff && transparency == Transparency_None )
407 {
d26d9754
VZ
408 transparency = CheckTransparency
409 (
410 ptrSrc,
411 x, y,
412 width, height,
413 3
414 );
27bb2b7c
VZ
415
416 if ( transparency == Transparency_Mask )
417 {
418 FindMaskColour(lines, width, height,
419 rMask, gMask, bMask);
420 }
421 else // transparency == Transparency_Alpha
422 {
423 alpha = InitAlpha(image, x, y);
424 }
425
426 }
427
428 switch ( transparency )
429 {
430 case Transparency_Alpha:
431 *alpha++ = a;
432 // fall through
433
434 case Transparency_None:
435 *ptrDst++ = r;
436 *ptrDst++ = g;
437 *ptrDst++ = b;
438 break;
439
440 case Transparency_Mask:
441 // if we couldn't find a unique colour for the mask, we
442 // can have real pixels with the same value as the mask
443 // and it's better to slightly change their colour than
444 // to make them transparent
445 if ( r == rMask && g == gMask && b == bMask )
446 {
447 r++;
448 }
449
450 *ptrDst++ = rMask;
451 *ptrDst++ = bMask;
452 *ptrDst++ = gMask;
453 }
454 }
455 }
456 }
457
458 if ( transparency == Transparency_Mask )
459 {
460 image->SetMaskColour(rMask, gMask, bMask);
461 }
462}
463
3ca6a5f0
BP
464// temporarily disable the warning C4611 (interaction between '_setjmp' and
465// C++ object destruction is non-portable) - I don't see any dtors here
466#ifdef __VISUALC__
467 #pragma warning(disable:4611)
468#endif /* VC++ */
469
27bb2b7c
VZ
470bool
471wxPNGHandler::LoadFile(wxImage *image,
472 wxInputStream& stream,
473 bool verbose,
474 int WXUNUSED(index))
e9c4b1a2
JS
475{
476 // VZ: as this function uses setjmp() the only fool proof error handling
477 // method is to use goto (setjmp is not really C++ dtors friendly...)
717b9bf2 478
27bb2b7c
VZ
479 unsigned char **lines = NULL;
480 png_infop info_ptr = (png_infop) NULL;
bdffd806
VS
481 wxPNGInfoStruct wxinfo;
482
483 wxinfo.verbose = verbose;
484 wxinfo.stream.in = &stream;
717b9bf2 485
e9c4b1a2 486 image->Destroy();
717b9bf2 487
e9c4b1a2
JS
488 png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,
489 (voidp) NULL,
490 (png_error_ptr) NULL,
491 (png_error_ptr) NULL );
492 if (!png_ptr)
27bb2b7c 493 goto error;
717b9bf2 494
bdffd806
VS
495 png_set_error_fn(png_ptr, (png_voidp)NULL, wx_png_error, wx_png_warning);
496
497 // NB: please see the comment near wxPNGInfoStruct declaration for
498 // explanation why this line is mandatory
499 png_set_read_fn( png_ptr, &wxinfo, _PNG_stream_reader);
deb2fec0 500
e9c4b1a2
JS
501 info_ptr = png_create_info_struct( png_ptr );
502 if (!info_ptr)
27bb2b7c 503 goto error;
717b9bf2 504
bdffd806 505 if (setjmp(wxinfo.jmpbuf))
27bb2b7c 506 goto error;
717b9bf2 507
27bb2b7c
VZ
508 png_uint_32 i, width, height;
509 int bit_depth, color_type, interlace_type;
717b9bf2 510
e9c4b1a2
JS
511 png_read_info( png_ptr, info_ptr );
512 png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, (int*) NULL, (int*) NULL );
717b9bf2 513
e9c4b1a2
JS
514 if (color_type == PNG_COLOR_TYPE_PALETTE)
515 png_set_expand( png_ptr );
717b9bf2 516
2b5f62a0
VZ
517 // Fix for Bug [ 439207 ] Monochrome PNG images come up black
518 if (bit_depth < 8)
519 png_set_expand( png_ptr );
520
e9c4b1a2
JS
521 png_set_strip_16( png_ptr );
522 png_set_packing( png_ptr );
523 if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS))
524 png_set_expand( png_ptr );
525 png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER );
717b9bf2 526
479cd5de 527 image->Create( (int)width, (int)height );
717b9bf2 528
e9c4b1a2 529 if (!image->Ok())
27bb2b7c 530 goto error;
717b9bf2 531
479cd5de 532 lines = (unsigned char **)malloc( (size_t)(height * sizeof(unsigned char *)) );
27bb2b7c
VZ
533 if ( !lines )
534 goto error;
717b9bf2 535
e9c4b1a2
JS
536 for (i = 0; i < height; i++)
537 {
479cd5de 538 if ((lines[i] = (unsigned char *)malloc( (size_t)(width * (sizeof(unsigned char) * 4)))) == NULL)
e9c4b1a2
JS
539 {
540 for ( unsigned int n = 0; n < i; n++ )
541 free( lines[n] );
542 goto error;
543 }
544 }
717b9bf2 545
27bb2b7c
VZ
546 png_read_image( png_ptr, lines );
547 png_read_end( png_ptr, info_ptr );
548 png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
717b9bf2 549
27bb2b7c
VZ
550 // loaded successfully, now init wxImage with this data
551 CopyDataFromPNG(image, lines, width, height, color_type);
717b9bf2 552
27bb2b7c
VZ
553 for ( i = 0; i < height; i++ )
554 free( lines[i] );
555 free( lines );
717b9bf2 556
e9c4b1a2 557 return TRUE;
95ee0ac8 558
27bb2b7c 559error:
58c837a4
RR
560 if (verbose)
561 wxLogError(_("Couldn't load a PNG image - file is corrupted or not enough memory."));
717b9bf2 562
e9c4b1a2
JS
563 if ( image->Ok() )
564 {
565 image->Destroy();
566 }
717b9bf2 567
e9c4b1a2
JS
568 if ( lines )
569 {
570 free( lines );
571 }
717b9bf2 572
e9c4b1a2
JS
573 if ( png_ptr )
574 {
575 if ( info_ptr )
576 {
577 png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
578 free(info_ptr);
579 }
580 else
581 png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL );
582 }
583 return FALSE;
584}
585
27bb2b7c
VZ
586// ----------------------------------------------------------------------------
587// writing PNGs
588// ----------------------------------------------------------------------------
589
deb2fec0 590bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
e9c4b1a2 591{
bdffd806 592 wxPNGInfoStruct wxinfo;
717b9bf2 593
bdffd806
VS
594 wxinfo.verbose = verbose;
595 wxinfo.stream.out = &stream;
deb2fec0 596
bdffd806
VS
597 png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
598 if (!png_ptr)
599 {
600 if (verbose)
601 wxLogError(_("Couldn't save PNG image."));
602 return FALSE;
603 }
717b9bf2 604
bdffd806 605 png_set_error_fn(png_ptr, (png_voidp)NULL, wx_png_error, wx_png_warning);
717b9bf2 606
bdffd806
VS
607 png_infop info_ptr = png_create_info_struct(png_ptr);
608 if (info_ptr == NULL)
609 {
610 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
611 if (verbose)
612 wxLogError(_("Couldn't save PNG image."));
613 return FALSE;
614 }
717b9bf2 615
bdffd806
VS
616 if (setjmp(wxinfo.jmpbuf))
617 {
618 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
619 if (verbose)
620 wxLogError(_("Couldn't save PNG image."));
621 return FALSE;
622 }
717b9bf2 623
bdffd806
VS
624 // NB: please see the comment near wxPNGInfoStruct declaration for
625 // explanation why this line is mandatory
626 png_set_write_fn( png_ptr, &wxinfo, _PNG_stream_writer, NULL);
627
628 png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(), 8,
629 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
630 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
631
632 png_color_8 sig_bit;
633 sig_bit.red = 8;
634 sig_bit.green = 8;
635 sig_bit.blue = 8;
636 sig_bit.alpha = 8;
637 png_set_sBIT( png_ptr, info_ptr, &sig_bit );
638 png_write_info( png_ptr, info_ptr );
639 png_set_shift( png_ptr, &sig_bit );
640 png_set_packing( png_ptr );
717b9bf2 641
bdffd806
VS
642 unsigned char *data = (unsigned char *)malloc( image->GetWidth()*4 );
643 if (!data)
644 {
645 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
646 return FALSE;
647 }
717b9bf2 648
bdffd806
VS
649 for (int y = 0; y < image->GetHeight(); y++)
650 {
651 unsigned char *ptr = image->GetData() + (y * image->GetWidth() * 3);
652 for (int x = 0; x < image->GetWidth(); x++)
e9c4b1a2 653 {
bdffd806
VS
654 data[(x << 2) + 0] = *ptr++;
655 data[(x << 2) + 1] = *ptr++;
656 data[(x << 2) + 2] = *ptr++;
657 if (( !image->HasMask() ) || \
658 (data[(x << 2) + 0] != image->GetMaskRed()) || \
659 (data[(x << 2) + 1] != image->GetMaskGreen()) || \
660 (data[(x << 2) + 2] != image->GetMaskBlue()))
e9c4b1a2 661 {
bdffd806
VS
662 data[(x << 2) + 3] = 255;
663 }
664 else
665 {
666 data[(x << 2) + 3] = 0;
e9c4b1a2 667 }
e9c4b1a2 668 }
bdffd806
VS
669 png_bytep row_ptr = data;
670 png_write_rows( png_ptr, &row_ptr, 1 );
e9c4b1a2 671 }
bdffd806
VS
672
673 free(data);
674 png_write_end( png_ptr, info_ptr );
675 png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr );
676
e9c4b1a2
JS
677 return TRUE;
678}
e9c4b1a2 679
3ca6a5f0
BP
680#ifdef __VISUALC__
681 #pragma warning(default:4611)
682#endif /* VC++ */
683
9ab6ee85 684#endif // wxUSE_STREAMS
e9c4b1a2 685
9ab6ee85 686#endif // wxUSE_LIBPNG