4 * Copyright 2018 Dmitry Timoshkov
5 * Copyright 2019 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
38 #define WIN32_NO_STATUS
45 #include "wine/exception.h"
46 #include "wine/server.h"
49 #include "user_private.h"
50 #include "wine/list.h"
51 #include "wine/unicode.h"
52 #include "wine/debug.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(cursor
);
58 static void *libpng_handle
;
59 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
60 MAKE_FUNCPTR(png_create_read_struct
);
61 MAKE_FUNCPTR(png_create_info_struct
);
62 MAKE_FUNCPTR(png_destroy_read_struct
);
63 MAKE_FUNCPTR(png_error
);
64 MAKE_FUNCPTR(png_get_bit_depth
);
65 MAKE_FUNCPTR(png_get_color_type
);
66 MAKE_FUNCPTR(png_get_error_ptr
);
67 MAKE_FUNCPTR(png_get_image_height
);
68 MAKE_FUNCPTR(png_get_image_width
);
69 MAKE_FUNCPTR(png_get_io_ptr
);
70 MAKE_FUNCPTR(png_read_image
);
71 MAKE_FUNCPTR(png_read_info
);
72 MAKE_FUNCPTR(png_read_update_info
);
73 MAKE_FUNCPTR(png_set_bgr
);
74 MAKE_FUNCPTR(png_set_crc_action
);
75 MAKE_FUNCPTR(png_set_error_fn
);
76 MAKE_FUNCPTR(png_set_expand
);
77 MAKE_FUNCPTR(png_set_gray_to_rgb
);
78 MAKE_FUNCPTR(png_set_read_fn
);
81 static void user_error_fn(png_structp png_ptr
, png_const_charp error_message
)
85 /* This uses setjmp/longjmp just like the default. We can't use the
86 * default because there's no way to access the jmp buffer in the png_struct
87 * that works in 1.2 and 1.4 and allows us to dynamically load libpng. */
88 WARN("PNG error: %s\n", debugstr_a(error_message
));
89 pjmpbuf
= ppng_get_error_ptr(png_ptr
);
93 static void user_warning_fn(png_structp png_ptr
, png_const_charp warning_message
)
95 WARN("PNG warning: %s\n", debugstr_a(warning_message
));
104 static void user_read_data(png_structp png_ptr
, png_bytep data
, png_size_t length
)
106 struct png_wrapper
*png
= ppng_get_io_ptr(png_ptr
);
108 if (png
->size
- png
->pos
>= length
)
110 memcpy(data
, png
->buffer
+ png
->pos
, length
);
115 ppng_error(png_ptr
, "failed to read PNG data");
119 static unsigned be_uint(unsigned val
)
128 return (u
.c
[0] << 24) | (u
.c
[1] << 16) | (u
.c
[2] << 8) | u
.c
[3];
131 static BOOL CDECL
get_png_info(const void *png_data
, DWORD size
, int *width
, int *height
, int *bpp
)
133 static const char png_sig
[8] = { 0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a };
134 static const char png_IHDR
[8] = { 0,0,0,0x0d,'I','H','D','R' };
139 unsigned width
, height
;
140 char bit_depth
, color_type
, compression
, filter
, interlace
;
143 if (size
< sizeof(*png
)) return FALSE
;
144 if (memcmp(png
->png_sig
, png_sig
, sizeof(png_sig
)) != 0) return FALSE
;
145 if (memcmp(png
->ihdr_sig
, png_IHDR
, sizeof(png_IHDR
)) != 0) return FALSE
;
147 *bpp
= (png
->color_type
== PNG_COLOR_TYPE_RGB_ALPHA
) ? 32 : 24;
148 *width
= be_uint(png
->width
);
149 *height
= be_uint(png
->height
);
154 static BITMAPINFO
* CDECL
load_png(const char *png_data
, DWORD
*size
)
156 struct png_wrapper png
;
159 png_bytep
*row_pointers
= NULL
;
161 int color_type
, bit_depth
, bpp
, width
, height
;
162 int rowbytes
, image_size
, mask_size
= 0, i
;
163 BITMAPINFO
*info
= NULL
;
164 unsigned char *image_data
;
166 if (!get_png_info(png_data
, *size
, &width
, &height
, &bpp
)) return NULL
;
168 png
.buffer
= png_data
;
172 /* initialize libpng */
173 png_ptr
= ppng_create_read_struct(PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
174 if (!png_ptr
) return NULL
;
176 info_ptr
= ppng_create_info_struct(png_ptr
);
179 ppng_destroy_read_struct(&png_ptr
, NULL
, NULL
);
183 /* set up setjmp/longjmp error handling */
187 RtlFreeHeap(GetProcessHeap(), 0, info
);
188 ppng_destroy_read_struct(&png_ptr
, &info_ptr
, NULL
);
192 ppng_set_error_fn(png_ptr
, jmpbuf
, user_error_fn
, user_warning_fn
);
193 ppng_set_crc_action(png_ptr
, PNG_CRC_QUIET_USE
, PNG_CRC_QUIET_USE
);
195 /* set up custom i/o handling */
196 ppng_set_read_fn(png_ptr
, &png
, user_read_data
);
198 /* read the header */
199 ppng_read_info(png_ptr
, info_ptr
);
201 color_type
= ppng_get_color_type(png_ptr
, info_ptr
);
202 bit_depth
= ppng_get_bit_depth(png_ptr
, info_ptr
);
204 /* expand grayscale image data to rgb */
205 if (color_type
== PNG_COLOR_TYPE_GRAY
|| color_type
== PNG_COLOR_TYPE_GRAY_ALPHA
)
206 ppng_set_gray_to_rgb(png_ptr
);
208 /* expand palette image data to rgb */
209 if (color_type
== PNG_COLOR_TYPE_PALETTE
|| bit_depth
< 8)
210 ppng_set_expand(png_ptr
);
212 /* update color type information */
213 ppng_read_update_info(png_ptr
, info_ptr
);
215 color_type
= ppng_get_color_type(png_ptr
, info_ptr
);
216 bit_depth
= ppng_get_bit_depth(png_ptr
, info_ptr
);
222 case PNG_COLOR_TYPE_RGB
:
227 case PNG_COLOR_TYPE_RGB_ALPHA
:
230 ppng_set_bgr(png_ptr
);
241 FIXME("unsupported PNG color format %d, %d bpp\n", color_type
, bit_depth
);
242 ppng_destroy_read_struct(&png_ptr
, &info_ptr
, NULL
);
246 width
= ppng_get_image_width(png_ptr
, info_ptr
);
247 height
= ppng_get_image_height(png_ptr
, info_ptr
);
249 rowbytes
= (width
* bpp
+ 7) / 8;
250 image_size
= height
* rowbytes
;
251 if (bpp
!= 32) /* add a mask if there is no alpha */
252 mask_size
= (width
+ 7) / 8 * height
;
254 info
= RtlAllocateHeap(GetProcessHeap(), 0, sizeof(BITMAPINFOHEADER
) + image_size
+ mask_size
);
257 ppng_destroy_read_struct(&png_ptr
, &info_ptr
, NULL
);
261 image_data
= (unsigned char *)info
+ sizeof(BITMAPINFOHEADER
);
262 memset(image_data
+ image_size
, 0, mask_size
);
264 row_pointers
= malloc(height
* sizeof(png_bytep
));
267 RtlFreeHeap(GetProcessHeap(), 0, info
);
268 ppng_destroy_read_struct(&png_ptr
, &info_ptr
, NULL
);
273 for (i
= 0; i
< height
; i
++)
274 row_pointers
[i
] = image_data
+ (height
- i
- 1) * rowbytes
;
276 ppng_read_image(png_ptr
, row_pointers
);
278 ppng_destroy_read_struct(&png_ptr
, &info_ptr
, NULL
);
280 info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
281 info
->bmiHeader
.biWidth
= width
;
282 info
->bmiHeader
.biHeight
= height
* 2;
283 info
->bmiHeader
.biPlanes
= 1;
284 info
->bmiHeader
.biBitCount
= bpp
;
285 info
->bmiHeader
.biCompression
= BI_RGB
;
286 info
->bmiHeader
.biSizeImage
= image_size
;
287 info
->bmiHeader
.biXPelsPerMeter
= 0;
288 info
->bmiHeader
.biYPelsPerMeter
= 0;
289 info
->bmiHeader
.biClrUsed
= 0;
290 info
->bmiHeader
.biClrImportant
= 0;
292 *size
= sizeof(BITMAPINFOHEADER
) + image_size
+ mask_size
;
296 static const struct png_funcs png_funcs
=
302 NTSTATUS CDECL
__wine_init_unix_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
304 if (reason
!= DLL_PROCESS_ATTACH
) return STATUS_SUCCESS
;
306 if (!(libpng_handle
= dlopen( SONAME_LIBPNG
, RTLD_NOW
)))
308 WARN( "failed to load %s\n", SONAME_LIBPNG
);
309 return STATUS_DLL_NOT_FOUND
;
311 #define LOAD_FUNCPTR(f) \
312 if (!(p##f = dlsym( libpng_handle, #f ))) \
314 WARN( "%s not found in %s\n", #f, SONAME_LIBPNG ); \
315 return STATUS_PROCEDURE_NOT_FOUND; \
317 LOAD_FUNCPTR(png_create_read_struct
);
318 LOAD_FUNCPTR(png_create_info_struct
);
319 LOAD_FUNCPTR(png_destroy_read_struct
);
320 LOAD_FUNCPTR(png_error
);
321 LOAD_FUNCPTR(png_get_bit_depth
);
322 LOAD_FUNCPTR(png_get_color_type
);
323 LOAD_FUNCPTR(png_get_error_ptr
);
324 LOAD_FUNCPTR(png_get_image_height
);
325 LOAD_FUNCPTR(png_get_image_width
);
326 LOAD_FUNCPTR(png_get_io_ptr
);
327 LOAD_FUNCPTR(png_read_image
);
328 LOAD_FUNCPTR(png_read_info
);
329 LOAD_FUNCPTR(png_read_update_info
);
330 LOAD_FUNCPTR(png_set_bgr
);
331 LOAD_FUNCPTR(png_set_crc_action
);
332 LOAD_FUNCPTR(png_set_error_fn
);
333 LOAD_FUNCPTR(png_set_expand
);
334 LOAD_FUNCPTR(png_set_gray_to_rgb
);
335 LOAD_FUNCPTR(png_set_read_fn
);
338 *(const struct png_funcs
**)ptr_out
= &png_funcs
;
339 return STATUS_SUCCESS
;
342 #endif /* SONAME_LIBPNG */