1 | /* |
2 | * << Haru Free PDF Library >> -- hpdf_image.c |
3 | * |
4 | * URL: http://libharu.org |
5 | * |
6 | * Copyright (c) 1999-2006 Takeshi Kanno <takeshi_kanno@est.hi-ho.ne.jp> |
7 | * Copyright (c) 2007-2009 Antony Dovgal <tony@daylessday.org> |
8 | * |
9 | * Permission to use, copy, modify, distribute and sell this software |
10 | * and its documentation for any purpose is hereby granted without fee, |
11 | * provided that the above copyright notice appear in all copies and |
12 | * that both that copyright notice and this permission notice appear |
13 | * in supporting documentation. |
14 | * It is provided "as is" without express or implied warranty. |
15 | * |
16 | */ |
17 | |
18 | #include "hpdf_conf.h" |
19 | #include "hpdf_utils.h" |
20 | #include "hpdf_image.h" |
21 | |
22 | #ifndef LIBHPDF_HAVE_NOPNGLIB |
23 | #include <png.h> |
24 | #include <string.h> |
25 | |
26 | static void |
27 | PngErrorFunc (png_structp png_ptr, |
28 | const char *msg); |
29 | |
30 | |
31 | static void |
32 | PngReadFunc (png_structp png_ptr, |
33 | png_bytep data, |
34 | png_uint_32 length) |
35 | { |
36 | HPDF_UINT len = length; |
37 | HPDF_Stream stream = (HPDF_Stream)png_get_io_ptr (png_ptr); |
38 | |
39 | HPDF_Stream_Read (stream, data, &len); |
40 | } |
41 | |
42 | |
43 | static HPDF_STATUS |
44 | LoadPngData (HPDF_Dict image, |
45 | HPDF_Xref xref, |
46 | HPDF_Stream png_data, |
47 | HPDF_BOOL delayed_loading); |
48 | |
49 | |
50 | static void |
51 | PngErrorFunc (png_structp png_ptr, |
52 | const char *msg); |
53 | |
54 | |
55 | static HPDF_STATUS |
56 | ReadPngData_Interlaced (HPDF_Dict image, |
57 | png_structp png_ptr, |
58 | png_infop info_ptr); |
59 | |
60 | |
61 | static HPDF_STATUS |
62 | ReadPngData (HPDF_Dict image, |
63 | png_structp png_ptr, |
64 | png_infop info_ptr); |
65 | |
66 | |
67 | static HPDF_STATUS |
68 | CreatePallet (HPDF_Dict image, |
69 | png_structp png_ptr, |
70 | png_infop info_ptr); |
71 | |
72 | |
73 | static HPDF_STATUS |
74 | PngBeforeWrite (HPDF_Dict obj); |
75 | |
76 | |
77 | static HPDF_STATUS |
78 | PngAfterWrite (HPDF_Dict obj); |
79 | |
80 | |
81 | /*---------------------------------------------------------------------------*/ |
82 | |
83 | static void |
84 | PngErrorFunc (png_structp png_ptr, |
85 | const char *msg) |
86 | { |
87 | char error_number[16]; |
88 | HPDF_UINT i; |
89 | HPDF_STATUS detail_no; |
90 | HPDF_Error error; |
91 | |
92 | /* pick out error-number from error message */ |
93 | HPDF_MemSet (error_number, 0, 16); |
94 | |
95 | for (i = 0; i < 15; i++) { |
96 | error_number[i] = *(msg + i); |
97 | if (*(msg + i + 1) == ' ') |
98 | break; |
99 | } |
100 | |
101 | error = (HPDF_Error)png_get_error_ptr (png_ptr); |
102 | detail_no = (HPDF_STATUS)HPDF_AToI (error_number); |
103 | HPDF_SetError (error, HPDF_LIBPNG_ERROR, detail_no); |
104 | } |
105 | |
106 | |
107 | static HPDF_STATUS |
108 | ReadPngData_Interlaced (HPDF_Dict image, |
109 | png_structp png_ptr, |
110 | png_infop info_ptr) |
111 | { |
112 | png_uint_32 len = png_get_rowbytes(png_ptr, info_ptr); |
113 | png_uint_32 height = png_get_image_height(png_ptr, info_ptr); |
114 | png_bytep* row_pointers = HPDF_GetMem (image->mmgr, |
115 | height * sizeof (png_bytep)); |
116 | |
117 | if (row_pointers) { |
118 | HPDF_UINT i; |
119 | |
120 | HPDF_MemSet (row_pointers, 0, height * sizeof (png_bytep)); |
121 | for (i = 0; i < (HPDF_UINT)height; i++) { |
122 | row_pointers[i] = HPDF_GetMem (image->mmgr, len); |
123 | |
124 | if (image->error->error_no != HPDF_OK) |
125 | break; |
126 | } |
127 | |
128 | if (image->error->error_no == HPDF_OK) { |
129 | png_read_image(png_ptr, row_pointers); |
130 | if (image->error->error_no == HPDF_OK) { /* add this line */ |
131 | for (i = 0; i < (HPDF_UINT)height; i++) { |
132 | if (HPDF_Stream_Write (image->stream, row_pointers[i], len) != |
133 | HPDF_OK) |
134 | break; |
135 | } |
136 | } |
137 | } |
138 | |
139 | /* clean up */ |
140 | for (i = 0; i < (HPDF_UINT)height; i++) { |
141 | HPDF_FreeMem (image->mmgr, row_pointers[i]); |
142 | } |
143 | |
144 | HPDF_FreeMem (image->mmgr, row_pointers); |
145 | } |
146 | |
147 | return image->error->error_no; |
148 | } |
149 | |
150 | static HPDF_STATUS |
151 | ReadPngData (HPDF_Dict image, |
152 | png_structp png_ptr, |
153 | png_infop info_ptr) |
154 | { |
155 | png_uint_32 len = png_get_rowbytes(png_ptr, info_ptr); |
156 | png_uint_32 height = png_get_image_height(png_ptr, info_ptr); |
157 | png_bytep buf_ptr = HPDF_GetMem (image->mmgr, len); |
158 | |
159 | if (buf_ptr) { |
160 | HPDF_UINT i; |
161 | |
162 | for (i = 0; i < (HPDF_UINT)height; i++) { |
163 | png_read_rows(png_ptr, (png_byte**)&buf_ptr, NULL, 1); |
164 | if (image->error->error_no != HPDF_OK) |
165 | break; |
166 | |
167 | if (HPDF_Stream_Write (image->stream, buf_ptr, len) != HPDF_OK) |
168 | break; |
169 | } |
170 | |
171 | HPDF_FreeMem (image->mmgr, buf_ptr); |
172 | } |
173 | |
174 | return image->error->error_no; |
175 | } |
176 | |
177 | static HPDF_STATUS |
178 | ReadTransparentPaletteData (HPDF_Dict image, |
179 | png_structp png_ptr, |
180 | png_infop info_ptr, |
181 | png_bytep smask_data, |
182 | png_bytep trans, |
183 | int num_trans) |
184 | { |
185 | HPDF_STATUS ret = HPDF_OK; |
186 | HPDF_UINT i, j; |
187 | png_bytep *row_ptr; |
188 | png_uint_32 height = png_get_image_height(png_ptr, info_ptr); |
189 | png_uint_32 width = png_get_image_width(png_ptr, info_ptr); |
190 | |
191 | row_ptr = HPDF_GetMem (image->mmgr, height * sizeof(png_bytep)); |
192 | if (!row_ptr) { |
193 | return HPDF_FAILD_TO_ALLOC_MEM; |
194 | } else { |
195 | png_uint_32 len = png_get_rowbytes(png_ptr, info_ptr); |
196 | |
197 | for (i = 0; i < (HPDF_UINT)height; i++) { |
198 | row_ptr[i] = HPDF_GetMem(image->mmgr, len); |
199 | if (!row_ptr[i]) { |
200 | for (; i > 0; i--) { |
201 | HPDF_FreeMem (image->mmgr, row_ptr[i]); |
202 | } |
203 | HPDF_FreeMem (image->mmgr, row_ptr); |
204 | return HPDF_FAILD_TO_ALLOC_MEM; |
205 | } |
206 | } |
207 | } |
208 | |
209 | png_read_image(png_ptr, row_ptr); |
210 | if (image->error->error_no != HPDF_OK) { |
211 | ret = HPDF_INVALID_PNG_IMAGE; |
212 | goto Error; |
213 | } |
214 | |
215 | for (j = 0; j < height; j++) { |
216 | for (i = 0; i < width; i++) { |
217 | smask_data[width * j + i] = (row_ptr[j][i] < num_trans) ? trans[row_ptr[j][i]] : 0xFF; |
218 | } |
219 | |
220 | if (HPDF_Stream_Write (image->stream, row_ptr[j], width) != HPDF_OK) { |
221 | ret = HPDF_FILE_IO_ERROR; |
222 | goto Error; |
223 | } |
224 | } |
225 | |
226 | Error: |
227 | for (i = 0; i < (HPDF_UINT)height; i++) { |
228 | HPDF_FreeMem (image->mmgr, row_ptr[i]); |
229 | } |
230 | |
231 | HPDF_FreeMem (image->mmgr, row_ptr); |
232 | return ret; |
233 | } |
234 | |
235 | static HPDF_STATUS |
236 | ReadTransparentPngData (HPDF_Dict image, |
237 | png_structp png_ptr, |
238 | png_infop info_ptr, |
239 | png_bytep smask_data) |
240 | { |
241 | HPDF_STATUS ret = HPDF_OK; |
242 | HPDF_INT row_len; |
243 | HPDF_UINT i, j; |
244 | png_bytep *row_ptr, row; |
245 | png_byte color_type; |
246 | png_uint_32 height = png_get_image_height(png_ptr, info_ptr); |
247 | png_uint_32 width = png_get_image_width(png_ptr, info_ptr); |
248 | |
249 | color_type = png_get_color_type(png_ptr, info_ptr); |
250 | |
251 | if (!(color_type & PNG_COLOR_MASK_ALPHA)) { |
252 | return HPDF_INVALID_PNG_IMAGE; |
253 | } |
254 | |
255 | row_ptr = HPDF_GetMem (image->mmgr, height * sizeof(png_bytep)); |
256 | if (!row_ptr) { |
257 | return HPDF_FAILD_TO_ALLOC_MEM; |
258 | } else { |
259 | png_uint_32 len = png_get_rowbytes(png_ptr, info_ptr); |
260 | |
261 | for (i = 0; i < (HPDF_UINT)height; i++) { |
262 | row_ptr[i] = HPDF_GetMem(image->mmgr, len); |
263 | if (!row_ptr[i]) { |
264 | for (; i > 0; i--) { |
265 | HPDF_FreeMem (image->mmgr, row_ptr[i]); |
266 | } |
267 | HPDF_FreeMem (image->mmgr, row_ptr); |
268 | return HPDF_FAILD_TO_ALLOC_MEM; |
269 | } |
270 | } |
271 | } |
272 | |
273 | png_read_image(png_ptr, row_ptr); |
274 | if (image->error->error_no != HPDF_OK) { |
275 | ret = HPDF_INVALID_PNG_IMAGE; |
276 | goto Error; |
277 | } |
278 | |
279 | switch (color_type) { |
280 | case PNG_COLOR_TYPE_RGB_ALPHA: |
281 | row_len = 3 * width * sizeof(png_byte); |
282 | for (j = 0; j < height; j++) { |
283 | for (i = 0; i < width; i++) { |
284 | row = row_ptr[j]; |
285 | memmove(row + (3 * i), row + (4*i), 3); |
286 | smask_data[width * j + i] = row[4 * i + 3]; |
287 | } |
288 | |
289 | if (HPDF_Stream_Write (image->stream, row, row_len) != HPDF_OK) { |
290 | ret = HPDF_FILE_IO_ERROR; |
291 | goto Error; |
292 | } |
293 | } |
294 | break; |
295 | case PNG_COLOR_TYPE_GRAY_ALPHA: |
296 | row_len = width * sizeof(png_byte); |
297 | for (j = 0; j < height; j++) { |
298 | for (i = 0; i < width; i++) { |
299 | row = row_ptr[j]; |
300 | row[i] = row[2 * i]; |
301 | smask_data[width * j + i] = row[2 * i + 1]; |
302 | } |
303 | |
304 | if (HPDF_Stream_Write (image->stream, row, row_len) != HPDF_OK) { |
305 | ret = HPDF_FILE_IO_ERROR; |
306 | goto Error; |
307 | } |
308 | } |
309 | break; |
310 | default: |
311 | ret = HPDF_INVALID_PNG_IMAGE; |
312 | goto Error; |
313 | } |
314 | |
315 | Error: |
316 | for (i = 0; i < (HPDF_UINT)height; i++) { |
317 | HPDF_FreeMem (image->mmgr, row_ptr[i]); |
318 | } |
319 | |
320 | HPDF_FreeMem (image->mmgr, row_ptr); |
321 | return ret; |
322 | } |
323 | |
324 | static HPDF_STATUS |
325 | CreatePallet (HPDF_Dict image, |
326 | png_structp png_ptr, |
327 | png_infop info_ptr) |
328 | { |
329 | HPDF_INT num_pl = 0; |
330 | png_color *src_pl = NULL; |
331 | HPDF_BYTE *ppallet; |
332 | HPDF_BYTE *p; |
333 | HPDF_UINT i; |
334 | HPDF_Array array; |
335 | |
336 | /* png_get_PLTE does not call PngErrorFunc even if it failed. |
337 | * so we call HPDF_Set_Error to set error-code. |
338 | */ |
339 | if (png_get_PLTE(png_ptr, info_ptr, (png_color**)&src_pl, &num_pl) != |
340 | PNG_INFO_PLTE) |
341 | return HPDF_SetError (image->error, HPDF_LIBPNG_ERROR, |
342 | HPDF_CANNOT_GET_PALLET); |
343 | |
344 | |
345 | /* make a pallet array for indexed image. */ |
346 | ppallet = HPDF_GetMem (image->mmgr, num_pl * 3); |
347 | if (!ppallet) |
348 | return image->error->error_no; |
349 | |
350 | p = ppallet; |
351 | for (i = 0; i < num_pl; i++, src_pl++) { |
352 | *p++ = src_pl->red; |
353 | *p++ = src_pl->green; |
354 | *p++ = src_pl->blue; |
355 | } |
356 | |
357 | array = HPDF_Array_New (image->mmgr); |
358 | if (array) { |
359 | HPDF_Binary b; |
360 | |
361 | HPDF_Dict_Add (image, "ColorSpace" , array); |
362 | |
363 | HPDF_Array_AddName (array, "Indexed" ); |
364 | HPDF_Array_AddName (array, "DeviceRGB" ); |
365 | HPDF_Array_AddNumber (array, num_pl - 1); |
366 | |
367 | b = HPDF_Binary_New (image->mmgr, ppallet, num_pl * 3); |
368 | if (b) |
369 | HPDF_Array_Add (array, b); |
370 | } |
371 | |
372 | HPDF_FreeMem (image->mmgr, ppallet); |
373 | |
374 | return image->error->error_no; |
375 | } |
376 | |
377 | #define HPDF_PNG_BYTES_TO_CHECK 8 |
378 | |
379 | HPDF_Image |
380 | HPDF_Image_LoadPngImage (HPDF_MMgr mmgr, |
381 | HPDF_Stream png_data, |
382 | HPDF_Xref xref, |
383 | HPDF_BOOL delayed_loading) |
384 | { |
385 | HPDF_STATUS ret; |
386 | HPDF_Dict image; |
387 | png_byte [HPDF_PNG_BYTES_TO_CHECK]; |
388 | HPDF_UINT len = HPDF_PNG_BYTES_TO_CHECK; |
389 | |
390 | HPDF_PTRACE ((" HPDF_Image_LoadPngImage\n" )); |
391 | |
392 | HPDF_MemSet (header, 0x00, HPDF_PNG_BYTES_TO_CHECK); |
393 | ret = HPDF_Stream_Read (png_data, header, &len); |
394 | if (ret != HPDF_OK || |
395 | png_sig_cmp (header, (png_size_t)0, HPDF_PNG_BYTES_TO_CHECK)) { |
396 | HPDF_SetError (mmgr->error, HPDF_INVALID_PNG_IMAGE, 0); |
397 | return NULL; |
398 | } |
399 | |
400 | image = HPDF_DictStream_New (mmgr, xref); |
401 | if (!image) |
402 | return NULL; |
403 | |
404 | image->header.obj_class |= HPDF_OSUBCLASS_XOBJECT; |
405 | ret += HPDF_Dict_AddName (image, "Type" , "XObject" ); |
406 | ret += HPDF_Dict_AddName (image, "Subtype" , "Image" ); |
407 | if (ret != HPDF_OK) |
408 | return NULL; |
409 | |
410 | if (LoadPngData (image, xref, png_data, delayed_loading) != HPDF_OK) |
411 | return NULL; |
412 | |
413 | return image; |
414 | } |
415 | |
416 | |
417 | static HPDF_STATUS |
418 | LoadPngData (HPDF_Dict image, |
419 | HPDF_Xref xref, |
420 | HPDF_Stream png_data, |
421 | HPDF_BOOL delayed_loading) |
422 | |
423 | { |
424 | HPDF_STATUS ret = HPDF_OK; |
425 | png_uint_32 width, height; |
426 | int bit_depth, color_type; |
427 | png_structp png_ptr = NULL; |
428 | png_infop info_ptr = NULL; |
429 | |
430 | HPDF_PTRACE ((" HPDF_Image_LoadPngImage\n" )); |
431 | |
432 | /* create read_struct. */ |
433 | png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, |
434 | image->error, PngErrorFunc, PngErrorFunc); |
435 | |
436 | if (png_ptr == NULL) { |
437 | HPDF_SetError (image->error, HPDF_FAILD_TO_ALLOC_MEM, 0); |
438 | return HPDF_FAILD_TO_ALLOC_MEM; |
439 | } |
440 | |
441 | /* create info-struct */ |
442 | info_ptr = png_create_info_struct (png_ptr); |
443 | |
444 | if (info_ptr == NULL) { |
445 | HPDF_SetError (image->error, HPDF_FAILD_TO_ALLOC_MEM, 0); |
446 | goto Exit; |
447 | } |
448 | |
449 | png_set_sig_bytes (png_ptr, HPDF_PNG_BYTES_TO_CHECK); |
450 | png_set_read_fn (png_ptr, (void *)png_data, (png_rw_ptr)&PngReadFunc); |
451 | |
452 | /* reading info structure. */ |
453 | png_read_info(png_ptr, info_ptr); |
454 | if (image->error->error_no != HPDF_OK) { |
455 | goto Exit; |
456 | } |
457 | |
458 | png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); |
459 | |
460 | /* 16bit images are not supported. */ |
461 | if (bit_depth == 16) { |
462 | png_set_strip_16(png_ptr); |
463 | } |
464 | |
465 | png_read_update_info(png_ptr, info_ptr); |
466 | if (image->error->error_no != HPDF_OK) { |
467 | goto Exit; |
468 | } |
469 | |
470 | /* check palette-based images for transparent areas and load them immediately if found */ |
471 | if (xref && PNG_COLOR_TYPE_PALETTE & color_type) { |
472 | png_bytep trans; |
473 | int num_trans; |
474 | HPDF_Dict smask; |
475 | png_bytep smask_data; |
476 | |
477 | if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) || |
478 | !png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL)) { |
479 | goto no_transparent_color_in_palette; |
480 | } |
481 | |
482 | smask = HPDF_DictStream_New (image->mmgr, xref); |
483 | if (!smask) { |
484 | ret = HPDF_FAILD_TO_ALLOC_MEM; |
485 | goto Exit; |
486 | } |
487 | |
488 | smask->header.obj_class |= HPDF_OSUBCLASS_XOBJECT; |
489 | ret = HPDF_Dict_AddName (smask, "Type" , "XObject" ); |
490 | ret += HPDF_Dict_AddName (smask, "Subtype" , "Image" ); |
491 | ret += HPDF_Dict_AddNumber (smask, "Width" , (HPDF_UINT)width); |
492 | ret += HPDF_Dict_AddNumber (smask, "Height" , (HPDF_UINT)height); |
493 | ret += HPDF_Dict_AddName (smask, "ColorSpace" , "DeviceGray" ); |
494 | ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent" , (HPDF_UINT)bit_depth); |
495 | |
496 | if (ret != HPDF_OK) { |
497 | HPDF_Dict_Free(smask); |
498 | ret = HPDF_INVALID_PNG_IMAGE; |
499 | goto Exit; |
500 | } |
501 | |
502 | smask_data = HPDF_GetMem(image->mmgr, width * height); |
503 | if (!smask_data) { |
504 | HPDF_Dict_Free(smask); |
505 | ret = HPDF_FAILD_TO_ALLOC_MEM; |
506 | goto Exit; |
507 | } |
508 | |
509 | if (ReadTransparentPaletteData(image, png_ptr, info_ptr, smask_data, trans, num_trans) != HPDF_OK) { |
510 | HPDF_FreeMem(image->mmgr, smask_data); |
511 | HPDF_Dict_Free(smask); |
512 | ret = HPDF_INVALID_PNG_IMAGE; |
513 | goto Exit; |
514 | } |
515 | |
516 | if (HPDF_Stream_Write(smask->stream, smask_data, width * height) != HPDF_OK) { |
517 | HPDF_FreeMem(image->mmgr, smask_data); |
518 | HPDF_Dict_Free(smask); |
519 | ret = HPDF_FILE_IO_ERROR; |
520 | goto Exit; |
521 | } |
522 | HPDF_FreeMem(image->mmgr, smask_data); |
523 | |
524 | |
525 | ret += CreatePallet(image, png_ptr, info_ptr); |
526 | ret += HPDF_Dict_AddNumber (image, "Width" , (HPDF_UINT)width); |
527 | ret += HPDF_Dict_AddNumber (image, "Height" , (HPDF_UINT)height); |
528 | ret += HPDF_Dict_AddNumber (image, "BitsPerComponent" , (HPDF_UINT)bit_depth); |
529 | ret += HPDF_Dict_Add (image, "SMask" , smask); |
530 | |
531 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
532 | return HPDF_OK; |
533 | } |
534 | |
535 | no_transparent_color_in_palette: |
536 | |
537 | /* read images with alpha channel right away |
538 | we have to do this because image transparent mask must be added to the Xref */ |
539 | if (xref && PNG_COLOR_MASK_ALPHA & color_type) { |
540 | HPDF_Dict smask; |
541 | png_bytep smask_data; |
542 | |
543 | smask = HPDF_DictStream_New (image->mmgr, xref); |
544 | if (!smask) { |
545 | ret = HPDF_FAILD_TO_ALLOC_MEM; |
546 | goto Exit; |
547 | } |
548 | |
549 | smask->header.obj_class |= HPDF_OSUBCLASS_XOBJECT; |
550 | ret = HPDF_Dict_AddName (smask, "Type" , "XObject" ); |
551 | ret += HPDF_Dict_AddName (smask, "Subtype" , "Image" ); |
552 | ret += HPDF_Dict_AddNumber (smask, "Width" , (HPDF_UINT)width); |
553 | ret += HPDF_Dict_AddNumber (smask, "Height" , (HPDF_UINT)height); |
554 | ret += HPDF_Dict_AddName (smask, "ColorSpace" , "DeviceGray" ); |
555 | ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent" , (HPDF_UINT)bit_depth); |
556 | |
557 | if (ret != HPDF_OK) { |
558 | HPDF_Dict_Free(smask); |
559 | ret = HPDF_INVALID_PNG_IMAGE; |
560 | goto Exit; |
561 | } |
562 | |
563 | smask_data = HPDF_GetMem(image->mmgr, width * height); |
564 | if (!smask_data) { |
565 | HPDF_Dict_Free(smask); |
566 | ret = HPDF_FAILD_TO_ALLOC_MEM; |
567 | goto Exit; |
568 | } |
569 | |
570 | if (ReadTransparentPngData(image, png_ptr, info_ptr, smask_data) != HPDF_OK) { |
571 | HPDF_FreeMem(image->mmgr, smask_data); |
572 | HPDF_Dict_Free(smask); |
573 | ret = HPDF_INVALID_PNG_IMAGE; |
574 | goto Exit; |
575 | } |
576 | |
577 | if (HPDF_Stream_Write(smask->stream, smask_data, width * height) != HPDF_OK) { |
578 | HPDF_FreeMem(image->mmgr, smask_data); |
579 | HPDF_Dict_Free(smask); |
580 | ret = HPDF_FILE_IO_ERROR; |
581 | goto Exit; |
582 | } |
583 | HPDF_FreeMem(image->mmgr, smask_data); |
584 | |
585 | if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { |
586 | ret += HPDF_Dict_AddName (image, "ColorSpace" , "DeviceGray" ); |
587 | } else { |
588 | ret += HPDF_Dict_AddName (image, "ColorSpace" , "DeviceRGB" ); |
589 | } |
590 | ret += HPDF_Dict_AddNumber (image, "Width" , (HPDF_UINT)width); |
591 | ret += HPDF_Dict_AddNumber (image, "Height" , (HPDF_UINT)height); |
592 | ret += HPDF_Dict_AddNumber (image, "BitsPerComponent" , (HPDF_UINT)bit_depth); |
593 | ret += HPDF_Dict_Add (image, "SMask" , smask); |
594 | |
595 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
596 | return HPDF_OK; |
597 | } |
598 | |
599 | /* if the image has color palette, copy the pallet of the image to |
600 | * create color map. |
601 | */ |
602 | if (color_type == PNG_COLOR_TYPE_PALETTE) |
603 | ret = CreatePallet(image, png_ptr, info_ptr); |
604 | else if (color_type == PNG_COLOR_TYPE_GRAY) |
605 | ret = HPDF_Dict_AddName (image, "ColorSpace" , "DeviceGray" ); |
606 | else |
607 | ret = HPDF_Dict_AddName (image, "ColorSpace" , "DeviceRGB" ); |
608 | |
609 | if (ret != HPDF_OK) |
610 | goto Exit; |
611 | |
612 | /* read image-data |
613 | * if the image is interlaced, read whole image at once. |
614 | * if delayed_loading is HPDF_TRUE, the data does not load this phase. |
615 | */ |
616 | if (delayed_loading) { |
617 | image->before_write_fn = PngBeforeWrite; |
618 | image->after_write_fn = PngAfterWrite; |
619 | } else { |
620 | if (png_get_interlace_type(png_ptr, info_ptr) != PNG_INTERLACE_NONE) |
621 | ret = ReadPngData_Interlaced(image, png_ptr, info_ptr); |
622 | else |
623 | ret = ReadPngData(image, png_ptr, info_ptr); |
624 | |
625 | if (ret != HPDF_OK) |
626 | goto Exit; |
627 | } |
628 | |
629 | /* setting the info of the image. */ |
630 | if (HPDF_Dict_AddNumber (image, "Width" , (HPDF_UINT)width) |
631 | != HPDF_OK) |
632 | goto Exit; |
633 | |
634 | if (HPDF_Dict_AddNumber (image, "Height" , (HPDF_UINT)height) |
635 | != HPDF_OK) |
636 | goto Exit; |
637 | |
638 | if (HPDF_Dict_AddNumber (image, "BitsPerComponent" , |
639 | (HPDF_UINT)bit_depth) != HPDF_OK) |
640 | goto Exit; |
641 | |
642 | /* clean up */ |
643 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
644 | |
645 | return HPDF_OK; |
646 | |
647 | Exit: |
648 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
649 | |
650 | if (ret != HPDF_OK) { |
651 | return ret; |
652 | } |
653 | return image->error->error_no; |
654 | } |
655 | |
656 | |
657 | static HPDF_STATUS |
658 | PngBeforeWrite (HPDF_Dict obj) |
659 | { |
660 | HPDF_STATUS ret; |
661 | png_byte [HPDF_PNG_BYTES_TO_CHECK]; |
662 | HPDF_UINT len = HPDF_PNG_BYTES_TO_CHECK; |
663 | HPDF_Stream png_data; |
664 | HPDF_String s; |
665 | |
666 | HPDF_PTRACE ((" PngBeforeWrite\n" )); |
667 | |
668 | HPDF_MemStream_FreeData(obj->stream); |
669 | |
670 | s = HPDF_Dict_GetItem (obj, "_FILE_NAME" , HPDF_OCLASS_STRING); |
671 | if (!s) |
672 | return HPDF_SetError (obj->error, HPDF_MISSING_FILE_NAME_ENTRY, 0); |
673 | |
674 | png_data = HPDF_FileReader_New (obj->mmgr, (const char *)(s->value)); |
675 | if (!HPDF_Stream_Validate (png_data)) |
676 | return obj->error->error_no; |
677 | |
678 | HPDF_MemSet (header, 0x00, HPDF_PNG_BYTES_TO_CHECK); |
679 | ret = HPDF_Stream_Read (png_data, header, &len); |
680 | if (ret != HPDF_OK || |
681 | png_sig_cmp (header, (png_size_t)0, HPDF_PNG_BYTES_TO_CHECK)) { |
682 | HPDF_Stream_Free(png_data); |
683 | return HPDF_SetError (obj->error, HPDF_INVALID_PNG_IMAGE, 0); |
684 | } |
685 | |
686 | if ((ret = LoadPngData (obj, NULL, png_data, HPDF_FALSE)) != HPDF_OK) { |
687 | HPDF_Stream_Free(png_data); |
688 | return ret; |
689 | } |
690 | |
691 | HPDF_Stream_Free(png_data); |
692 | |
693 | return HPDF_OK; |
694 | } |
695 | |
696 | |
697 | static HPDF_STATUS |
698 | PngAfterWrite (HPDF_Dict obj) |
699 | { |
700 | HPDF_PTRACE ((" PngAfterWrite\n" )); |
701 | |
702 | HPDF_MemStream_FreeData(obj->stream); |
703 | |
704 | return HPDF_OK; |
705 | } |
706 | |
707 | |
708 | #endif /* LIBHPDF_HAVE_NOPNGLIB */ |
709 | |
710 | |