JPEG and PNG code taken out of image.cpp
[wxWidgets.git] / src / common / imagpng.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: imagepng.cpp
3 // Purpose: wxImage PNG handler
4 // Author: Robert Roebling
5 // RCS-ID: $Id$
6 // Copyright: (c) Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "image.h"
12 #endif
13
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
16
17 #ifdef __BORLANDC__
18 #pragma hdrstop
19 #endif
20
21 #include "wx/image.h"
22 #include "wx/bitmap.h"
23 #include "wx/debug.h"
24 #include "wx/log.h"
25 #include "wx/app.h"
26 #if wxUSE_LIBPNG
27 #include "../png/png.h"
28 #endif
29 #include "wx/filefn.h"
30 #include "wx/wfstream.h"
31 #include "wx/intl.h"
32 #include "wx/module.h"
33
34 // For memcpy
35 #include <string.h>
36
37 #ifdef __SALFORDC__
38 #ifdef FAR
39 #undef FAR
40 #endif
41 #endif
42
43 #ifdef __WXMSW__
44 #include <windows.h>
45 #endif
46
47 //-----------------------------------------------------------------------------
48 // wxPNGHandler
49 //-----------------------------------------------------------------------------
50
51 #if wxUSE_LIBPNG
52
53 #if !USE_SHARED_LIBRARIES
54 IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler,wxImageHandler)
55 #endif
56
57
58 #if wxUSE_STREAMS
59 static void _PNG_stream_reader( png_structp png_ptr, png_bytep data, png_size_t length )
60 {
61 ((wxInputStream*) png_get_io_ptr( png_ptr )) -> Read(data, length);
62 }
63
64 static void _PNG_stream_writer( png_structp png_ptr, png_bytep data, png_size_t length )
65 {
66 ((wxOutputStream*) png_get_io_ptr( png_ptr )) -> Write(data, length);
67 }
68
69 bool wxPNGHandler::LoadFile( wxImage *image, wxInputStream& stream )
70 {
71 // VZ: as this function uses setjmp() the only fool proof error handling
72 // method is to use goto (setjmp is not really C++ dtors friendly...)
73
74 unsigned char **lines = (unsigned char **) NULL;
75 unsigned int i;
76 png_infop info_ptr = (png_infop) NULL;
77
78 image->Destroy();
79
80 png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,
81 (voidp) NULL,
82 (png_error_ptr) NULL,
83 (png_error_ptr) NULL );
84 if (!png_ptr)
85 goto error;
86
87 info_ptr = png_create_info_struct( png_ptr );
88 if (!info_ptr)
89 goto error;
90
91 if (setjmp(png_ptr->jmpbuf))
92 goto error;
93
94 if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
95 goto error;
96
97 png_set_read_fn( png_ptr, &stream, _PNG_stream_reader);
98
99 png_uint_32 width,height;
100 int bit_depth,color_type,interlace_type;
101
102 png_read_info( png_ptr, info_ptr );
103 png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, (int*) NULL, (int*) NULL );
104
105 if (color_type == PNG_COLOR_TYPE_PALETTE)
106 png_set_expand( png_ptr );
107
108 png_set_strip_16( png_ptr );
109 png_set_packing( png_ptr );
110 if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS))
111 png_set_expand( png_ptr );
112 png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER );
113
114 image->Create( width, height );
115
116 if (!image->Ok())
117 goto error;
118
119 lines = (unsigned char **)malloc( height * sizeof(unsigned char *) );
120 if (lines == NULL)
121 goto error;
122
123 for (i = 0; i < height; i++)
124 {
125 if ((lines[i] = (unsigned char *)malloc(width * (sizeof(unsigned char) * 4))) == NULL)
126 {
127 for ( unsigned int n = 0; n < i; n++ )
128 free( lines[n] );
129 goto error;
130 }
131 }
132
133 // loaded successfully!
134 {
135 int transp = 0;
136 png_read_image( png_ptr, lines );
137 png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
138 unsigned char *ptr = image->GetData();
139 if ((color_type == PNG_COLOR_TYPE_GRAY) ||
140 (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
141 {
142 for (unsigned int y = 0; y < height; y++)
143 {
144 unsigned char *ptr2 = lines[y];
145 for (unsigned int x = 0; x < width; x++)
146 {
147 unsigned char r = *ptr2++;
148 unsigned char a = *ptr2++;
149 if (a < 128)
150 {
151 *ptr++ = 255;
152 *ptr++ = 0;
153 *ptr++ = 255;
154 transp = 1;
155 }
156 else
157 {
158 *ptr++ = r;
159 *ptr++ = r;
160 *ptr++ = r;
161 }
162 }
163 }
164 }
165 else
166 {
167 for (unsigned int y = 0; y < height; y++)
168 {
169 unsigned char *ptr2 = lines[y];
170 for (unsigned int x = 0; x < width; x++)
171 {
172 unsigned char r = *ptr2++;
173 unsigned char g = *ptr2++;
174 unsigned char b = *ptr2++;
175 unsigned char a = *ptr2++;
176 if (a < 128)
177 {
178 *ptr++ = 255;
179 *ptr++ = 0;
180 *ptr++ = 255;
181 transp = 1;
182 }
183 else
184 {
185 if ((r == 255) && (g == 0) && (b == 255)) r = 254;
186 *ptr++ = r;
187 *ptr++ = g;
188 *ptr++ = b;
189 }
190 }
191 }
192 }
193
194 for ( unsigned int j = 0; j < height; j++ )
195 free( lines[j] );
196 free( lines );
197
198 if (transp)
199 {
200 image->SetMaskColour( 255, 0, 255 );
201 }
202 else
203 {
204 image->SetMask( FALSE );
205 }
206 }
207
208 return TRUE;
209
210 error:
211 wxLogError(_("Couldn't load a PNG image - probably file is corrupted."));
212
213 if ( image->Ok() )
214 {
215 image->Destroy();
216 }
217
218 if ( lines )
219 {
220 free( lines );
221 }
222
223 if ( png_ptr )
224 {
225 if ( info_ptr )
226 {
227 png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL );
228 free(info_ptr);
229 }
230 else
231 png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL );
232 }
233 return FALSE;
234 }
235
236
237 bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream )
238 {
239 {
240 png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
241 if (!png_ptr)
242 {
243 return FALSE;
244 }
245
246 png_infop info_ptr = png_create_info_struct(png_ptr);
247 if (info_ptr == NULL)
248 {
249 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
250 return FALSE;
251 }
252
253 if (setjmp(png_ptr->jmpbuf))
254 {
255 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
256 return FALSE;
257 }
258
259 png_set_write_fn( png_ptr, &stream, _PNG_stream_writer, NULL);
260
261 png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(), 8,
262 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
263 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
264
265 png_color_8 sig_bit;
266 sig_bit.red = 8;
267 sig_bit.green = 8;
268 sig_bit.blue = 8;
269 sig_bit.alpha = 8;
270 png_set_sBIT( png_ptr, info_ptr, &sig_bit );
271 png_write_info( png_ptr, info_ptr );
272 png_set_shift( png_ptr, &sig_bit );
273 png_set_packing( png_ptr );
274
275 unsigned char *data = (unsigned char *)malloc( image->GetWidth()*4 );
276 if (!data)
277 {
278 png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
279 return FALSE;
280 }
281
282 for (int y = 0; y < image->GetHeight(); y++)
283 {
284 unsigned char *ptr = image->GetData() + (y * image->GetWidth() * 3);
285 for (int x = 0; x < image->GetWidth(); x++)
286 {
287 data[(x << 2) + 0] = *ptr++;
288 data[(x << 2) + 1] = *ptr++;
289 data[(x << 2) + 2] = *ptr++;
290 if ((data[(x << 2) + 0] == image->GetMaskRed()) &&
291 (data[(x << 2) + 1] == image->GetMaskGreen()) &&
292 (data[(x << 2) + 2] == image->GetMaskBlue()))
293 {
294 data[(x << 2) + 3] = 0;
295 }
296 else
297 {
298 data[(x << 2) + 3] = 255;
299 }
300 }
301 png_bytep row_ptr = data;
302 png_write_rows( png_ptr, &row_ptr, 1 );
303 }
304
305 free(data);
306 png_write_end( png_ptr, info_ptr );
307 png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr );
308 }
309 return TRUE;
310 }
311 #endif // wxUSE_STREAMS
312
313 #endif
314
315 // wxUSE_LIBPNG
316