OSDN Git Service

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