Leptonica  1.77.0
Image processing and image analysis suite
pngio.c
Go to the documentation of this file.
1 /*====================================================================*
2  - Copyright (C) 2001 Leptonica. All rights reserved.
3  - Copyright (C) 2017 Milner Technologies, Inc.
4  -
5  - Redistribution and use in source and binary forms, with or without
6  - modification, are permitted provided that the following conditions
7  - are met:
8  - 1. Redistributions of source code must retain the above copyright
9  - notice, this list of conditions and the following disclaimer.
10  - 2. Redistributions in binary form must reproduce the above
11  - copyright notice, this list of conditions and the following
12  - disclaimer in the documentation and/or other materials
13  - provided with the distribution.
14  -
15  - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18  - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
19  - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24  - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *====================================================================*/
27 
120 #ifdef HAVE_CONFIG_H
121 #include "config_auto.h"
122 #endif /* HAVE_CONFIG_H */
123 
124 #include <string.h>
125 #include "allheaders.h"
126 
127 /* --------------------------------------------*/
128 #if HAVE_LIBPNG /* defined in environ.h */
129 /* --------------------------------------------*/
130 
131 #include "png.h"
132 
133 #if HAVE_LIBZ
134 #include "zlib.h"
135 #else
136 #define Z_DEFAULT_COMPRESSION (-1)
137 #endif /* HAVE_LIBZ */
138 
139 /* ------------------ Set default for read option -------------------- */
140  /* Strip 16 bpp --> 8 bpp on reading png; default is for stripping.
141  * If you don't strip, you can't read the gray-alpha spp = 2 images. */
142 static l_int32 var_PNG_STRIP_16_TO_8 = 1;
143 
144 #ifndef NO_CONSOLE_IO
145 #define DEBUG_READ 0
146 #define DEBUG_WRITE 0
147 #endif /* ~NO_CONSOLE_IO */
148 
149 
150 /*---------------------------------------------------------------------*
151  * Reading png through stream *
152  *---------------------------------------------------------------------*/
184 PIX *
186 {
187 l_uint8 byte;
188 l_int32 rval, gval, bval;
189 l_int32 i, j, k, index, ncolors, bitval;
190 l_int32 wpl, d, spp, cindex, tRNS;
191 l_uint32 png_transforms;
192 l_uint32 *data, *line, *ppixel;
193 int num_palette, num_text, num_trans;
194 png_byte bit_depth, color_type, channels;
195 png_uint_32 w, h, rowbytes;
196 png_uint_32 xres, yres;
197 png_bytep rowptr, trans;
198 png_bytep *row_pointers;
199 png_structp png_ptr;
200 png_infop info_ptr, end_info;
201 png_colorp palette;
202 png_textp text_ptr; /* ptr to text_chunk */
203 PIX *pix, *pix1;
204 PIXCMAP *cmap;
205 
206  PROCNAME("pixReadStreamPng");
207 
208  if (!fp)
209  return (PIX *)ERROR_PTR("fp not defined", procName, NULL);
210  pix = NULL;
211 
212  /* Allocate the 3 data structures */
213  if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
214  (png_voidp)NULL, NULL, NULL)) == NULL)
215  return (PIX *)ERROR_PTR("png_ptr not made", procName, NULL);
216 
217  if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) {
218  png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
219  return (PIX *)ERROR_PTR("info_ptr not made", procName, NULL);
220  }
221 
222  if ((end_info = png_create_info_struct(png_ptr)) == NULL) {
223  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
224  return (PIX *)ERROR_PTR("end_info not made", procName, NULL);
225  }
226 
227  /* Set up png setjmp error handling */
228  if (setjmp(png_jmpbuf(png_ptr))) {
229  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
230  return (PIX *)ERROR_PTR("internal png error", procName, NULL);
231  }
232 
233  png_init_io(png_ptr, fp);
234 
235  /* ---------------------------------------------------------- *
236  * Set the transforms flags. Whatever happens here,
237  * NEVER invert 1 bpp using PNG_TRANSFORM_INVERT_MONO.
238  * Also, do not use PNG_TRANSFORM_EXPAND, which would
239  * expand all images with bpp < 8 to 8 bpp.
240  * ---------------------------------------------------------- */
241  /* To strip 16 --> 8 bit depth, use PNG_TRANSFORM_STRIP_16 */
242  if (var_PNG_STRIP_16_TO_8 == 1) { /* our default */
243  png_transforms = PNG_TRANSFORM_STRIP_16;
244  } else {
245  png_transforms = PNG_TRANSFORM_IDENTITY;
246  L_INFO("not stripping 16 --> 8 in png reading\n", procName);
247  }
248 
249  /* Read it */
250  png_read_png(png_ptr, info_ptr, png_transforms, NULL);
251 
252  row_pointers = png_get_rows(png_ptr, info_ptr);
253  w = png_get_image_width(png_ptr, info_ptr);
254  h = png_get_image_height(png_ptr, info_ptr);
255  bit_depth = png_get_bit_depth(png_ptr, info_ptr);
256  rowbytes = png_get_rowbytes(png_ptr, info_ptr);
257  color_type = png_get_color_type(png_ptr, info_ptr);
258  channels = png_get_channels(png_ptr, info_ptr);
259  spp = channels;
260  tRNS = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ? 1 : 0;
261 
262  if (spp == 1) {
263  d = bit_depth;
264  } else { /* spp == 2 (gray + alpha), spp == 3 (rgb), spp == 4 (rgba) */
265  d = 4 * bit_depth;
266  }
267 
268  /* Remove if/when this is implemented for all bit_depths */
269  if (spp == 3 && bit_depth != 8) {
270  fprintf(stderr, "Help: spp = 3 and depth = %d != 8\n!!", bit_depth);
271  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
272  return (PIX *)ERROR_PTR("not implemented for this depth",
273  procName, NULL);
274  }
275 
276  cmap = NULL;
277  if (color_type == PNG_COLOR_TYPE_PALETTE ||
278  color_type == PNG_COLOR_MASK_PALETTE) { /* generate a colormap */
279  png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
280  cmap = pixcmapCreate(d); /* spp == 1 */
281  for (cindex = 0; cindex < num_palette; cindex++) {
282  rval = palette[cindex].red;
283  gval = palette[cindex].green;
284  bval = palette[cindex].blue;
285  pixcmapAddColor(cmap, rval, gval, bval);
286  }
287  }
288 
289  if ((pix = pixCreate(w, h, d)) == NULL) {
290  pixcmapDestroy(&cmap);
291  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
292  return (PIX *)ERROR_PTR("pix not made", procName, NULL);
293  }
294  pixSetInputFormat(pix, IFF_PNG);
295  wpl = pixGetWpl(pix);
296  data = pixGetData(pix);
297  pixSetColormap(pix, cmap);
298  pixSetSpp(pix, spp);
299 
300  if (spp == 1 && !tRNS) { /* copy straight from buffer to pix */
301  for (i = 0; i < h; i++) {
302  line = data + i * wpl;
303  rowptr = row_pointers[i];
304  for (j = 0; j < rowbytes; j++) {
305  SET_DATA_BYTE(line, j, rowptr[j]);
306  }
307  }
308  } else if (spp == 2) { /* grayscale + alpha; convert to RGBA */
309  L_INFO("converting (gray + alpha) ==> RGBA\n", procName);
310  for (i = 0; i < h; i++) {
311  ppixel = data + i * wpl;
312  rowptr = row_pointers[i];
313  for (j = k = 0; j < w; j++) {
314  /* Copy gray value into r, g and b */
315  SET_DATA_BYTE(ppixel, COLOR_RED, rowptr[k]);
316  SET_DATA_BYTE(ppixel, COLOR_GREEN, rowptr[k]);
317  SET_DATA_BYTE(ppixel, COLOR_BLUE, rowptr[k++]);
318  SET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL, rowptr[k++]);
319  ppixel++;
320  }
321  }
322  pixSetSpp(pix, 4); /* we do not support 2 spp pix */
323  } else if (spp == 3 || spp == 4) {
324  for (i = 0; i < h; i++) {
325  ppixel = data + i * wpl;
326  rowptr = row_pointers[i];
327  for (j = k = 0; j < w; j++) {
328  SET_DATA_BYTE(ppixel, COLOR_RED, rowptr[k++]);
329  SET_DATA_BYTE(ppixel, COLOR_GREEN, rowptr[k++]);
330  SET_DATA_BYTE(ppixel, COLOR_BLUE, rowptr[k++]);
331  if (spp == 4)
332  SET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL, rowptr[k++]);
333  ppixel++;
334  }
335  }
336  }
337 
338  /* Special spp == 1 cases with transparency:
339  * (1) 8 bpp without colormap; assume full transparency
340  * (2) 1 bpp with colormap + trans array (for alpha)
341  * (3) 8 bpp with colormap + trans array (for alpha)
342  * These all require converting to RGBA */
343  if (spp == 1 && tRNS) {
344  if (!cmap) {
345  /* Case 1: make fully transparent RGBA image */
346  L_INFO("transparency, 1 spp, no colormap, no transparency array: "
347  "convention is fully transparent image\n", procName);
348  L_INFO("converting (fully transparent 1 spp) ==> RGBA\n", procName);
349  pixDestroy(&pix);
350  pix = pixCreate(w, h, 32); /* init to alpha = 0 (transparent) */
351  pixSetSpp(pix, 4);
352  } else {
353  L_INFO("converting (cmap + alpha) ==> RGBA\n", procName);
354 
355  /* Grab the transparency array */
356  png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
357  if (!trans) { /* invalid png file */
358  pixDestroy(&pix);
359  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
360  return (PIX *)ERROR_PTR("cmap, tRNS, but no transparency array",
361  procName, NULL);
362  }
363 
364  /* Save the cmap and destroy the pix */
365  cmap = pixcmapCopy(pixGetColormap(pix));
366  ncolors = pixcmapGetCount(cmap);
367  pixDestroy(&pix);
368 
369  /* Start over with 32 bit RGBA */
370  pix = pixCreate(w, h, 32);
371  wpl = pixGetWpl(pix);
372  data = pixGetData(pix);
373  pixSetSpp(pix, 4);
374 
375 #if DEBUG_READ
376  fprintf(stderr, "ncolors = %d, num_trans = %d\n",
377  ncolors, num_trans);
378  for (i = 0; i < ncolors; i++) {
379  pixcmapGetColor(cmap, i, &rval, &gval, &bval);
380  if (i < num_trans) {
381  fprintf(stderr, "(r,g,b,a) = (%d,%d,%d,%d)\n",
382  rval, gval, bval, trans[i]);
383  } else {
384  fprintf(stderr, "(r,g,b,a) = (%d,%d,%d,<<255>>)\n",
385  rval, gval, bval);
386  }
387  }
388 #endif /* DEBUG_READ */
389 
390  /* Extract the data and convert to RGBA */
391  if (d == 1) {
392  /* Case 2: 1 bpp with transparency (usually) behind white */
393  L_INFO("converting 1 bpp cmap with alpha ==> RGBA\n", procName);
394  if (num_trans == 1)
395  L_INFO("num_trans = 1; second color opaque by default\n",
396  procName);
397  for (i = 0; i < h; i++) {
398  ppixel = data + i * wpl;
399  rowptr = row_pointers[i];
400  for (j = 0, index = 0; j < rowbytes; j++) {
401  byte = rowptr[j];
402  for (k = 0; k < 8 && index < w; k++, index++) {
403  bitval = (byte >> (7 - k)) & 1;
404  pixcmapGetColor(cmap, bitval, &rval, &gval, &bval);
405  composeRGBPixel(rval, gval, bval, ppixel);
407  bitval < num_trans ? trans[bitval] : 255);
408  ppixel++;
409  }
410  }
411  }
412  } else if (d == 8) {
413  /* Case 3: 8 bpp with cmap and associated transparency */
414  L_INFO("converting 8 bpp cmap with alpha ==> RGBA\n", procName);
415  for (i = 0; i < h; i++) {
416  ppixel = data + i * wpl;
417  rowptr = row_pointers[i];
418  for (j = 0; j < w; j++) {
419  index = rowptr[j];
420  pixcmapGetColor(cmap, index, &rval, &gval, &bval);
421  composeRGBPixel(rval, gval, bval, ppixel);
422  /* Assume missing entries to be 255 (opaque)
423  * according to the spec:
424  * http://www.w3.org/TR/PNG/#11tRNS */
426  index < num_trans ? trans[index] : 255);
427  ppixel++;
428  }
429  }
430  } else {
431  L_ERROR("spp == 1, cmap, trans array, invalid depth: %d\n",
432  procName, d);
433  }
434  pixcmapDestroy(&cmap);
435  }
436  }
437 
438 #if DEBUG_READ
439  if (cmap) {
440  for (i = 0; i < 16; i++) {
441  fprintf(stderr, "[%d] = %d\n", i,
442  ((l_uint8 *)(cmap->array))[i]);
443  }
444  }
445 #endif /* DEBUG_READ */
446 
447  /* Final adjustments for bpp = 1.
448  * + If there is no colormap, the image must be inverted because
449  * png stores black pixels as 0.
450  * + We have already handled the case of cmapped, 1 bpp pix
451  * with transparency, where the output pix is 32 bpp RGBA.
452  * If there is no transparency but the pix has a colormap,
453  * we remove the colormap, because functions operating on
454  * 1 bpp images in leptonica assume no colormap.
455  * + The colormap must be removed in such a way that the pixel
456  * values are not changed. If the values are only black and
457  * white, we return a 1 bpp image; if gray, return an 8 bpp pix;
458  * otherwise, return a 32 bpp rgb pix.
459  *
460  * Note that we cannot use the PNG_TRANSFORM_INVERT_MONO flag
461  * to do the inversion, because that flag (since version 1.0.9)
462  * inverts 8 bpp grayscale as well, which we don't want to do.
463  * (It also doesn't work if there is a colormap.)
464  *
465  * Note that if the input png is a 1-bit with colormap and
466  * transparency, it has already been rendered as a 32 bpp,
467  * spp = 4 rgba pix.
468  */
469  if (pixGetDepth(pix) == 1) {
470  if (!cmap) {
471  pixInvert(pix, pix);
472  } else {
473  L_INFO("removing opaque cmap from 1 bpp\n", procName);
475  pixDestroy(&pix);
476  pix = pix1;
477  }
478  }
479 
480  xres = png_get_x_pixels_per_meter(png_ptr, info_ptr);
481  yres = png_get_y_pixels_per_meter(png_ptr, info_ptr);
482  pixSetXRes(pix, (l_int32)((l_float32)xres / 39.37 + 0.5)); /* to ppi */
483  pixSetYRes(pix, (l_int32)((l_float32)yres / 39.37 + 0.5)); /* to ppi */
484 
485  /* Get the text if there is any */
486  png_get_text(png_ptr, info_ptr, &text_ptr, &num_text);
487  if (num_text && text_ptr)
488  pixSetText(pix, text_ptr->text);
489 
490  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
491  return pix;
492 }
493 
494 
495 /*---------------------------------------------------------------------*
496  * Reading png header *
497  *---------------------------------------------------------------------*/
517 l_ok
518 readHeaderPng(const char *filename,
519  l_int32 *pw,
520  l_int32 *ph,
521  l_int32 *pbps,
522  l_int32 *pspp,
523  l_int32 *piscmap)
524 {
525 l_int32 ret;
526 FILE *fp;
527 
528  PROCNAME("readHeaderPng");
529 
530  if (pw) *pw = 0;
531  if (ph) *ph = 0;
532  if (pbps) *pbps = 0;
533  if (pspp) *pspp = 0;
534  if (piscmap) *piscmap = 0;
535  if (!filename)
536  return ERROR_INT("filename not defined", procName, 1);
537  if ((fp = fopenReadStream(filename)) == NULL)
538  return ERROR_INT("image file not found", procName, 1);
539  ret = freadHeaderPng(fp, pw, ph, pbps, pspp, piscmap);
540  fclose(fp);
541  return ret;
542 }
543 
544 
561 l_ok
562 freadHeaderPng(FILE *fp,
563  l_int32 *pw,
564  l_int32 *ph,
565  l_int32 *pbps,
566  l_int32 *pspp,
567  l_int32 *piscmap)
568 {
569 l_int32 nbytes, ret;
570 l_uint8 data[40];
571 
572  PROCNAME("freadHeaderPng");
573 
574  if (pw) *pw = 0;
575  if (ph) *ph = 0;
576  if (pbps) *pbps = 0;
577  if (pspp) *pspp = 0;
578  if (piscmap) *piscmap = 0;
579  if (!fp)
580  return ERROR_INT("stream not defined", procName, 1);
581 
582  nbytes = fnbytesInFile(fp);
583  if (nbytes < 40)
584  return ERROR_INT("file too small to be png", procName, 1);
585  if (fread(data, 1, 40, fp) != 40)
586  return ERROR_INT("error reading data", procName, 1);
587  ret = readHeaderMemPng(data, 40, pw, ph, pbps, pspp, piscmap);
588  return ret;
589 }
590 
591 
618 l_ok
619 readHeaderMemPng(const l_uint8 *data,
620  size_t size,
621  l_int32 *pw,
622  l_int32 *ph,
623  l_int32 *pbps,
624  l_int32 *pspp,
625  l_int32 *piscmap)
626 {
627 l_uint16 twobytes;
628 l_uint16 *pshort;
629 l_int32 colortype, bps, spp;
630 l_uint32 *pword;
631 
632  PROCNAME("readHeaderMemPng");
633 
634  if (pw) *pw = 0;
635  if (ph) *ph = 0;
636  if (pbps) *pbps = 0;
637  if (pspp) *pspp = 0;
638  if (piscmap) *piscmap = 0;
639  if (!data)
640  return ERROR_INT("data not defined", procName, 1);
641  if (size < 40)
642  return ERROR_INT("size < 40", procName, 1);
643 
644  /* Check password */
645  if (data[0] != 137 || data[1] != 80 || data[2] != 78 ||
646  data[3] != 71 || data[4] != 13 || data[5] != 10 ||
647  data[6] != 26 || data[7] != 10)
648  return ERROR_INT("not a valid png file", procName, 1);
649 
650  pword = (l_uint32 *)data;
651  pshort = (l_uint16 *)data;
652  if (pw) *pw = convertOnLittleEnd32(pword[4]);
653  if (ph) *ph = convertOnLittleEnd32(pword[5]);
654  twobytes = convertOnLittleEnd16(pshort[12]); /* contains depth/sample */
655  /* and the color type */
656  colortype = twobytes & 0xff; /* color type */
657  bps = twobytes >> 8; /* bits/sample */
658 
659  /* Special case with alpha that is extracted as RGBA.
660  * Note that the cmap+alpha is also extracted as RGBA,
661  * but only if the tRNS chunk exists, which we can't tell
662  * by this simple parser.*/
663  if (colortype == 4)
664  L_INFO("gray + alpha: will extract as RGBA (spp = 4)\n", procName);
665 
666  if (colortype == 2) { /* RGB */
667  spp = 3;
668  } else if (colortype == 6) { /* RGBA */
669  spp = 4;
670  } else if (colortype == 4) { /* gray + alpha */
671  spp = 2;
672  bps = 8; /* both the gray and alpha are 8-bit samples */
673  } else { /* gray (0) or cmap (3) or cmap+alpha (3) */
674  spp = 1;
675  }
676  if (pbps) *pbps = bps;
677  if (pspp) *pspp = spp;
678  if (piscmap) {
679  if (colortype & 1) /* palette */
680  *piscmap = 1;
681  else
682  *piscmap = 0;
683  }
684 
685  return 0;
686 }
687 
688 
689 /*---------------------------------------------------------------------*
690  * Reading png metadata *
691  *---------------------------------------------------------------------*/
692 /*
693  * fgetPngResolution()
694  *
695  * Input: fp (file stream opened for read)
696  * &xres, &yres (<return> resolution in ppi)
697  * Return: 0 if OK; 1 on error
698  *
699  * Notes:
700  * (1) If neither resolution field is set, this is not an error;
701  * the returned resolution values are 0 (designating 'unknown').
702  * (2) Side-effect: this rewinds the stream.
703  */
704 l_int32
705 fgetPngResolution(FILE *fp,
706  l_int32 *pxres,
707  l_int32 *pyres)
708 {
709 png_uint_32 xres, yres;
710 png_structp png_ptr;
711 png_infop info_ptr;
712 
713  PROCNAME("fgetPngResolution");
714 
715  if (pxres) *pxres = 0;
716  if (pyres) *pyres = 0;
717  if (!fp)
718  return ERROR_INT("stream not opened", procName, 1);
719  if (!pxres || !pyres)
720  return ERROR_INT("&xres and &yres not both defined", procName, 1);
721 
722  /* Make the two required structs */
723  if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
724  (png_voidp)NULL, NULL, NULL)) == NULL)
725  return ERROR_INT("png_ptr not made", procName, 1);
726  if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) {
727  png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
728  return ERROR_INT("info_ptr not made", procName, 1);
729  }
730 
731  /* Set up png setjmp error handling.
732  * Without this, an error calls exit. */
733  if (setjmp(png_jmpbuf(png_ptr))) {
734  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
735  return ERROR_INT("internal png error", procName, 1);
736  }
737 
738  /* Read the metadata */
739  rewind(fp);
740  png_init_io(png_ptr, fp);
741  png_read_info(png_ptr, info_ptr);
742 
743  xres = png_get_x_pixels_per_meter(png_ptr, info_ptr);
744  yres = png_get_y_pixels_per_meter(png_ptr, info_ptr);
745  *pxres = (l_int32)((l_float32)xres / 39.37 + 0.5); /* to ppi */
746  *pyres = (l_int32)((l_float32)yres / 39.37 + 0.5);
747 
748  png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
749  rewind(fp);
750  return 0;
751 }
752 
753 
761 l_ok
762 isPngInterlaced(const char *filename,
763  l_int32 *pinterlaced)
764 {
765 l_uint8 buf[32];
766 FILE *fp;
767 
768  PROCNAME("isPngInterlaced");
769 
770  if (!pinterlaced)
771  return ERROR_INT("&interlaced not defined", procName, 1);
772  *pinterlaced = 0;
773  if (!filename)
774  return ERROR_INT("filename not defined", procName, 1);
775 
776  if ((fp = fopenReadStream(filename)) == NULL)
777  return ERROR_INT("stream not opened", procName, 1);
778  if (fread(buf, 1, 32, fp) != 32) {
779  fclose(fp);
780  return ERROR_INT("data not read", procName, 1);
781  }
782  fclose(fp);
783 
784  *pinterlaced = (buf[28] == 0) ? 0 : 1;
785  return 0;
786 }
787 
788 
789 /*
790  * \brief fgetPngColormapInfo()
791  *
792  * \param[in] fp file stream opened for read
793  * \param[out] pcmap optional; use NULL to skip
794  * \param[out] ptransparency optional; 1 if colormapped with
795  * transparency, 0 otherwise; use NULL to skip
796  * \return 0 if OK, 1 on error
797  *
798  * Notes:
799  * (1) The transparency information in a png is in the tRNA array,
800  * which is separate from the colormap. If this array exists
801  * and if any element is less than 255, there exists some
802  * transparency.
803  * (2) Side-effect: this rewinds the stream.
804  */
805 l_ok
806 fgetPngColormapInfo(FILE *fp,
807  PIXCMAP **pcmap,
808  l_int32 *ptransparency)
809 {
810 l_int32 i, cindex, rval, gval, bval, num_palette, num_trans;
811 png_byte bit_depth, color_type;
812 png_bytep trans;
813 png_colorp palette;
814 png_structp png_ptr;
815 png_infop info_ptr;
816 
817  PROCNAME("fgetPngColormapInfo");
818 
819  if (pcmap) *pcmap = NULL;
820  if (ptransparency) *ptransparency = 0;
821  if (!pcmap && !ptransparency)
822  return ERROR_INT("no output defined", procName, 1);
823  if (!fp)
824  return ERROR_INT("stream not opened", procName, 1);
825 
826  /* Make the two required structs */
827  if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
828  (png_voidp)NULL, NULL, NULL)) == NULL)
829  return ERROR_INT("png_ptr not made", procName, 1);
830  if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) {
831  png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
832  return ERROR_INT("info_ptr not made", procName, 1);
833  }
834 
835  /* Set up png setjmp error handling.
836  * Without this, an error calls exit. */
837  if (setjmp(png_jmpbuf(png_ptr))) {
838  png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
839  if (pcmap && *pcmap) pixcmapDestroy(pcmap);
840  return ERROR_INT("internal png error", procName, 1);
841  }
842 
843  /* Read the metadata and check if there is a colormap */
844  rewind(fp);
845  png_init_io(png_ptr, fp);
846  png_read_info(png_ptr, info_ptr);
847  color_type = png_get_color_type(png_ptr, info_ptr);
848  if (color_type != PNG_COLOR_TYPE_PALETTE &&
849  color_type != PNG_COLOR_MASK_PALETTE) {
850  png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
851  return 0;
852  }
853 
854  /* Optionally, read the colormap */
855  if (pcmap) {
856  bit_depth = png_get_bit_depth(png_ptr, info_ptr);
857  png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
858  *pcmap = pixcmapCreate(bit_depth); /* spp == 1 */
859  for (cindex = 0; cindex < num_palette; cindex++) {
860  rval = palette[cindex].red;
861  gval = palette[cindex].green;
862  bval = palette[cindex].blue;
863  pixcmapAddColor(*pcmap, rval, gval, bval);
864  }
865  }
866 
867  /* Optionally, look for transparency. Note that the colormap
868  * has been initialized to fully opaque. */
869  if (ptransparency && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
870  png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
871  if (trans) {
872  for (i = 0; i < num_trans; i++) {
873  if (trans[i] < 255) { /* not fully opaque */
874  *ptransparency = 1;
875  if (pcmap) pixcmapSetAlpha(*pcmap, i, trans[i]);
876  }
877  }
878  } else {
879  L_ERROR("transparency array not returned\n", procName);
880  }
881  }
882 
883  png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
884  rewind(fp);
885  return 0;
886 }
887 
888 
889 /*---------------------------------------------------------------------*
890  * Writing png through stream *
891  *---------------------------------------------------------------------*/
906 l_ok
907 pixWritePng(const char *filename,
908  PIX *pix,
909  l_float32 gamma)
910 {
911 FILE *fp;
912 
913  PROCNAME("pixWritePng");
914 
915  if (!pix)
916  return ERROR_INT("pix not defined", procName, 1);
917  if (!filename)
918  return ERROR_INT("filename not defined", procName, 1);
919 
920  if ((fp = fopenWriteStream(filename, "wb+")) == NULL)
921  return ERROR_INT("stream not opened", procName, 1);
922 
923  if (pixWriteStreamPng(fp, pix, gamma)) {
924  fclose(fp);
925  return ERROR_INT("pix not written to stream", procName, 1);
926  }
927 
928  fclose(fp);
929  return 0;
930 }
931 
932 
1006 l_ok
1008  PIX *pix,
1009  l_float32 gamma)
1010 {
1011 char commentstring[] = "Comment";
1012 l_int32 i, j, k;
1013 l_int32 wpl, d, spp, cmflag, opaque;
1014 l_int32 ncolors, compval;
1015 l_int32 *rmap, *gmap, *bmap, *amap;
1016 l_uint32 *data, *ppixel;
1017 png_byte bit_depth, color_type;
1018 png_byte alpha[256];
1019 png_uint_32 w, h;
1020 png_uint_32 xres, yres;
1021 png_bytep *row_pointers;
1022 png_bytep rowbuffer;
1023 png_structp png_ptr;
1024 png_infop info_ptr;
1025 png_colorp palette;
1026 PIX *pix1;
1027 PIXCMAP *cmap;
1028 char *text;
1029 
1030  PROCNAME("pixWriteStreamPng");
1031 
1032  if (!fp)
1033  return ERROR_INT("stream not open", procName, 1);
1034  if (!pix)
1035  return ERROR_INT("pix not defined", procName, 1);
1036 
1037  /* Allocate the 2 data structures */
1038  if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
1039  (png_voidp)NULL, NULL, NULL)) == NULL)
1040  return ERROR_INT("png_ptr not made", procName, 1);
1041 
1042  if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) {
1043  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
1044  return ERROR_INT("info_ptr not made", procName, 1);
1045  }
1046 
1047  /* Set up png setjmp error handling */
1048  if (setjmp(png_jmpbuf(png_ptr))) {
1049  png_destroy_write_struct(&png_ptr, &info_ptr);
1050  return ERROR_INT("internal png error", procName, 1);
1051  }
1052 
1053  png_init_io(png_ptr, fp);
1054 
1055  /* With best zlib compression (9), get between 1 and 10% improvement
1056  * over default (6), but the compression is 3 to 10 times slower.
1057  * Use the zlib default (6) as our default compression unless
1058  * pix->special falls in the range [10 ... 19]; then subtract 10
1059  * to get the compression value. */
1060  compval = Z_DEFAULT_COMPRESSION;
1061  if (pix->special >= 10 && pix->special < 20)
1062  compval = pix->special - 10;
1063  png_set_compression_level(png_ptr, compval);
1064 
1065  w = pixGetWidth(pix);
1066  h = pixGetHeight(pix);
1067  d = pixGetDepth(pix);
1068  spp = pixGetSpp(pix);
1069  if ((cmap = pixGetColormap(pix)))
1070  cmflag = 1;
1071  else
1072  cmflag = 0;
1073  pixSetPadBits(pix, 0);
1074 
1075  /* Set the color type and bit depth. */
1076  if (d == 32 && spp == 4) {
1077  bit_depth = 8;
1078  color_type = PNG_COLOR_TYPE_RGBA; /* 6 */
1079  cmflag = 0; /* ignore if it exists */
1080  } else if (d == 24 || d == 32) {
1081  bit_depth = 8;
1082  color_type = PNG_COLOR_TYPE_RGB; /* 2 */
1083  cmflag = 0; /* ignore if it exists */
1084  } else {
1085  bit_depth = d;
1086  color_type = PNG_COLOR_TYPE_GRAY; /* 0 */
1087  }
1088  if (cmflag)
1089  color_type = PNG_COLOR_TYPE_PALETTE; /* 3 */
1090 
1091 #if DEBUG_WRITE
1092  fprintf(stderr, "cmflag = %d, bit_depth = %d, color_type = %d\n",
1093  cmflag, bit_depth, color_type);
1094 #endif /* DEBUG_WRITE */
1095 
1096  png_set_IHDR(png_ptr, info_ptr, w, h, bit_depth, color_type,
1097  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
1098  PNG_FILTER_TYPE_BASE);
1099 
1100  /* Store resolution in ppm, if known */
1101  xres = (png_uint_32)(39.37 * (l_float32)pixGetXRes(pix) + 0.5);
1102  yres = (png_uint_32)(39.37 * (l_float32)pixGetYRes(pix) + 0.5);
1103  if ((xres == 0) || (yres == 0))
1104  png_set_pHYs(png_ptr, info_ptr, 0, 0, PNG_RESOLUTION_UNKNOWN);
1105  else
1106  png_set_pHYs(png_ptr, info_ptr, xres, yres, PNG_RESOLUTION_METER);
1107 
1108  if (cmflag) {
1109  pixcmapToArrays(cmap, &rmap, &gmap, &bmap, &amap);
1110  ncolors = pixcmapGetCount(cmap);
1111  pixcmapIsOpaque(cmap, &opaque);
1112 
1113  /* Make and save the palette */
1114  palette = (png_colorp)LEPT_CALLOC(ncolors, sizeof(png_color));
1115  for (i = 0; i < ncolors; i++) {
1116  palette[i].red = (png_byte)rmap[i];
1117  palette[i].green = (png_byte)gmap[i];
1118  palette[i].blue = (png_byte)bmap[i];
1119  alpha[i] = (png_byte)amap[i];
1120  }
1121 
1122  png_set_PLTE(png_ptr, info_ptr, palette, (int)ncolors);
1123  if (!opaque) /* alpha channel has some transparency; assume valid */
1124  png_set_tRNS(png_ptr, info_ptr, (png_bytep)alpha,
1125  (int)ncolors, NULL);
1126  LEPT_FREE(rmap);
1127  LEPT_FREE(gmap);
1128  LEPT_FREE(bmap);
1129  LEPT_FREE(amap);
1130  }
1131 
1132  /* 0.4545 is treated as the default by some image
1133  * display programs (not gqview). A value > 0.4545 will
1134  * lighten an image as displayed by xv, display, etc. */
1135  if (gamma > 0.0)
1136  png_set_gAMA(png_ptr, info_ptr, (l_float64)gamma);
1137 
1138  if ((text = pixGetText(pix))) {
1139  png_text text_chunk;
1140  text_chunk.compression = PNG_TEXT_COMPRESSION_NONE;
1141  text_chunk.key = commentstring;
1142  text_chunk.text = text;
1143  text_chunk.text_length = strlen(text);
1144 #ifdef PNG_ITXT_SUPPORTED
1145  text_chunk.itxt_length = 0;
1146  text_chunk.lang = NULL;
1147  text_chunk.lang_key = NULL;
1148 #endif
1149  png_set_text(png_ptr, info_ptr, &text_chunk, 1);
1150  }
1151 
1152  /* Write header and palette info */
1153  png_write_info(png_ptr, info_ptr);
1154 
1155  if ((d != 32) && (d != 24)) { /* not rgb color */
1156  /* Generate a temporary pix with bytes swapped.
1157  * For writing a 1 bpp image as png:
1158  * ~ if no colormap, invert the data, because png writes
1159  * black as 0
1160  * ~ if colormapped, do not invert the data; the two RGBA
1161  * colors can have any value. */
1162  if (d == 1 && !cmap) {
1163  pix1 = pixInvert(NULL, pix);
1164  pixEndianByteSwap(pix1);
1165  } else {
1166  pix1 = pixEndianByteSwapNew(pix);
1167  }
1168  if (!pix1) {
1169  png_destroy_write_struct(&png_ptr, &info_ptr);
1170  if (cmflag) LEPT_FREE(palette);
1171  return ERROR_INT("pix1 not made", procName, 1);
1172  }
1173 
1174  /* Make and assign array of image row pointers */
1175  row_pointers = (png_bytep *)LEPT_CALLOC(h, sizeof(png_bytep));
1176  wpl = pixGetWpl(pix1);
1177  data = pixGetData(pix1);
1178  for (i = 0; i < h; i++)
1179  row_pointers[i] = (png_bytep)(data + i * wpl);
1180  png_set_rows(png_ptr, info_ptr, row_pointers);
1181 
1182  /* Transfer the data */
1183  png_write_image(png_ptr, row_pointers);
1184  png_write_end(png_ptr, info_ptr);
1185 
1186  if (cmflag) LEPT_FREE(palette);
1187  LEPT_FREE(row_pointers);
1188  pixDestroy(&pix1);
1189  png_destroy_write_struct(&png_ptr, &info_ptr);
1190  return 0;
1191  }
1192 
1193  /* For rgb, compose and write a row at a time */
1194  data = pixGetData(pix);
1195  wpl = pixGetWpl(pix);
1196  if (d == 24) { /* See note 7 above: special case of 24 bpp rgb */
1197  for (i = 0; i < h; i++) {
1198  ppixel = data + i * wpl;
1199  png_write_rows(png_ptr, (png_bytepp)&ppixel, 1);
1200  }
1201  } else { /* 32 bpp rgb and rgba. Write out the alpha channel if either
1202  * the pix has 4 spp or writing it is requested anyway */
1203  rowbuffer = (png_bytep)LEPT_CALLOC(w, 4);
1204  for (i = 0; i < h; i++) {
1205  ppixel = data + i * wpl;
1206  for (j = k = 0; j < w; j++) {
1207  rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
1208  rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
1209  rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
1210  if (spp == 4)
1211  rowbuffer[k++] = GET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL);
1212  ppixel++;
1213  }
1214 
1215  png_write_rows(png_ptr, &rowbuffer, 1);
1216  }
1217  LEPT_FREE(rowbuffer);
1218  }
1219 
1220  png_write_end(png_ptr, info_ptr);
1221 
1222  if (cmflag)
1223  LEPT_FREE(palette);
1224  png_destroy_write_struct(&png_ptr, &info_ptr);
1225  return 0;
1226 }
1227 
1228 
1250 l_ok
1252  l_int32 compval)
1253 {
1254  PROCNAME("pixSetZlibCompression");
1255 
1256  if (!pix)
1257  return ERROR_INT("pix not defined", procName, 1);
1258  if (compval < 0 || compval > 9) {
1259  L_ERROR("Invalid zlib comp val; using default\n", procName);
1260  compval = Z_DEFAULT_COMPRESSION;
1261  }
1262  pixSetSpecial(pix, 10 + compval); /* valid range [10 ... 19] */
1263  return 0;
1264 }
1265 
1266 
1267 /*---------------------------------------------------------------------*
1268  * Set flag for stripping 16 bits on reading *
1269  *---------------------------------------------------------------------*/
1277 void
1279 {
1280  var_PNG_STRIP_16_TO_8 = flag;
1281 }
1282 
1283 
1284 /*-------------------------------------------------------------------------*
1285  * Memio utility *
1286  * libpng read/write callback replacements for performing memory I/O *
1287  * *
1288  * Copyright (C) 2017 Milner Technologies, Inc. This content is a *
1289  * component of leptonica and is provided under the terms of the *
1290  * Leptonica license. *
1291  *-------------------------------------------------------------------------*/
1292 
1295 {
1296  char* m_Buffer;
1297  l_int32 m_Count;
1298  l_int32 m_Size;
1299  struct MemIOData *m_Next;
1301  struct MemIOData *m_Last;
1304 };
1305 typedef struct MemIOData MEMIODATA;
1306 
1307 static void memio_png_write_data(png_structp png_ptr, png_bytep data,
1308  png_size_t length);
1309 static void memio_png_flush(MEMIODATA* pthing);
1310 static void memio_png_read_data(png_structp png_ptr, png_bytep outBytes,
1311  png_size_t byteCountToRead);
1312 static void memio_free(MEMIODATA* pthing);
1313 
1314 static const l_int32 MEMIO_BUFFER_SIZE = 8192;
1316 /*
1317  * \brief memio_png_write_data()
1318  *
1319  * \param[in] png_ptr
1320  * \param[in] data
1321  * \param[in] len size of array data in bytes
1322  *
1323  * <pre>
1324  * Notes:
1325  * (1) This is a libpng callback for writing an image into a
1326  * linked list of memory buffers.
1327  * </pre>
1328  */
1329 static void
1330 memio_png_write_data(png_structp png_ptr,
1331  png_bytep data,
1332  png_size_t len)
1333 {
1334 MEMIODATA *thing, *last;
1335 l_int32 written = 0;
1336 l_int32 remainingSpace, remainingToWrite;
1337 
1338  thing = (struct MemIOData*)png_get_io_ptr(png_ptr);
1339  last = (struct MemIOData*)thing->m_Last;
1340  if (last->m_Buffer == NULL) {
1341  if (len > MEMIO_BUFFER_SIZE) {
1342  last->m_Buffer = (char *)LEPT_MALLOC(len);
1343  memcpy(last->m_Buffer, data, len);
1344  last->m_Size = last->m_Count = len;
1345  return;
1346  }
1347 
1348  last->m_Buffer = (char *)LEPT_MALLOC(MEMIO_BUFFER_SIZE);
1349  last->m_Size = MEMIO_BUFFER_SIZE;
1350  }
1351 
1352  while (written < len) {
1353  if (last->m_Count == last->m_Size) {
1354  MEMIODATA* next = (MEMIODATA *)LEPT_MALLOC(sizeof(MEMIODATA));
1355  next->m_Next = NULL;
1356  next->m_Count = 0;
1357  next->m_Last = next;
1358 
1359  last->m_Next = next;
1360  last = thing->m_Last = next;
1361 
1362  last->m_Buffer = (char *)LEPT_MALLOC(MEMIO_BUFFER_SIZE);
1363  last->m_Size = MEMIO_BUFFER_SIZE;
1364  }
1365 
1366  remainingSpace = last->m_Size - last->m_Count;
1367  remainingToWrite = len - written;
1368  if (remainingSpace < remainingToWrite) {
1369  memcpy(last->m_Buffer + last->m_Count, data + written,
1370  remainingSpace);
1371  written += remainingSpace;
1372  last->m_Count += remainingSpace;
1373  } else {
1374  memcpy(last->m_Buffer + last->m_Count, data + written,
1375  remainingToWrite);
1376  written += remainingToWrite;
1377  last->m_Count += remainingToWrite;
1378  }
1379  }
1380 }
1381 
1382 
1383 /*
1384  * \brief memio_png_flush()
1385  *
1386  * \param[in] pthing
1387  *
1388  * <pre>
1389  * Notes:
1390  * (1) This consolidates write buffers into a single buffer at the
1391  * haed of the link list of buffers.
1392  * </pre>
1393  */
1394 static void
1395 memio_png_flush(MEMIODATA *pthing)
1396 {
1397 l_int32 amount = 0;
1398 l_int32 copied = 0;
1399 MEMIODATA *buffer = 0;
1400 char *data = 0;
1401 
1402  /* If the data is in one buffer, give the buffer to the user. */
1403  if (pthing->m_Next == NULL) return;
1404 
1405  /* Consolidate multiple buffers into one new one; add the buffer
1406  * sizes together. */
1407  amount = pthing->m_Count;
1408  buffer = pthing->m_Next;
1409  while (buffer != NULL) {
1410  amount += buffer->m_Count;
1411  buffer = buffer->m_Next;
1412  }
1413 
1414  /* Copy data to a new buffer. */
1415  data = (char *)LEPT_MALLOC(amount);
1416  memcpy(data, pthing->m_Buffer, pthing->m_Count);
1417  copied = pthing->m_Count;
1418 
1419  LEPT_FREE(pthing->m_Buffer);
1420  pthing->m_Buffer = NULL;
1421 
1422  /* Don't delete original "thing" because we don't control it. */
1423  buffer = pthing->m_Next;
1424  pthing->m_Next = NULL;
1425  while (buffer != NULL && copied < amount) {
1426  MEMIODATA* old;
1427  memcpy(data + copied, buffer->m_Buffer, buffer->m_Count);
1428  copied += buffer->m_Count;
1429 
1430  old = buffer;
1431  buffer = buffer->m_Next;
1432 
1433  LEPT_FREE(old->m_Buffer);
1434  LEPT_FREE(old);
1435  }
1436 
1437  pthing->m_Buffer = data;
1438  pthing->m_Count = copied;
1439  pthing->m_Size = amount;
1440  return;
1441 }
1442 
1443 
1444 /*
1445  * \brief memio_png_read_data()
1446  *
1447  * \param[in] png_ptr
1448  * \param[in] outBytes
1449  * \param[in] byteCountToRead
1450  *
1451  * <pre>
1452  * Notes:
1453  * (1) This is a libpng callback that reads an image from a single
1454  * memory buffer.
1455  * </pre>
1456  */
1457 static void
1458 memio_png_read_data(png_structp png_ptr,
1459  png_bytep outBytes,
1460  png_size_t byteCountToRead)
1461 {
1462 MEMIODATA *thing;
1463 
1464  thing = (MEMIODATA *)png_get_io_ptr(png_ptr);
1465  if (byteCountToRead > (thing->m_Size - thing->m_Count)) {
1466  png_error(png_ptr, "read error in memio_png_read_data");
1467  }
1468  memcpy(outBytes, thing->m_Buffer + thing->m_Count, byteCountToRead);
1469  thing->m_Count += byteCountToRead;
1470 }
1471 
1472 
1473 /*
1474  * \brief memio_free()
1475  *
1476  * \param[in] pthing
1477  *
1478  * <pre>
1479  * Notes:
1480  * (1) This frees all the write buffers in the linked list. It must
1481  * be done before exiting the pixWriteMemPng().
1482  * </pre>
1483  */
1484 static void
1485 memio_free(MEMIODATA* pthing)
1486 {
1487 MEMIODATA *buffer, *old;
1488 
1489  if (pthing->m_Buffer != NULL)
1490  LEPT_FREE(pthing->m_Buffer);
1491 
1492  pthing->m_Buffer = NULL;
1493  buffer = pthing->m_Next;
1494  while (buffer != NULL) {
1495  old = buffer;
1496  buffer = buffer->m_Next;
1497 
1498  if (old->m_Buffer != NULL)
1499  LEPT_FREE(old->m_Buffer);
1500  LEPT_FREE(old);
1501  }
1502 }
1503 
1504 
1505 /*---------------------------------------------------------------------*
1506  * Reading png from memory *
1507  *---------------------------------------------------------------------*/
1520 PIX *
1521 pixReadMemPng(const l_uint8 *filedata,
1522  size_t filesize)
1523 {
1524 l_uint8 byte;
1525 l_int32 rval, gval, bval;
1526 l_int32 i, j, k, index, ncolors, bitval;
1527 l_int32 wpl, d, spp, cindex, tRNS;
1528 l_uint32 png_transforms;
1529 l_uint32 *data, *line, *ppixel;
1530 int num_palette, num_text, num_trans;
1531 png_byte bit_depth, color_type, channels;
1532 png_uint_32 w, h, rowbytes;
1533 png_uint_32 xres, yres;
1534 png_bytep rowptr, trans;
1535 png_bytep *row_pointers;
1536 png_structp png_ptr;
1537 png_infop info_ptr, end_info;
1538 png_colorp palette;
1539 png_textp text_ptr; /* ptr to text_chunk */
1540 PIX *pix, *pix1;
1541 PIXCMAP *cmap;
1542 MEMIODATA state;
1543 
1544  PROCNAME("pixReadMemPng");
1545 
1546  if (!filedata)
1547  return (PIX *)ERROR_PTR("filedata not defined", procName, NULL);
1548  if (filesize < 1)
1549  return (PIX *)ERROR_PTR("invalid filesize", procName, NULL);
1550 
1551  state.m_Next = 0;
1552  state.m_Count = 0;
1553  state.m_Last = &state;
1554  state.m_Buffer = (char*)filedata;
1555  state.m_Size = filesize;
1556  pix = NULL;
1557 
1558  /* Allocate the 3 data structures */
1559  if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
1560  (png_voidp)NULL, NULL, NULL)) == NULL)
1561  return (PIX *)ERROR_PTR("png_ptr not made", procName, NULL);
1562 
1563  if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) {
1564  png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
1565  return (PIX *)ERROR_PTR("info_ptr not made", procName, NULL);
1566  }
1567 
1568  if ((end_info = png_create_info_struct(png_ptr)) == NULL) {
1569  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
1570  return (PIX *)ERROR_PTR("end_info not made", procName, NULL);
1571  }
1572 
1573  /* Set up png setjmp error handling */
1574  if (setjmp(png_jmpbuf(png_ptr))) {
1575  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
1576  return (PIX *)ERROR_PTR("internal png error", procName, NULL);
1577  }
1578 
1579  png_set_read_fn(png_ptr, &state, memio_png_read_data);
1580 
1581  /* ---------------------------------------------------------- *
1582  * Set the transforms flags. Whatever happens here,
1583  * NEVER invert 1 bpp using PNG_TRANSFORM_INVERT_MONO.
1584  * Also, do not use PNG_TRANSFORM_EXPAND, which would
1585  * expand all images with bpp < 8 to 8 bpp.
1586  * ---------------------------------------------------------- */
1587  /* To strip 16 --> 8 bit depth, use PNG_TRANSFORM_STRIP_16 */
1588  if (var_PNG_STRIP_16_TO_8 == 1) { /* our default */
1589  png_transforms = PNG_TRANSFORM_STRIP_16;
1590  } else {
1591  png_transforms = PNG_TRANSFORM_IDENTITY;
1592  L_INFO("not stripping 16 --> 8 in png reading\n", procName);
1593  }
1594 
1595  /* Read it */
1596  png_read_png(png_ptr, info_ptr, png_transforms, NULL);
1597 
1598  row_pointers = png_get_rows(png_ptr, info_ptr);
1599  w = png_get_image_width(png_ptr, info_ptr);
1600  h = png_get_image_height(png_ptr, info_ptr);
1601  bit_depth = png_get_bit_depth(png_ptr, info_ptr);
1602  rowbytes = png_get_rowbytes(png_ptr, info_ptr);
1603  color_type = png_get_color_type(png_ptr, info_ptr);
1604  channels = png_get_channels(png_ptr, info_ptr);
1605  spp = channels;
1606  tRNS = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ? 1 : 0;
1607 
1608  if (spp == 1) {
1609  d = bit_depth;
1610  } else { /* spp == 2 (gray + alpha), spp == 3 (rgb), spp == 4 (rgba) */
1611  d = 4 * bit_depth;
1612  }
1613 
1614  /* Remove if/when this is implemented for all bit_depths */
1615  if (spp == 3 && bit_depth != 8) {
1616  fprintf(stderr, "Help: spp = 3 and depth = %d != 8\n!!", bit_depth);
1617  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
1618  return (PIX *)ERROR_PTR("not implemented for this depth",
1619  procName, NULL);
1620  }
1621 
1622  cmap = NULL;
1623  if (color_type == PNG_COLOR_TYPE_PALETTE ||
1624  color_type == PNG_COLOR_MASK_PALETTE) { /* generate a colormap */
1625  png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
1626  cmap = pixcmapCreate(d); /* spp == 1 */
1627  for (cindex = 0; cindex < num_palette; cindex++) {
1628  rval = palette[cindex].red;
1629  gval = palette[cindex].green;
1630  bval = palette[cindex].blue;
1631  pixcmapAddColor(cmap, rval, gval, bval);
1632  }
1633  }
1634 
1635  if ((pix = pixCreate(w, h, d)) == NULL) {
1636  pixcmapDestroy(&cmap);
1637  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
1638  pixcmapDestroy(&cmap);
1639  return (PIX *)ERROR_PTR("pix not made", procName, NULL);
1640  }
1641  pixSetInputFormat(pix, IFF_PNG);
1642  wpl = pixGetWpl(pix);
1643  data = pixGetData(pix);
1644  pixSetColormap(pix, cmap);
1645  pixSetSpp(pix, spp);
1646 
1647  if (spp == 1 && !tRNS) { /* copy straight from buffer to pix */
1648  for (i = 0; i < h; i++) {
1649  line = data + i * wpl;
1650  rowptr = row_pointers[i];
1651  for (j = 0; j < rowbytes; j++) {
1652  SET_DATA_BYTE(line, j, rowptr[j]);
1653  }
1654  }
1655  } else if (spp == 2) { /* grayscale + alpha; convert to RGBA */
1656  L_INFO("converting (gray + alpha) ==> RGBA\n", procName);
1657  for (i = 0; i < h; i++) {
1658  ppixel = data + i * wpl;
1659  rowptr = row_pointers[i];
1660  for (j = k = 0; j < w; j++) {
1661  /* Copy gray value into r, g and b */
1662  SET_DATA_BYTE(ppixel, COLOR_RED, rowptr[k]);
1663  SET_DATA_BYTE(ppixel, COLOR_GREEN, rowptr[k]);
1664  SET_DATA_BYTE(ppixel, COLOR_BLUE, rowptr[k++]);
1665  SET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL, rowptr[k++]);
1666  ppixel++;
1667  }
1668  }
1669  pixSetSpp(pix, 4); /* we do not support 2 spp pix */
1670  } else if (spp == 3 || spp == 4) {
1671  for (i = 0; i < h; i++) {
1672  ppixel = data + i * wpl;
1673  rowptr = row_pointers[i];
1674  for (j = k = 0; j < w; j++) {
1675  SET_DATA_BYTE(ppixel, COLOR_RED, rowptr[k++]);
1676  SET_DATA_BYTE(ppixel, COLOR_GREEN, rowptr[k++]);
1677  SET_DATA_BYTE(ppixel, COLOR_BLUE, rowptr[k++]);
1678  if (spp == 4)
1679  SET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL, rowptr[k++]);
1680  ppixel++;
1681  }
1682  }
1683  }
1684 
1685  /* Special spp == 1 cases with transparency:
1686  * (1) 8 bpp without colormap; assume full transparency
1687  * (2) 1 bpp with colormap + trans array (for alpha)
1688  * (3) 8 bpp with colormap + trans array (for alpha)
1689  * These all require converting to RGBA */
1690  if (spp == 1 && tRNS) {
1691  if (!cmap) {
1692  /* Case 1: make fully transparent RGBA image */
1693  L_INFO("transparency, 1 spp, no colormap, no transparency array: "
1694  "convention is fully transparent image\n", procName);
1695  L_INFO("converting (fully transparent 1 spp) ==> RGBA\n", procName);
1696  pixDestroy(&pix);
1697  pix = pixCreate(w, h, 32); /* init to alpha = 0 (transparent) */
1698  pixSetSpp(pix, 4);
1699  } else {
1700  L_INFO("converting (cmap + alpha) ==> RGBA\n", procName);
1701 
1702  /* Grab the transparency array */
1703  png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
1704  if (!trans) { /* invalid png file */
1705  pixDestroy(&pix);
1706  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
1707  return (PIX *)ERROR_PTR("cmap, tRNS, but no transparency array",
1708  procName, NULL);
1709  }
1710 
1711  /* Save the cmap and destroy the pix */
1712  cmap = pixcmapCopy(pixGetColormap(pix));
1713  ncolors = pixcmapGetCount(cmap);
1714  pixDestroy(&pix);
1715 
1716  /* Start over with 32 bit RGBA */
1717  pix = pixCreate(w, h, 32);
1718  wpl = pixGetWpl(pix);
1719  data = pixGetData(pix);
1720  pixSetSpp(pix, 4);
1721 
1722 #if DEBUG_READ
1723  fprintf(stderr, "ncolors = %d, num_trans = %d\n",
1724  ncolors, num_trans);
1725  for (i = 0; i < ncolors; i++) {
1726  pixcmapGetColor(cmap, i, &rval, &gval, &bval);
1727  if (i < num_trans) {
1728  fprintf(stderr, "(r,g,b,a) = (%d,%d,%d,%d)\n",
1729  rval, gval, bval, trans[i]);
1730  } else {
1731  fprintf(stderr, "(r,g,b,a) = (%d,%d,%d,<<255>>)\n",
1732  rval, gval, bval);
1733  }
1734  }
1735 #endif /* DEBUG_READ */
1736 
1737  /* Extract the data and convert to RGBA */
1738  if (d == 1) {
1739  /* Case 2: 1 bpp with transparency (usually) behind white */
1740  L_INFO("converting 1 bpp cmap with alpha ==> RGBA\n", procName);
1741  if (num_trans == 1)
1742  L_INFO("num_trans = 1; second color opaque by default\n",
1743  procName);
1744  for (i = 0; i < h; i++) {
1745  ppixel = data + i * wpl;
1746  rowptr = row_pointers[i];
1747  for (j = 0, index = 0; j < rowbytes; j++) {
1748  byte = rowptr[j];
1749  for (k = 0; k < 8 && index < w; k++, index++) {
1750  bitval = (byte >> (7 - k)) & 1;
1751  pixcmapGetColor(cmap, bitval, &rval, &gval, &bval);
1752  composeRGBPixel(rval, gval, bval, ppixel);
1754  bitval < num_trans ? trans[bitval] : 255);
1755  ppixel++;
1756  }
1757  }
1758  }
1759  } else if (d == 8) {
1760  /* Case 3: 8 bpp with cmap and associated transparency */
1761  L_INFO("converting 8 bpp cmap with alpha ==> RGBA\n", procName);
1762  for (i = 0; i < h; i++) {
1763  ppixel = data + i * wpl;
1764  rowptr = row_pointers[i];
1765  for (j = 0; j < w; j++) {
1766  index = rowptr[j];
1767  pixcmapGetColor(cmap, index, &rval, &gval, &bval);
1768  composeRGBPixel(rval, gval, bval, ppixel);
1769  /* Assume missing entries to be 255 (opaque)
1770  * according to the spec:
1771  * http://www.w3.org/TR/PNG/#11tRNS */
1773  index < num_trans ? trans[index] : 255);
1774  ppixel++;
1775  }
1776  }
1777  } else {
1778  L_ERROR("spp == 1, cmap, trans array, invalid depth: %d\n",
1779  procName, d);
1780  }
1781  pixcmapDestroy(&cmap);
1782  }
1783  }
1784 
1785 #if DEBUG_READ
1786  if (cmap) {
1787  for (i = 0; i < 16; i++) {
1788  fprintf(stderr, "[%d] = %d\n", i,
1789  ((l_uint8 *)(cmap->array))[i]);
1790  }
1791  }
1792 #endif /* DEBUG_READ */
1793 
1794  /* Final adjustments for bpp = 1.
1795  * + If there is no colormap, the image must be inverted because
1796  * png stores black pixels as 0.
1797  * + We have already handled the case of cmapped, 1 bpp pix
1798  * with transparency, where the output pix is 32 bpp RGBA.
1799  * If there is no transparency but the pix has a colormap,
1800  * we remove the colormap, because functions operating on
1801  * 1 bpp images in leptonica assume no colormap.
1802  * + The colormap must be removed in such a way that the pixel
1803  * values are not changed. If the values are only black and
1804  * white, we return a 1 bpp image; if gray, return an 8 bpp pix;
1805  * otherwise, return a 32 bpp rgb pix.
1806  *
1807  * Note that we cannot use the PNG_TRANSFORM_INVERT_MONO flag
1808  * to do the inversion, because that flag (since version 1.0.9)
1809  * inverts 8 bpp grayscale as well, which we don't want to do.
1810  * (It also doesn't work if there is a colormap.)
1811  *
1812  * Note that if the input png is a 1-bit with colormap and
1813  * transparency, it has already been rendered as a 32 bpp,
1814  * spp = 4 rgba pix.
1815  */
1816  if (pixGetDepth(pix) == 1) {
1817  if (!cmap) {
1818  pixInvert(pix, pix);
1819  } else {
1821  pixDestroy(&pix);
1822  pix = pix1;
1823  }
1824  }
1825 
1826  xres = png_get_x_pixels_per_meter(png_ptr, info_ptr);
1827  yres = png_get_y_pixels_per_meter(png_ptr, info_ptr);
1828  pixSetXRes(pix, (l_int32)((l_float32)xres / 39.37 + 0.5)); /* to ppi */
1829  pixSetYRes(pix, (l_int32)((l_float32)yres / 39.37 + 0.5)); /* to ppi */
1830 
1831  /* Get the text if there is any */
1832  png_get_text(png_ptr, info_ptr, &text_ptr, &num_text);
1833  if (num_text && text_ptr)
1834  pixSetText(pix, text_ptr->text);
1835 
1836  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
1837  return pix;
1838 }
1839 
1840 
1841 /*---------------------------------------------------------------------*
1842  * Writing png to memory *
1843  *---------------------------------------------------------------------*/
1858 l_ok
1859 pixWriteMemPng(l_uint8 **pfiledata,
1860  size_t *pfilesize,
1861  PIX *pix,
1862  l_float32 gamma)
1863 {
1864 char commentstring[] = "Comment";
1865 l_int32 i, j, k;
1866 l_int32 wpl, d, spp, cmflag, opaque;
1867 l_int32 ncolors, compval;
1868 l_int32 *rmap, *gmap, *bmap, *amap;
1869 l_uint32 *data, *ppixel;
1870 png_byte bit_depth, color_type;
1871 png_byte alpha[256];
1872 png_uint_32 w, h;
1873 png_uint_32 xres, yres;
1874 png_bytep *row_pointers;
1875 png_bytep rowbuffer;
1876 png_structp png_ptr;
1877 png_infop info_ptr;
1878 png_colorp palette;
1879 PIX *pix1;
1880 PIXCMAP *cmap;
1881 char *text;
1882 MEMIODATA state;
1883 
1884  PROCNAME("pixWriteMemPng");
1885 
1886  if (pfiledata) *pfiledata = NULL;
1887  if (pfilesize) *pfilesize = 0;
1888  if (!pfiledata)
1889  return ERROR_INT("&filedata not defined", procName, 1);
1890  if (!pfilesize)
1891  return ERROR_INT("&filesize not defined", procName, 1);
1892  if (!pix)
1893  return ERROR_INT("pix not defined", procName, 1);
1894 
1895  state.m_Buffer = 0;
1896  state.m_Size = 0;
1897  state.m_Next = 0;
1898  state.m_Count = 0;
1899  state.m_Last = &state;
1900 
1901  /* Allocate the 2 data structures */
1902  if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
1903  (png_voidp)NULL, NULL, NULL)) == NULL)
1904  return ERROR_INT("png_ptr not made", procName, 1);
1905 
1906  if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) {
1907  png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
1908  return ERROR_INT("info_ptr not made", procName, 1);
1909  }
1910 
1911  /* Set up png setjmp error handling */
1912  if (setjmp(png_jmpbuf(png_ptr))) {
1913  png_destroy_write_struct(&png_ptr, &info_ptr);
1914  return ERROR_INT("internal png error", procName, 1);
1915  }
1916 
1917  png_set_write_fn(png_ptr, &state, memio_png_write_data,
1918  (png_flush_ptr)NULL);
1919 
1920  /* With best zlib compression (9), get between 1 and 10% improvement
1921  * over default (6), but the compression is 3 to 10 times slower.
1922  * Use the zlib default (6) as our default compression unless
1923  * pix->special falls in the range [10 ... 19]; then subtract 10
1924  * to get the compression value. */
1925  compval = Z_DEFAULT_COMPRESSION;
1926  if (pix->special >= 10 && pix->special < 20)
1927  compval = pix->special - 10;
1928  png_set_compression_level(png_ptr, compval);
1929 
1930  w = pixGetWidth(pix);
1931  h = pixGetHeight(pix);
1932  d = pixGetDepth(pix);
1933  spp = pixGetSpp(pix);
1934  if ((cmap = pixGetColormap(pix)))
1935  cmflag = 1;
1936  else
1937  cmflag = 0;
1938 
1939  /* Set the color type and bit depth. */
1940  if (d == 32 && spp == 4) {
1941  bit_depth = 8;
1942  color_type = PNG_COLOR_TYPE_RGBA; /* 6 */
1943  cmflag = 0; /* ignore if it exists */
1944  } else if (d == 24 || d == 32) {
1945  bit_depth = 8;
1946  color_type = PNG_COLOR_TYPE_RGB; /* 2 */
1947  cmflag = 0; /* ignore if it exists */
1948  } else {
1949  bit_depth = d;
1950  color_type = PNG_COLOR_TYPE_GRAY; /* 0 */
1951  }
1952  if (cmflag)
1953  color_type = PNG_COLOR_TYPE_PALETTE; /* 3 */
1954 
1955 #if DEBUG_WRITE
1956  fprintf(stderr, "cmflag = %d, bit_depth = %d, color_type = %d\n",
1957  cmflag, bit_depth, color_type);
1958 #endif /* DEBUG_WRITE */
1959 
1960  png_set_IHDR(png_ptr, info_ptr, w, h, bit_depth, color_type,
1961  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
1962  PNG_FILTER_TYPE_BASE);
1963 
1964  /* Store resolution in ppm, if known */
1965  xres = (png_uint_32)(39.37 * (l_float32)pixGetXRes(pix) + 0.5);
1966  yres = (png_uint_32)(39.37 * (l_float32)pixGetYRes(pix) + 0.5);
1967  if ((xres == 0) || (yres == 0))
1968  png_set_pHYs(png_ptr, info_ptr, 0, 0, PNG_RESOLUTION_UNKNOWN);
1969  else
1970  png_set_pHYs(png_ptr, info_ptr, xres, yres, PNG_RESOLUTION_METER);
1971 
1972  if (cmflag) {
1973  pixcmapToArrays(cmap, &rmap, &gmap, &bmap, &amap);
1974  ncolors = pixcmapGetCount(cmap);
1975  pixcmapIsOpaque(cmap, &opaque);
1976 
1977  /* Make and save the palette */
1978  palette = (png_colorp)LEPT_CALLOC(ncolors, sizeof(png_color));
1979  for (i = 0; i < ncolors; i++) {
1980  palette[i].red = (png_byte)rmap[i];
1981  palette[i].green = (png_byte)gmap[i];
1982  palette[i].blue = (png_byte)bmap[i];
1983  alpha[i] = (png_byte)amap[i];
1984  }
1985 
1986  png_set_PLTE(png_ptr, info_ptr, palette, (int)ncolors);
1987  if (!opaque) /* alpha channel has some transparency; assume valid */
1988  png_set_tRNS(png_ptr, info_ptr, (png_bytep)alpha,
1989  (int)ncolors, NULL);
1990  LEPT_FREE(rmap);
1991  LEPT_FREE(gmap);
1992  LEPT_FREE(bmap);
1993  LEPT_FREE(amap);
1994  }
1995 
1996  /* 0.4545 is treated as the default by some image
1997  * display programs (not gqview). A value > 0.4545 will
1998  * lighten an image as displayed by xv, display, etc. */
1999  if (gamma > 0.0)
2000  png_set_gAMA(png_ptr, info_ptr, (l_float64)gamma);
2001 
2002  if ((text = pixGetText(pix))) {
2003  png_text text_chunk;
2004  text_chunk.compression = PNG_TEXT_COMPRESSION_NONE;
2005  text_chunk.key = commentstring;
2006  text_chunk.text = text;
2007  text_chunk.text_length = strlen(text);
2008 #ifdef PNG_ITXT_SUPPORTED
2009  text_chunk.itxt_length = 0;
2010  text_chunk.lang = NULL;
2011  text_chunk.lang_key = NULL;
2012 #endif
2013  png_set_text(png_ptr, info_ptr, &text_chunk, 1);
2014  }
2015 
2016  /* Write header and palette info */
2017  png_write_info(png_ptr, info_ptr);
2018 
2019  if ((d != 32) && (d != 24)) { /* not rgb color */
2020  /* Generate a temporary pix with bytes swapped.
2021  * For writing a 1 bpp image as png:
2022  * ~ if no colormap, invert the data, because png writes
2023  * black as 0
2024  * ~ if colormapped, do not invert the data; the two RGBA
2025  * colors can have any value. */
2026  if (d == 1 && !cmap) {
2027  pix1 = pixInvert(NULL, pix);
2028  pixEndianByteSwap(pix1);
2029  } else {
2030  pix1 = pixEndianByteSwapNew(pix);
2031  }
2032  if (!pix1) {
2033  png_destroy_write_struct(&png_ptr, &info_ptr);
2034  if (cmflag) LEPT_FREE(palette);
2035  memio_free(&state);
2036  return ERROR_INT("pix1 not made", procName, 1);
2037  }
2038 
2039  /* Make and assign array of image row pointers */
2040  row_pointers = (png_bytep *)LEPT_CALLOC(h, sizeof(png_bytep));
2041  wpl = pixGetWpl(pix1);
2042  data = pixGetData(pix1);
2043  for (i = 0; i < h; i++)
2044  row_pointers[i] = (png_bytep)(data + i * wpl);
2045  png_set_rows(png_ptr, info_ptr, row_pointers);
2046 
2047  /* Transfer the data */
2048  png_write_image(png_ptr, row_pointers);
2049  png_write_end(png_ptr, info_ptr);
2050 
2051  if (cmflag) LEPT_FREE(palette);
2052  LEPT_FREE(row_pointers);
2053  pixDestroy(&pix1);
2054  png_destroy_write_struct(&png_ptr, &info_ptr);
2055 
2056  memio_png_flush(&state);
2057  *pfiledata = (l_uint8 *)state.m_Buffer;
2058  state.m_Buffer = 0;
2059  *pfilesize = state.m_Count;
2060  memio_free(&state);
2061  return 0;
2062  }
2063 
2064  /* For rgb, compose and write a row at a time */
2065  data = pixGetData(pix);
2066  wpl = pixGetWpl(pix);
2067  if (d == 24) { /* See note 7 above: special case of 24 bpp rgb */
2068  for (i = 0; i < h; i++) {
2069  ppixel = data + i * wpl;
2070  png_write_rows(png_ptr, (png_bytepp)&ppixel, 1);
2071  }
2072  } else { /* 32 bpp rgb and rgba. Write out the alpha channel if either
2073  * the pix has 4 spp or writing it is requested anyway */
2074  rowbuffer = (png_bytep)LEPT_CALLOC(w, 4);
2075  for (i = 0; i < h; i++) {
2076  ppixel = data + i * wpl;
2077  for (j = k = 0; j < w; j++) {
2078  rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
2079  rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
2080  rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
2081  if (spp == 4)
2082  rowbuffer[k++] = GET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL);
2083  ppixel++;
2084  }
2085 
2086  png_write_rows(png_ptr, &rowbuffer, 1);
2087  }
2088  LEPT_FREE(rowbuffer);
2089  }
2090 
2091  png_write_end(png_ptr, info_ptr);
2092 
2093  if (cmflag)
2094  LEPT_FREE(palette);
2095  png_destroy_write_struct(&png_ptr, &info_ptr);
2096 
2097  memio_png_flush(&state);
2098  *pfiledata = (l_uint8 *)state.m_Buffer;
2099  state.m_Buffer = 0;
2100  *pfilesize = state.m_Count;
2101  memio_free(&state);
2102  return 0;
2103 }
2104 
2105 /* --------------------------------------------*/
2106 #endif /* HAVE_LIBPNG */
2107 /* --------------------------------------------*/
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:322
l_ok readHeaderMemPng(const l_uint8 *data, size_t size, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp, l_int32 *piscmap)
readHeaderMemPng()
Definition: pngio.c:619
PIX * pixReadStreamPng(FILE *fp)
pixReadStreamPng()
Definition: pngio.c:185
l_int32 special
Definition: pix.h:147
static void memio_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
Definition: pngio.c:1330
l_ok freadHeaderPng(FILE *fp, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp, l_int32 *piscmap)
freadHeaderPng()
Definition: pngio.c:562
size_t nbytes
Definition: pixalloc.c:120
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:302
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1395
void pixcmapDestroy(PIXCMAP **pcmap)
pixcmapDestroy()
Definition: colormap.c:265
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1624
void l_pngSetReadStrip16To8(l_int32 flag)
l_pngSetReadStrip16To8()
Definition: pngio.c:1278
l_ok pixWriteStreamPng(FILE *fp, PIX *pix, l_float32 gamma)
pixWriteStreamPng()
Definition: pngio.c:1007
struct MemIOData * m_Next
Definition: pngio.c:1299
l_ok pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1573
l_ok pixSetText(PIX *pix, const char *textstring)
pixSetText()
Definition: pix1.c:1483
l_ok pixWritePng(const char *filename, PIX *pix, l_float32 gamma)
pixWritePng()
Definition: pngio.c:907
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:111
l_int32 m_Count
Definition: pngio.c:1297
l_ok readHeaderPng(const char *filename, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp, l_int32 *piscmap)
readHeaderPng()
Definition: pngio.c:518
char * text
Definition: pix.h:148
l_ok pixcmapToArrays(PIXCMAP *cmap, l_int32 **prmap, l_int32 **pgmap, l_int32 **pbmap, l_int32 **pamap)
pixcmapToArrays()
Definition: colormap.c:1856
l_ok pixWriteMemPng(l_uint8 **pfiledata, size_t *pfilesize, PIX *pix, l_float32 gamma)
pixWriteMemPng()
Definition: pngio.c:1859
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition: colormap.c:751
l_ok pixSetZlibCompression(PIX *pix, l_int32 compval)
pixSetZlibCompression()
Definition: pngio.c:1251
l_ok pixEndianByteSwap(PIX *pixs)
pixEndianByteSwap()
Definition: pix2.c:2942
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
char * m_Buffer
Definition: pngio.c:1296
l_ok pixSetPadBits(PIX *pix, l_int32 val)
pixSetPadBits()
Definition: pix2.c:1307
size_t fnbytesInFile(FILE *fp)
fnbytesInFile()
Definition: utils2.c:1495
l_int32 m_Size
Definition: pngio.c:1298
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
l_ok pixcmapIsOpaque(PIXCMAP *cmap, l_int32 *popaque)
pixcmapIsOpaque()
Definition: colormap.c:1041
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:543
l_ok pixcmapSetAlpha(PIXCMAP *cmap, l_int32 index, l_int32 aval)
pixcmapSetAlpha()
Definition: colormap.c:934
PIX * pixEndianByteSwapNew(PIX *pixs)
pixEndianByteSwapNew()
Definition: pix2.c:2879
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1700
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1657
l_ok isPngInterlaced(const char *filename, l_int32 *pinterlaced)
isPngInterlaced()
Definition: pngio.c:762
char * pixGetText(PIX *pix)
pixGetText()
Definition: pix1.c:1459
void * array
Definition: pix.h:157
l_int32 pixcmapGetCount(PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:635
Definition: pix.h:134
Definition: pix.h:201
PIX * pixReadMemPng(const l_uint8 *filedata, size_t filesize)
pixReadMemPng()
Definition: pngio.c:1521
PIXCMAP * pixcmapCopy(PIXCMAP *cmaps)
pixcmapCopy()
Definition: colormap.c:234
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2671
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:341
struct MemIOData * m_Last
Definition: pngio.c:1301