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