Leptonica 1.82.0
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 */
83static PIX * gifToPix(GifFileType *gif);
84 /* Interface that enables low-level GIF support for writing to memory */
85static l_int32 pixToGif(PIX *pix, GifFileType *gif);
86
88typedef struct GifReadBuffer
89{
90 size_t size;
91 size_t pos;
92 const l_uint8 *cdata;
93} GifReadBuffer;
94
96static l_int32 gifReadFunc(GifFileType *gif, GifByteType *dest,
97 l_int32 bytesToRead);
99static l_int32 gifWriteFunc(GifFileType *gif, const GifByteType *src,
100 l_int32 bytesToWrite);
101
102
103/*---------------------------------------------------------------------*
104 * Reading gif *
105 *---------------------------------------------------------------------*/
112PIX *
113pixReadStreamGif(FILE *fp)
114{
115l_uint8 *filedata;
116size_t filesize;
117PIX *pix;
118
119 PROCNAME("pixReadStreamGif");
120
121 if (!fp)
122 return (PIX *)ERROR_PTR("fp not defined", procName, NULL);
123
124 /* Read data into memory from file */
125 rewind(fp);
126 if ((filedata = l_binaryReadStream(fp, &filesize)) == NULL)
127 return (PIX *)ERROR_PTR("filedata not read", procName, NULL);
128
129 /* Uncompress from memory */
130 pix = pixReadMemGif(filedata, filesize);
131 LEPT_FREE(filedata);
132 if (!pix)
133 L_ERROR("failed to read gif from file data\n", procName);
134 return pix;
135}
136
137
155PIX *
156pixReadMemGif(const l_uint8 *cdata,
157 size_t size)
158{
159GifFileType *gif;
160GifReadBuffer buffer;
161
162 PROCNAME("pixReadMemGif");
163
164 /* 5.1+ and not 5.1.2 */
165#if (GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0))
166 L_ERROR("Require giflib-5.1 or later\n", procName);
167 return NULL;
168#endif /* < 5.1 */
169#if GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 1 && GIFLIB_RELEASE == 2 /* 5.1.2 */
170 L_ERROR("Can't use giflib-5.1.2; suggest 5.1.3 or later\n", procName);
171 return NULL;
172#endif /* 5.1.2 */
173
174 if (!cdata)
175 return (PIX *)ERROR_PTR("cdata not defined", procName, NULL);
176
177 buffer.cdata = cdata;
178 buffer.size = size;
179 buffer.pos = 0;
180 if ((gif = DGifOpen((void*)&buffer, gifReadFunc, NULL)) == NULL)
181 return (PIX *)ERROR_PTR("could not open gif stream from memory",
182 procName, NULL);
183
184 return gifToPix(gif);
185}
186
187
188static l_int32
189gifReadFunc(GifFileType *gif,
190 GifByteType *dest,
191 l_int32 bytesToRead)
192{
193GifReadBuffer *buffer;
194l_int32 bytesRead;
195
196 PROCNAME("gifReadFunc");
197
198 if ((buffer = (GifReadBuffer*)gif->UserData) == NULL)
199 return ERROR_INT("UserData not set", procName, -1);
200
201 if(buffer->pos >= buffer->size || bytesToRead > buffer->size)
202 return -1;
203
204 bytesRead = (buffer->pos < buffer->size - bytesToRead)
205 ? bytesToRead : buffer->size - buffer->pos;
206 memcpy(dest, buffer->cdata + buffer->pos, bytesRead);
207 buffer->pos += bytesRead;
208 return bytesRead;
209}
210
211
225static PIX *
226gifToPix(GifFileType *gif)
227{
228l_int32 wpl, i, j, w, h, d, cindex, ncolors, valid, nimages;
229l_int32 rval, gval, bval;
230l_uint32 *data, *line;
231PIX *pixd;
232PIXCMAP *cmap;
233ColorMapObject *gif_cmap;
234SavedImage si;
235int giferr;
236
237 PROCNAME("gifToPix");
238
239 /* Read all the data, but use only the first image found */
240 if (DGifSlurp(gif) != GIF_OK) {
241 DGifCloseFile(gif, &giferr);
242 return (PIX *)ERROR_PTR("failed to read GIF data", procName, NULL);
243 }
244
245 if (gif->SavedImages == NULL) {
246 DGifCloseFile(gif, &giferr);
247 return (PIX *)ERROR_PTR("no images found in GIF", procName, NULL);
248 }
249
250 nimages = gif->ImageCount;
251 if (nimages > 1)
252 L_WARNING("There are %d images in the file; we only read the first\n",
253 procName, nimages);
254
255 si = gif->SavedImages[0];
256 w = si.ImageDesc.Width;
257 h = si.ImageDesc.Height;
258 if (w <= 0 || h <= 0) {
259 DGifCloseFile(gif, &giferr);
260 return (PIX *)ERROR_PTR("invalid image dimensions", procName, NULL);
261 }
262
263 if (si.RasterBits == NULL) {
264 DGifCloseFile(gif, &giferr);
265 return (PIX *)ERROR_PTR("no raster data in GIF", procName, NULL);
266 }
267
268 if (si.ImageDesc.ColorMap) {
269 /* private cmap for this image */
270 gif_cmap = si.ImageDesc.ColorMap;
271 } else if (gif->SColorMap) {
272 /* global cmap for whole picture */
273 gif_cmap = gif->SColorMap;
274 } else {
275 /* don't know where to take cmap from */
276 DGifCloseFile(gif, &giferr);
277 return (PIX *)ERROR_PTR("color map is missing", procName, NULL);
278 }
279
280 ncolors = gif_cmap->ColorCount;
281 if (ncolors <= 0 || ncolors > 256) {
282 DGifCloseFile(gif, &giferr);
283 return (PIX *)ERROR_PTR("ncolors is invalid", procName, NULL);
284 }
285 if (ncolors <= 2)
286 d = 1;
287 else if (ncolors <= 4)
288 d = 2;
289 else if (ncolors <= 16)
290 d = 4;
291 else /* [17 ... 256] */
292 d = 8;
293 cmap = pixcmapCreate(d);
294 for (cindex = 0; cindex < ncolors; cindex++) {
295 rval = gif_cmap->Colors[cindex].Red;
296 gval = gif_cmap->Colors[cindex].Green;
297 bval = gif_cmap->Colors[cindex].Blue;
298 pixcmapAddColor(cmap, rval, gval, bval);
299 }
300
301 if ((pixd = pixCreate(w, h, d)) == NULL) {
302 DGifCloseFile(gif, &giferr);
303 pixcmapDestroy(&cmap);
304 return (PIX *)ERROR_PTR("failed to allocate pixd", procName, NULL);
305 }
306 pixSetInputFormat(pixd, IFF_GIF);
307 pixSetColormap(pixd, cmap);
308 pixcmapIsValid(cmap, pixd, &valid);
309 if (!valid) {
310 DGifCloseFile(gif, &giferr);
311 pixDestroy(&pixd);
312 pixcmapDestroy(&cmap);
313 return (PIX *)ERROR_PTR("colormap is invalid", procName, NULL);
314 }
315
316 wpl = pixGetWpl(pixd);
317 data = pixGetData(pixd);
318 for (i = 0; i < h; i++) {
319 line = data + i * wpl;
320 if (d == 1) {
321 for (j = 0; j < w; j++) {
322 if (si.RasterBits[i * w + j])
323 SET_DATA_BIT(line, j);
324 }
325 } else if (d == 2) {
326 for (j = 0; j < w; j++)
327 SET_DATA_DIBIT(line, j, si.RasterBits[i * w + j]);
328 } else if (d == 4) {
329 for (j = 0; j < w; j++)
330 SET_DATA_QBIT(line, j, si.RasterBits[i * w + j]);
331 } else { /* d == 8 */
332 for (j = 0; j < w; j++)
333 SET_DATA_BYTE(line, j, si.RasterBits[i * w + j]);
334 }
335 }
336
337 /* Versions before 5.0 required un-interlacing to restore
338 * the raster lines to normal order if the image
339 * had been interlaced (for viewing in a browser):
340 if (gif->Image.Interlace) {
341 PIX *pixdi = pixUninterlaceGIF(pixd);
342 pixTransferAllData(pixd, &pixdi, 0, 0);
343 }
344 * This is no longer required. */
345
346 DGifCloseFile(gif, &giferr);
347 return pixd;
348}
349
350
351/*---------------------------------------------------------------------*
352 * Writing gif *
353 *---------------------------------------------------------------------*/
368l_ok
369pixWriteStreamGif(FILE *fp,
370 PIX *pix)
371{
372l_uint8 *filedata;
373size_t filebytes, nbytes;
374
375 PROCNAME("pixWriteStreamGif");
376
377 if (!fp)
378 return ERROR_INT("stream not open", procName, 1);
379 if (!pix)
380 return ERROR_INT("pix not defined", procName, 1);
381
382 pixSetPadBits(pix, 0);
383 if (pixWriteMemGif(&filedata, &filebytes, pix) != 0) {
384 LEPT_FREE(filedata);
385 return ERROR_INT("failure to gif encode pix", procName, 1);
386 }
387
388 rewind(fp);
389 nbytes = fwrite(filedata, 1, filebytes, fp);
390 LEPT_FREE(filedata);
391 if (nbytes != filebytes)
392 return ERROR_INT("write error", procName, 1);
393 return 0;
394}
395
396
410l_ok
411pixWriteMemGif(l_uint8 **pdata,
412 size_t *psize,
413 PIX *pix)
414{
415int giferr;
416l_int32 result;
417GifFileType *gif;
418L_BBUFFER *buffer;
419
420 PROCNAME("pixWriteMemGif");
421
422 /* 5.1+ and not 5.1.2 */
423#if (GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0))
424 L_ERROR("Require giflib-5.1 or later\n", procName);
425 return 1;
426#endif /* < 5.1 */
427#if GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 1 && GIFLIB_RELEASE == 2 /* 5.1.2 */
428 L_ERROR("Can't use giflib-5.1.2; suggest 5.1.3 or later\n", procName);
429 return 1;
430#endif /* 5.1.2 */
431
432 if (!pdata)
433 return ERROR_INT("&data not defined", procName, 1 );
434 *pdata = NULL;
435 if (!psize)
436 return ERROR_INT("&size not defined", procName, 1 );
437 *psize = 0;
438 if (!pix)
439 return ERROR_INT("&pix not defined", procName, 1 );
440
441 if ((buffer = bbufferCreate(NULL, 0)) == NULL)
442 return ERROR_INT("failed to create buffer", procName, 1);
443
444 if ((gif = EGifOpen((void*)buffer, gifWriteFunc, NULL)) == NULL) {
445 bbufferDestroy(&buffer);
446 return ERROR_INT("failed to create GIF image handle", procName, 1);
447 }
448
449 result = pixToGif(pix, gif);
450 EGifCloseFile(gif, &giferr);
451
452 if (result == 0) {
453 *pdata = bbufferDestroyAndSaveData(&buffer, psize);
454 } else {
455 bbufferDestroy(&buffer);
456 }
457 return result;
458}
459
460
461static l_int32
462gifWriteFunc(GifFileType *gif,
463 const GifByteType *src,
464 l_int32 bytesToWrite)
465{
466L_BBUFFER *buffer;
467
468 PROCNAME("gifWriteFunc");
469
470 if ((buffer = (L_BBUFFER*)gif->UserData) == NULL)
471 return ERROR_INT("UserData not set", procName, -1);
472
473 if(bbufferRead(buffer, (l_uint8*)src, bytesToWrite) == 0)
474 return bytesToWrite;
475 return 0;
476}
477
478
493static l_int32
494pixToGif(PIX *pix,
495 GifFileType *gif)
496{
497char *text;
498l_int32 wpl, i, j, w, h, d, ncolor, rval, gval, bval, valid;
499l_int32 gif_ncolor = 0;
500l_uint32 *data, *line;
501PIX *pixd;
502PIXCMAP *cmap;
503ColorMapObject *gif_cmap;
504GifByteType *gif_line;
505
506 PROCNAME("pixToGif");
507
508 if (!pix)
509 return ERROR_INT("pix not defined", procName, 1);
510 if (!gif)
511 return ERROR_INT("gif not defined", procName, 1);
512
513 d = pixGetDepth(pix);
514 if (d == 32) {
515 pixd = pixConvertRGBToColormap(pix, 1);
516 } else if (d > 1) {
517 pixd = pixConvertTo8(pix, TRUE);
518 } else { /* d == 1; make sure there's a colormap */
519 pixd = pixClone(pix);
520 if (!pixGetColormap(pixd)) {
521 cmap = pixcmapCreate(1);
522 pixcmapAddColor(cmap, 255, 255, 255);
523 pixcmapAddColor(cmap, 0, 0, 0);
524 pixSetColormap(pixd, cmap);
525 }
526 }
527
528 if (!pixd)
529 return ERROR_INT("failed to convert to colormapped pix", procName, 1);
530 d = pixGetDepth(pixd);
531 cmap = pixGetColormap(pixd);
532 if (!cmap) {
533 pixDestroy(&pixd);
534 return ERROR_INT("cmap is missing", procName, 1);
535 }
536 pixcmapIsValid(cmap, pixd, &valid);
537 if (!valid) {
538 pixDestroy(&pixd);
539 return ERROR_INT("colormap is not valid", procName, 1);
540 }
541
542 /* 'Round' the number of gif colors up to a power of 2 */
543 ncolor = pixcmapGetCount(cmap);
544 for (i = 0; i <= 8; i++) {
545 if ((1 << i) >= ncolor) {
546 gif_ncolor = (1 << i);
547 break;
548 }
549 }
550 if (gif_ncolor < 1) {
551 pixDestroy(&pixd);
552 return ERROR_INT("number of colors is invalid", procName, 1);
553 }
554
555 /* Save the cmap colors in a gif_cmap */
556 if ((gif_cmap = GifMakeMapObject(gif_ncolor, NULL)) == NULL) {
557 pixDestroy(&pixd);
558 return ERROR_INT("failed to create GIF color map", procName, 1);
559 }
560 for (i = 0; i < gif_ncolor; i++) {
561 rval = gval = bval = 0;
562 if (ncolor > 0) {
563 if (pixcmapGetColor(cmap, i, &rval, &gval, &bval) != 0) {
564 pixDestroy(&pixd);
565 GifFreeMapObject(gif_cmap);
566 return ERROR_INT("failed to get color from color map",
567 procName, 1);
568 }
569 ncolor--;
570 }
571 gif_cmap->Colors[i].Red = rval;
572 gif_cmap->Colors[i].Green = gval;
573 gif_cmap->Colors[i].Blue = bval;
574 }
575
576 pixGetDimensions(pixd, &w, &h, NULL);
577 if (EGifPutScreenDesc(gif, w, h, gif_cmap->BitsPerPixel, 0, gif_cmap)
578 != GIF_OK) {
579 pixDestroy(&pixd);
580 GifFreeMapObject(gif_cmap);
581 return ERROR_INT("failed to write screen description", procName, 1);
582 }
583 GifFreeMapObject(gif_cmap); /* not needed after this point */
584
585 if (EGifPutImageDesc(gif, 0, 0, w, h, FALSE, NULL) != GIF_OK) {
586 pixDestroy(&pixd);
587 return ERROR_INT("failed to image screen description", procName, 1);
588 }
589
590 data = pixGetData(pixd);
591 wpl = pixGetWpl(pixd);
592 if (d != 1 && d != 2 && d != 4 && d != 8) {
593 pixDestroy(&pixd);
594 return ERROR_INT("image depth is not in {1, 2, 4, 8}", procName, 1);
595 }
596
597 if ((gif_line = (GifByteType *)LEPT_CALLOC(sizeof(GifByteType), w))
598 == NULL) {
599 pixDestroy(&pixd);
600 return ERROR_INT("mem alloc fail for data line", procName, 1);
601 }
602
603 for (i = 0; i < h; i++) {
604 line = data + i * wpl;
605 /* Gif's way of setting the raster line up for compression */
606 for (j = 0; j < w; j++) {
607 switch(d)
608 {
609 case 8:
610 gif_line[j] = GET_DATA_BYTE(line, j);
611 break;
612 case 4:
613 gif_line[j] = GET_DATA_QBIT(line, j);
614 break;
615 case 2:
616 gif_line[j] = GET_DATA_DIBIT(line, j);
617 break;
618 case 1:
619 gif_line[j] = GET_DATA_BIT(line, j);
620 break;
621 }
622 }
623
624 /* Compress and save the line */
625 if (EGifPutLine(gif, gif_line, w) != GIF_OK) {
626 LEPT_FREE(gif_line);
627 pixDestroy(&pixd);
628 return ERROR_INT("failed to write data line into GIF", procName, 1);
629 }
630 }
631
632 /* Write a text comment. This must be placed after writing the
633 * data (!!) Note that because libgif does not provide a function
634 * for reading comments from file, you will need another way
635 * to read comments. */
636 if ((text = pixGetText(pix)) != NULL) {
637 if (EGifPutComment(gif, text) != GIF_OK)
638 L_WARNING("gif comment not written\n", procName);
639 }
640
641 LEPT_FREE(gif_line);
642 pixDestroy(&pixd);
643 return 0;
644}
645
646
647#if 0
648/*---------------------------------------------------------------------*
649 * Removing interlacing (reference only; not used) *
650 *---------------------------------------------------------------------*/
651 /* GIF supports 4-way interlacing by raster lines.
652 * Before 5.0, it was necessary for leptonica to restore interlaced
653 * data to normal raster order when reading to a pix. With 5.0,
654 * the de-interlacing is done by the library read function.
655 * It is here only as a reference. */
656static const l_int32 InterlacedOffset[] = {0, 4, 2, 1};
657static const l_int32 InterlacedJumps[] = {8, 8, 4, 2};
658
659static PIX *
660pixUninterlaceGIF(PIX *pixs)
661{
662l_int32 w, h, d, wpl, j, k, srow, drow;
663l_uint32 *datas, *datad, *lines, *lined;
664PIX *pixd;
665
666 PROCNAME("pixUninterlaceGIF");
667
668 if (!pixs)
669 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
670
671 pixGetDimensions(pixs, &w, &h, &d);
672 wpl = pixGetWpl(pixs);
673 pixd = pixCreateTemplate(pixs);
674 datas = pixGetData(pixs);
675 datad = pixGetData(pixd);
676 for (k = 0, srow = 0; k < 4; k++) {
677 for (drow = InterlacedOffset[k]; drow < h;
678 drow += InterlacedJumps[k], srow++) {
679 lines = datas + srow * wpl;
680 lined = datad + drow * wpl;
681 for (j = 0; j < w; j++)
682 memcpy(lined, lines, 4 * wpl);
683 }
684 }
685
686 return pixd;
687}
688#endif
689
690
691/* -----------------------------------------------------------------*/
692#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:265
l_uint8 * bbufferDestroyAndSaveData(L_BBUFFER **pbb, size_t *pnbytes)
bbufferDestroyAndSaveData()
Definition: bbuffer.c:206
L_BBUFFER * bbufferCreate(const l_uint8 *indata, l_int32 nalloc)
bbufferCreate()
Definition: bbuffer.c:130
void bbufferDestroy(L_BBUFFER **pbb)
bbufferDestroy()
Definition: bbuffer.c:172
void pixcmapDestroy(PIXCMAP **pcmap)
pixcmapDestroy()
Definition: colormap.c:279
l_int32 pixcmapGetCount(const PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:708
l_ok pixcmapIsValid(const PIXCMAP *cmap, PIX *pix, l_int32 *pvalid)
pixcmapIsValid()
Definition: colormap.c:317
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:125
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition: colormap.c:824
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:414
l_ok pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1699
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
PIX * pixCreateTemplate(const PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:383
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
char * pixGetText(PIX *pix)
pixGetText()
Definition: pix1.c:1512
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1763
l_ok pixSetPadBits(PIX *pix, l_int32 val)
pixSetPadBits()
Definition: pix2.c:1382
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3133
PIX * pixConvertRGBToColormap(PIX *pixs, l_int32 ditherflag)
pixConvertRGBToColormap()
Definition: pixconv.c:1486
Definition: pix.h:139
l_uint8 * l_binaryReadStream(FILE *fp, size_t *pnbytes)
l_binaryReadStream()
Definition: utils2.c:1402