Leptonica  1.83.1
Image processing and image analysis suite
gifio.c
Go to the documentation of this file.
1 /*====================================================================*
2  - Copyright (C) 2001 Leptonica. All rights reserved.
3  -
4  - Redistribution and use in source and binary forms, with or without
5  - modification, are permitted provided that the following conditions
6  - are met:
7  - 1. Redistributions of source code must retain the above copyright
8  - notice, this list of conditions and the following disclaimer.
9  - 2. Redistributions in binary form must reproduce the above
10  - copyright notice, this list of conditions and the following
11  - disclaimer in the documentation and/or other materials
12  - provided with the distribution.
13  -
14  - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18  - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
69 #ifdef HAVE_CONFIG_H
70 #include <config_auto.h>
71 #endif /* HAVE_CONFIG_H */
72 
73 #include <string.h>
74 #include "allheaders.h"
75 
76 /* --------------------------------------------------------------------*/
77 #if HAVE_LIBGIF || HAVE_LIBUNGIF /* defined in environ.h */
78 /* --------------------------------------------------------------------*/
79 
80 #include "gif_lib.h"
81 
82  /* Interface that enables low-level GIF support for reading from memory */
83 static PIX * gifToPix(GifFileType *gif);
84  /* Interface that enables low-level GIF support for writing to memory */
85 static l_int32 pixToGif(PIX *pix, GifFileType *gif);
86 
88 typedef struct GifReadBuffer
89 {
90  size_t size;
91  size_t pos;
92  const l_uint8 *cdata;
93 } GifReadBuffer;
94 
96 static l_int32 gifReadFunc(GifFileType *gif, GifByteType *dest,
97  l_int32 bytesToRead);
99 static l_int32 gifWriteFunc(GifFileType *gif, const GifByteType *src,
100  l_int32 bytesToWrite);
101 
102 
103 /*---------------------------------------------------------------------*
104  * Reading gif *
105  *---------------------------------------------------------------------*/
112 PIX *
113 pixReadStreamGif(FILE *fp)
114 {
115 l_uint8 *filedata;
116 size_t filesize;
117 PIX *pix;
118 
119  if (!fp)
120  return (PIX *)ERROR_PTR("fp not defined", __func__, NULL);
121 
122  /* Read data into memory from file */
123  rewind(fp);
124  if ((filedata = l_binaryReadStream(fp, &filesize)) == NULL)
125  return (PIX *)ERROR_PTR("filedata not read", __func__, NULL);
126 
127  /* Uncompress from memory */
128  pix = pixReadMemGif(filedata, filesize);
129  LEPT_FREE(filedata);
130  if (!pix)
131  L_ERROR("failed to read gif from file data\n", __func__);
132  return pix;
133 }
134 
135 
153 PIX *
154 pixReadMemGif(const l_uint8 *cdata,
155  size_t size)
156 {
157 GifFileType *gif;
158 GifReadBuffer buffer;
159 
160  /* 5.1+ and not 5.1.2 */
161 #if (GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0))
162  L_ERROR("Require giflib-5.1 or later\n", __func__);
163  return NULL;
164 #endif /* < 5.1 */
165 #if GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 1 && GIFLIB_RELEASE == 2 /* 5.1.2 */
166  L_ERROR("Can't use giflib-5.1.2; suggest 5.1.3 or later\n", __func__);
167  return NULL;
168 #endif /* 5.1.2 */
169 
170  if (!cdata)
171  return (PIX *)ERROR_PTR("cdata not defined", __func__, NULL);
172 
173  buffer.cdata = cdata;
174  buffer.size = size;
175  buffer.pos = 0;
176  if ((gif = DGifOpen((void*)&buffer, gifReadFunc, NULL)) == NULL)
177  return (PIX *)ERROR_PTR("could not open gif stream from memory",
178  __func__, NULL);
179 
180  return gifToPix(gif);
181 }
182 
183 
184 static l_int32
185 gifReadFunc(GifFileType *gif,
186  GifByteType *dest,
187  l_int32 bytesToRead)
188 {
189 GifReadBuffer *buffer;
190 l_int32 bytesRead;
191 
192  if ((buffer = (GifReadBuffer*)gif->UserData) == NULL)
193  return ERROR_INT("UserData not set", __func__, -1);
194 
195  if(buffer->pos >= buffer->size || bytesToRead > buffer->size)
196  return -1;
197 
198  bytesRead = (buffer->pos < buffer->size - bytesToRead)
199  ? bytesToRead : buffer->size - buffer->pos;
200  memcpy(dest, buffer->cdata + buffer->pos, bytesRead);
201  buffer->pos += bytesRead;
202  return bytesRead;
203 }
204 
205 
219 static PIX *
220 gifToPix(GifFileType *gif)
221 {
222 l_int32 wpl, i, j, w, h, d, cindex, ncolors, valid, nimages;
223 l_int32 rval, gval, bval;
224 l_uint32 *data, *line;
225 PIX *pixd;
226 PIXCMAP *cmap;
227 ColorMapObject *gif_cmap;
228 SavedImage si;
229 int giferr;
230 
231  /* Read all the data, but use only the first image found */
232  if (DGifSlurp(gif) != GIF_OK) {
233  DGifCloseFile(gif, &giferr);
234  return (PIX *)ERROR_PTR("failed to read GIF data", __func__, NULL);
235  }
236 
237  if (gif->SavedImages == NULL) {
238  DGifCloseFile(gif, &giferr);
239  return (PIX *)ERROR_PTR("no images found in GIF", __func__, NULL);
240  }
241 
242  nimages = gif->ImageCount;
243  if (nimages > 1)
244  L_WARNING("There are %d images in the file; we only read the first\n",
245  __func__, nimages);
246 
247  si = gif->SavedImages[0];
248  w = si.ImageDesc.Width;
249  h = si.ImageDesc.Height;
250  if (w <= 0 || h <= 0) {
251  DGifCloseFile(gif, &giferr);
252  return (PIX *)ERROR_PTR("invalid image dimensions", __func__, NULL);
253  }
254 
255  if (si.RasterBits == NULL) {
256  DGifCloseFile(gif, &giferr);
257  return (PIX *)ERROR_PTR("no raster data in GIF", __func__, NULL);
258  }
259 
260  if (si.ImageDesc.ColorMap) {
261  /* private cmap for this image */
262  gif_cmap = si.ImageDesc.ColorMap;
263  } else if (gif->SColorMap) {
264  /* global cmap for whole picture */
265  gif_cmap = gif->SColorMap;
266  } else {
267  /* don't know where to take cmap from */
268  DGifCloseFile(gif, &giferr);
269  return (PIX *)ERROR_PTR("color map is missing", __func__, NULL);
270  }
271 
272  ncolors = gif_cmap->ColorCount;
273  if (ncolors <= 0 || ncolors > 256) {
274  DGifCloseFile(gif, &giferr);
275  return (PIX *)ERROR_PTR("ncolors is invalid", __func__, NULL);
276  }
277  if (ncolors <= 2)
278  d = 1;
279  else if (ncolors <= 4)
280  d = 2;
281  else if (ncolors <= 16)
282  d = 4;
283  else /* [17 ... 256] */
284  d = 8;
285  cmap = pixcmapCreate(d);
286  for (cindex = 0; cindex < ncolors; cindex++) {
287  rval = gif_cmap->Colors[cindex].Red;
288  gval = gif_cmap->Colors[cindex].Green;
289  bval = gif_cmap->Colors[cindex].Blue;
290  pixcmapAddColor(cmap, rval, gval, bval);
291  }
292 
293  if ((pixd = pixCreate(w, h, d)) == NULL) {
294  DGifCloseFile(gif, &giferr);
295  pixcmapDestroy(&cmap);
296  return (PIX *)ERROR_PTR("failed to allocate pixd", __func__, NULL);
297  }
298  pixSetInputFormat(pixd, IFF_GIF);
299  pixSetColormap(pixd, cmap);
300  pixcmapIsValid(cmap, pixd, &valid);
301  if (!valid) {
302  DGifCloseFile(gif, &giferr);
303  pixDestroy(&pixd);
304  pixcmapDestroy(&cmap);
305  return (PIX *)ERROR_PTR("colormap is invalid", __func__, NULL);
306  }
307 
308  wpl = pixGetWpl(pixd);
309  data = pixGetData(pixd);
310  for (i = 0; i < h; i++) {
311  line = data + i * wpl;
312  if (d == 1) {
313  for (j = 0; j < w; j++) {
314  if (si.RasterBits[i * w + j])
315  SET_DATA_BIT(line, j);
316  }
317  } else if (d == 2) {
318  for (j = 0; j < w; j++)
319  SET_DATA_DIBIT(line, j, si.RasterBits[i * w + j]);
320  } else if (d == 4) {
321  for (j = 0; j < w; j++)
322  SET_DATA_QBIT(line, j, si.RasterBits[i * w + j]);
323  } else { /* d == 8 */
324  for (j = 0; j < w; j++)
325  SET_DATA_BYTE(line, j, si.RasterBits[i * w + j]);
326  }
327  }
328 
329  /* Versions before 5.0 required un-interlacing to restore
330  * the raster lines to normal order if the image
331  * had been interlaced (for viewing in a browser):
332  if (gif->Image.Interlace) {
333  PIX *pixdi = pixUninterlaceGIF(pixd);
334  pixTransferAllData(pixd, &pixdi, 0, 0);
335  }
336  * This is no longer required. */
337 
338  DGifCloseFile(gif, &giferr);
339  return pixd;
340 }
341 
342 
343 /*---------------------------------------------------------------------*
344  * Writing gif *
345  *---------------------------------------------------------------------*/
360 l_ok
361 pixWriteStreamGif(FILE *fp,
362  PIX *pix)
363 {
364 l_uint8 *filedata;
365 size_t filebytes, nbytes;
366 
367  if (!fp)
368  return ERROR_INT("stream not open", __func__, 1);
369  if (!pix)
370  return ERROR_INT("pix not defined", __func__, 1);
371 
372  pixSetPadBits(pix, 0);
373  if (pixWriteMemGif(&filedata, &filebytes, pix) != 0) {
374  LEPT_FREE(filedata);
375  return ERROR_INT("failure to gif encode pix", __func__, 1);
376  }
377 
378  rewind(fp);
379  nbytes = fwrite(filedata, 1, filebytes, fp);
380  LEPT_FREE(filedata);
381  if (nbytes != filebytes)
382  return ERROR_INT("write error", __func__, 1);
383  return 0;
384 }
385 
386 
400 l_ok
401 pixWriteMemGif(l_uint8 **pdata,
402  size_t *psize,
403  PIX *pix)
404 {
405 int giferr;
406 l_int32 result;
407 GifFileType *gif;
408 L_BBUFFER *buffer;
409 
410  /* 5.1+ and not 5.1.2 */
411 #if (GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0))
412  L_ERROR("Require giflib-5.1 or later\n", __func__);
413  return 1;
414 #endif /* < 5.1 */
415 #if GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 1 && GIFLIB_RELEASE == 2 /* 5.1.2 */
416  L_ERROR("Can't use giflib-5.1.2; suggest 5.1.3 or later\n", __func__);
417  return 1;
418 #endif /* 5.1.2 */
419 
420  if (!pdata)
421  return ERROR_INT("&data not defined", __func__, 1 );
422  *pdata = NULL;
423  if (!psize)
424  return ERROR_INT("&size not defined", __func__, 1 );
425  *psize = 0;
426  if (!pix)
427  return ERROR_INT("&pix not defined", __func__, 1 );
428 
429  if ((buffer = bbufferCreate(NULL, 0)) == NULL)
430  return ERROR_INT("failed to create buffer", __func__, 1);
431 
432  if ((gif = EGifOpen((void*)buffer, gifWriteFunc, NULL)) == NULL) {
433  bbufferDestroy(&buffer);
434  return ERROR_INT("failed to create GIF image handle", __func__, 1);
435  }
436 
437  result = pixToGif(pix, gif);
438  EGifCloseFile(gif, &giferr);
439 
440  if (result == 0) {
441  *pdata = bbufferDestroyAndSaveData(&buffer, psize);
442  } else {
443  bbufferDestroy(&buffer);
444  }
445  return result;
446 }
447 
448 
449 static l_int32
450 gifWriteFunc(GifFileType *gif,
451  const GifByteType *src,
452  l_int32 bytesToWrite)
453 {
454 L_BBUFFER *buffer;
455 
456  if ((buffer = (L_BBUFFER*)gif->UserData) == NULL)
457  return ERROR_INT("UserData not set", __func__, -1);
458 
459  if(bbufferRead(buffer, (l_uint8*)src, bytesToWrite) == 0)
460  return bytesToWrite;
461  return 0;
462 }
463 
464 
479 static l_int32
480 pixToGif(PIX *pix,
481  GifFileType *gif)
482 {
483 char *text;
484 l_int32 wpl, i, j, w, h, d, ncolor, rval, gval, bval, valid;
485 l_int32 gif_ncolor = 0;
486 l_uint32 *data, *line;
487 PIX *pixd;
488 PIXCMAP *cmap;
489 ColorMapObject *gif_cmap;
490 GifByteType *gif_line;
491 
492  if (!pix)
493  return ERROR_INT("pix not defined", __func__, 1);
494  if (!gif)
495  return ERROR_INT("gif not defined", __func__, 1);
496 
497  d = pixGetDepth(pix);
498  if (d == 32) {
499  pixd = pixConvertRGBToColormap(pix, 1);
500  } else if (d > 1) {
501  pixd = pixConvertTo8(pix, TRUE);
502  } else { /* d == 1; make sure there's a colormap */
503  pixd = pixClone(pix);
504  if (!pixGetColormap(pixd)) {
505  cmap = pixcmapCreate(1);
506  pixcmapAddColor(cmap, 255, 255, 255);
507  pixcmapAddColor(cmap, 0, 0, 0);
508  pixSetColormap(pixd, cmap);
509  }
510  }
511 
512  if (!pixd)
513  return ERROR_INT("failed to convert to colormapped pix", __func__, 1);
514  d = pixGetDepth(pixd);
515  cmap = pixGetColormap(pixd);
516  if (!cmap) {
517  pixDestroy(&pixd);
518  return ERROR_INT("cmap is missing", __func__, 1);
519  }
520  pixcmapIsValid(cmap, pixd, &valid);
521  if (!valid) {
522  pixDestroy(&pixd);
523  return ERROR_INT("colormap is not valid", __func__, 1);
524  }
525 
526  /* 'Round' the number of gif colors up to a power of 2 */
527  ncolor = pixcmapGetCount(cmap);
528  for (i = 0; i <= 8; i++) {
529  if ((1 << i) >= ncolor) {
530  gif_ncolor = (1 << i);
531  break;
532  }
533  }
534  if (gif_ncolor < 1) {
535  pixDestroy(&pixd);
536  return ERROR_INT("number of colors is invalid", __func__, 1);
537  }
538 
539  /* Save the cmap colors in a gif_cmap */
540  if ((gif_cmap = GifMakeMapObject(gif_ncolor, NULL)) == NULL) {
541  pixDestroy(&pixd);
542  return ERROR_INT("failed to create GIF color map", __func__, 1);
543  }
544  for (i = 0; i < gif_ncolor; i++) {
545  rval = gval = bval = 0;
546  if (ncolor > 0) {
547  if (pixcmapGetColor(cmap, i, &rval, &gval, &bval) != 0) {
548  pixDestroy(&pixd);
549  GifFreeMapObject(gif_cmap);
550  return ERROR_INT("failed to get color from color map",
551  __func__, 1);
552  }
553  ncolor--;
554  }
555  gif_cmap->Colors[i].Red = rval;
556  gif_cmap->Colors[i].Green = gval;
557  gif_cmap->Colors[i].Blue = bval;
558  }
559 
560  pixGetDimensions(pixd, &w, &h, NULL);
561  if (EGifPutScreenDesc(gif, w, h, gif_cmap->BitsPerPixel, 0, gif_cmap)
562  != GIF_OK) {
563  pixDestroy(&pixd);
564  GifFreeMapObject(gif_cmap);
565  return ERROR_INT("failed to write screen description", __func__, 1);
566  }
567  GifFreeMapObject(gif_cmap); /* not needed after this point */
568 
569  if (EGifPutImageDesc(gif, 0, 0, w, h, FALSE, NULL) != GIF_OK) {
570  pixDestroy(&pixd);
571  return ERROR_INT("failed to image screen description", __func__, 1);
572  }
573 
574  data = pixGetData(pixd);
575  wpl = pixGetWpl(pixd);
576  if (d != 1 && d != 2 && d != 4 && d != 8) {
577  pixDestroy(&pixd);
578  return ERROR_INT("image depth is not in {1, 2, 4, 8}", __func__, 1);
579  }
580 
581  if ((gif_line = (GifByteType *)LEPT_CALLOC(sizeof(GifByteType), w))
582  == NULL) {
583  pixDestroy(&pixd);
584  return ERROR_INT("mem alloc fail for data line", __func__, 1);
585  }
586 
587  for (i = 0; i < h; i++) {
588  line = data + i * wpl;
589  /* Gif's way of setting the raster line up for compression */
590  for (j = 0; j < w; j++) {
591  switch(d)
592  {
593  case 8:
594  gif_line[j] = GET_DATA_BYTE(line, j);
595  break;
596  case 4:
597  gif_line[j] = GET_DATA_QBIT(line, j);
598  break;
599  case 2:
600  gif_line[j] = GET_DATA_DIBIT(line, j);
601  break;
602  case 1:
603  gif_line[j] = GET_DATA_BIT(line, j);
604  break;
605  }
606  }
607 
608  /* Compress and save the line */
609  if (EGifPutLine(gif, gif_line, w) != GIF_OK) {
610  LEPT_FREE(gif_line);
611  pixDestroy(&pixd);
612  return ERROR_INT("failed to write data line into GIF", __func__, 1);
613  }
614  }
615 
616  /* Write a text comment. This must be placed after writing the
617  * data (!!) Note that because libgif does not provide a function
618  * for reading comments from file, you will need another way
619  * to read comments. */
620  if ((text = pixGetText(pix)) != NULL) {
621  if (EGifPutComment(gif, text) != GIF_OK)
622  L_WARNING("gif comment not written\n", __func__);
623  }
624 
625  LEPT_FREE(gif_line);
626  pixDestroy(&pixd);
627  return 0;
628 }
629 
630 
631 #if 0
632 /*---------------------------------------------------------------------*
633  * Removing interlacing (reference only; not used) *
634  *---------------------------------------------------------------------*/
635  /* GIF supports 4-way interlacing by raster lines.
636  * Before 5.0, it was necessary for leptonica to restore interlaced
637  * data to normal raster order when reading to a pix. With 5.0,
638  * the de-interlacing is done by the library read function.
639  * It is here only as a reference. */
640 static const l_int32 InterlacedOffset[] = {0, 4, 2, 1};
641 static const l_int32 InterlacedJumps[] = {8, 8, 4, 2};
642 
643 static PIX *
644 pixUninterlaceGIF(PIX *pixs)
645 {
646 l_int32 w, h, d, wpl, j, k, srow, drow;
647 l_uint32 *datas, *datad, *lines, *lined;
648 PIX *pixd;
649 
650  if (!pixs)
651  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
652 
653  pixGetDimensions(pixs, &w, &h, &d);
654  wpl = pixGetWpl(pixs);
655  pixd = pixCreateTemplate(pixs);
656  datas = pixGetData(pixs);
657  datad = pixGetData(pixd);
658  for (k = 0, srow = 0; k < 4; k++) {
659  for (drow = InterlacedOffset[k]; drow < h;
660  drow += InterlacedJumps[k], srow++) {
661  lines = datas + srow * wpl;
662  lined = datad + drow * wpl;
663  for (j = 0; j < w; j++)
664  memcpy(lined, lines, 4 * wpl);
665  }
666  }
667 
668  return pixd;
669 }
670 #endif
671 
672 
673 /* -----------------------------------------------------------------*/
674 #endif /* HAVE_LIBGIF || HAVE_LIBUNGIF */
#define GET_DATA_QBIT(pdata, n)
Definition: arrayaccess.h:164
#define SET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:127
#define SET_DATA_DIBIT(pdata, n, val)
Definition: arrayaccess.h:149
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
#define GET_DATA_DIBIT(pdata, n)
Definition: arrayaccess.h:145
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:123
#define SET_DATA_QBIT(pdata, n, val)
Definition: arrayaccess.h:168
l_ok bbufferRead(L_BBUFFER *bb, l_uint8 *src, l_int32 nbytes)
bbufferRead()
Definition: bbuffer.c:259
L_BBUFFER * bbufferCreate(const l_uint8 *indata, l_int32 nalloc)
bbufferCreate()
Definition: bbuffer.c:130
l_uint8 * bbufferDestroyAndSaveData(L_BBUFFER **pbb, size_t *pnbytes)
bbufferDestroyAndSaveData()
Definition: bbuffer.c:202
void bbufferDestroy(L_BBUFFER **pbb)
bbufferDestroy()
Definition: bbuffer.c:170
void pixcmapDestroy(PIXCMAP **pcmap)
pixcmapDestroy()
Definition: colormap.c:272
l_int32 pixcmapGetCount(const PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:683
l_ok pixcmapIsValid(const PIXCMAP *cmap, PIX *pix, l_int32 *pvalid)
pixcmapIsValid()
Definition: colormap.c:308
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:126
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition: colormap.c:789
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:403
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1642
l_ok pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1582
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1074
char * pixGetText(PIX *pix)
pixGetText()
Definition: pix1.c:1408
PIX * pixCreateTemplate(const PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:380
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
l_ok pixSetPadBits(PIX *pix, l_int32 val)
pixSetPadBits()
Definition: pix2.c:1346
PIX * pixConvertRGBToColormap(PIX *pixs, l_int32 ditherflag)
pixConvertRGBToColormap()
Definition: pixconv.c:1456
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3055
l_uint8 * l_binaryReadStream(FILE *fp, size_t *pnbytes)
l_binaryReadStream()
Definition: utils2.c:1358