70 #include <config_auto.h>
74 #include "allheaders.h"
77 #if HAVE_LIBGIF || HAVE_LIBUNGIF
83 static PIX * gifToPix(GifFileType *gif);
85 static l_int32 pixToGif(
PIX *pix, GifFileType *gif);
88 typedef struct GifReadBuffer
96 static l_int32 gifReadFunc(GifFileType *gif, GifByteType *dest,
99 static l_int32 gifWriteFunc(GifFileType *gif,
const GifByteType *src,
100 l_int32 bytesToWrite);
113 pixReadStreamGif(FILE *fp)
120 return (
PIX *)ERROR_PTR(
"fp not defined", __func__, NULL);
125 return (
PIX *)ERROR_PTR(
"filedata not read", __func__, NULL);
128 pix = pixReadMemGif(filedata, filesize);
131 L_ERROR(
"failed to read gif from file data\n", __func__);
154 pixReadMemGif(
const l_uint8 *cdata,
158 GifReadBuffer buffer;
161 #if (GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0))
162 L_ERROR(
"Require giflib-5.1 or later\n", __func__);
165 #if GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 1 && GIFLIB_RELEASE == 2
166 L_ERROR(
"Can't use giflib-5.1.2; suggest 5.1.3 or later\n", __func__);
171 return (
PIX *)ERROR_PTR(
"cdata not defined", __func__, NULL);
173 buffer.cdata = cdata;
176 if ((gif = DGifOpen((
void*)&buffer, gifReadFunc, NULL)) == NULL)
177 return (
PIX *)ERROR_PTR(
"could not open gif stream from memory",
180 return gifToPix(gif);
185 gifReadFunc(GifFileType *gif,
189 GifReadBuffer *buffer;
192 if ((buffer = (GifReadBuffer*)gif->UserData) == NULL)
193 return ERROR_INT(
"UserData not set", __func__, -1);
195 if(buffer->pos >= buffer->size || bytesToRead > buffer->size)
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;
220 gifToPix(GifFileType *gif)
222 l_int32 wpl, i, j, w, h, d, cindex, ncolors, valid, nimages;
223 l_int32 rval, gval, bval;
224 l_uint32 *data, *line;
227 ColorMapObject *gif_cmap;
232 if (DGifSlurp(gif) != GIF_OK) {
233 DGifCloseFile(gif, &giferr);
234 return (
PIX *)ERROR_PTR(
"failed to read GIF data", __func__, NULL);
237 if (gif->SavedImages == NULL) {
238 DGifCloseFile(gif, &giferr);
239 return (
PIX *)ERROR_PTR(
"no images found in GIF", __func__, NULL);
242 nimages = gif->ImageCount;
244 L_WARNING(
"There are %d images in the file; we only read the first\n",
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);
255 if (si.RasterBits == NULL) {
256 DGifCloseFile(gif, &giferr);
257 return (
PIX *)ERROR_PTR(
"no raster data in GIF", __func__, NULL);
260 if (si.ImageDesc.ColorMap) {
262 gif_cmap = si.ImageDesc.ColorMap;
263 }
else if (gif->SColorMap) {
265 gif_cmap = gif->SColorMap;
268 DGifCloseFile(gif, &giferr);
269 return (
PIX *)ERROR_PTR(
"color map is missing", __func__, NULL);
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);
279 else if (ncolors <= 4)
281 else if (ncolors <= 16)
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;
293 if ((pixd =
pixCreate(w, h, d)) == NULL) {
294 DGifCloseFile(gif, &giferr);
296 return (
PIX *)ERROR_PTR(
"failed to allocate pixd", __func__, NULL);
298 pixSetInputFormat(pixd, IFF_GIF);
302 DGifCloseFile(gif, &giferr);
305 return (
PIX *)ERROR_PTR(
"colormap is invalid", __func__, NULL);
308 wpl = pixGetWpl(pixd);
310 for (i = 0; i < h; i++) {
311 line = data + i * wpl;
313 for (j = 0; j < w; j++) {
314 if (si.RasterBits[i * w + j])
318 for (j = 0; j < w; j++)
321 for (j = 0; j < w; j++)
324 for (j = 0; j < w; j++)
338 DGifCloseFile(gif, &giferr);
361 pixWriteStreamGif(FILE *fp,
365 size_t filebytes, nbytes;
368 return ERROR_INT(
"stream not open", __func__, 1);
370 return ERROR_INT(
"pix not defined", __func__, 1);
373 if (pixWriteMemGif(&filedata, &filebytes, pix) != 0) {
375 return ERROR_INT(
"failure to gif encode pix", __func__, 1);
379 nbytes = fwrite(filedata, 1, filebytes, fp);
381 if (nbytes != filebytes)
382 return ERROR_INT(
"write error", __func__, 1);
401 pixWriteMemGif(l_uint8 **pdata,
411 #if (GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0))
412 L_ERROR(
"Require giflib-5.1 or later\n", __func__);
415 #if GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 1 && GIFLIB_RELEASE == 2
416 L_ERROR(
"Can't use giflib-5.1.2; suggest 5.1.3 or later\n", __func__);
421 return ERROR_INT(
"&data not defined", __func__, 1 );
424 return ERROR_INT(
"&size not defined", __func__, 1 );
427 return ERROR_INT(
"&pix not defined", __func__, 1 );
430 return ERROR_INT(
"failed to create buffer", __func__, 1);
432 if ((gif = EGifOpen((
void*)buffer, gifWriteFunc, NULL)) == NULL) {
434 return ERROR_INT(
"failed to create GIF image handle", __func__, 1);
437 result = pixToGif(pix, gif);
438 EGifCloseFile(gif, &giferr);
450 gifWriteFunc(GifFileType *gif,
451 const GifByteType *src,
452 l_int32 bytesToWrite)
456 if ((buffer = (
L_BBUFFER*)gif->UserData) == NULL)
457 return ERROR_INT(
"UserData not set", __func__, -1);
459 if(
bbufferRead(buffer, (l_uint8*)src, bytesToWrite) == 0)
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;
489 ColorMapObject *gif_cmap;
490 GifByteType *gif_line;
493 return ERROR_INT(
"pix not defined", __func__, 1);
495 return ERROR_INT(
"gif not defined", __func__, 1);
497 d = pixGetDepth(pix);
504 if (!pixGetColormap(pixd)) {
513 return ERROR_INT(
"failed to convert to colormapped pix", __func__, 1);
514 d = pixGetDepth(pixd);
515 cmap = pixGetColormap(pixd);
518 return ERROR_INT(
"cmap is missing", __func__, 1);
523 return ERROR_INT(
"colormap is not valid", __func__, 1);
528 for (i = 0; i <= 8; i++) {
529 if ((1 << i) >= ncolor) {
530 gif_ncolor = (1 << i);
534 if (gif_ncolor < 1) {
536 return ERROR_INT(
"number of colors is invalid", __func__, 1);
540 if ((gif_cmap = GifMakeMapObject(gif_ncolor, NULL)) == NULL) {
542 return ERROR_INT(
"failed to create GIF color map", __func__, 1);
544 for (i = 0; i < gif_ncolor; i++) {
545 rval = gval = bval = 0;
549 GifFreeMapObject(gif_cmap);
550 return ERROR_INT(
"failed to get color from color map",
555 gif_cmap->Colors[i].Red = rval;
556 gif_cmap->Colors[i].Green = gval;
557 gif_cmap->Colors[i].Blue = bval;
561 if (EGifPutScreenDesc(gif, w, h, gif_cmap->BitsPerPixel, 0, gif_cmap)
564 GifFreeMapObject(gif_cmap);
565 return ERROR_INT(
"failed to write screen description", __func__, 1);
567 GifFreeMapObject(gif_cmap);
569 if (EGifPutImageDesc(gif, 0, 0, w, h, FALSE, NULL) != GIF_OK) {
571 return ERROR_INT(
"failed to image screen description", __func__, 1);
575 wpl = pixGetWpl(pixd);
576 if (d != 1 && d != 2 && d != 4 && d != 8) {
578 return ERROR_INT(
"image depth is not in {1, 2, 4, 8}", __func__, 1);
581 if ((gif_line = (GifByteType *)LEPT_CALLOC(
sizeof(GifByteType), w))
584 return ERROR_INT(
"mem alloc fail for data line", __func__, 1);
587 for (i = 0; i < h; i++) {
588 line = data + i * wpl;
590 for (j = 0; j < w; j++) {
609 if (EGifPutLine(gif, gif_line, w) != GIF_OK) {
612 return ERROR_INT(
"failed to write data line into GIF", __func__, 1);
621 if (EGifPutComment(gif, text) != GIF_OK)
622 L_WARNING(
"gif comment not written\n", __func__);
640 static const l_int32 InterlacedOffset[] = {0, 4, 2, 1};
641 static const l_int32 InterlacedJumps[] = {8, 8, 4, 2};
644 pixUninterlaceGIF(
PIX *pixs)
646 l_int32 w, h, d, wpl, j, k, srow, drow;
647 l_uint32 *datas, *datad, *lines, *lined;
651 return (
PIX *)ERROR_PTR(
"pixs not defined", __func__, NULL);
654 wpl = pixGetWpl(pixs);
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);
#define GET_DATA_QBIT(pdata, n)
#define SET_DATA_BIT(pdata, n)
#define SET_DATA_DIBIT(pdata, n, val)
#define GET_DATA_BYTE(pdata, n)
#define GET_DATA_DIBIT(pdata, n)
#define SET_DATA_BYTE(pdata, n, val)
#define GET_DATA_BIT(pdata, n)
#define SET_DATA_QBIT(pdata, n, val)
l_ok bbufferRead(L_BBUFFER *bb, l_uint8 *src, l_int32 nbytes)
bbufferRead()
L_BBUFFER * bbufferCreate(const l_uint8 *indata, l_int32 nalloc)
bbufferCreate()
l_uint8 * bbufferDestroyAndSaveData(L_BBUFFER **pbb, size_t *pnbytes)
bbufferDestroyAndSaveData()
void bbufferDestroy(L_BBUFFER **pbb)
bbufferDestroy()
void pixcmapDestroy(PIXCMAP **pcmap)
pixcmapDestroy()
l_int32 pixcmapGetCount(const PIXCMAP *cmap)
pixcmapGetCount()
l_ok pixcmapIsValid(const PIXCMAP *cmap, PIX *pix, l_int32 *pvalid)
pixcmapIsValid()
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
l_uint32 * pixGetData(PIX *pix)
pixGetData()
l_ok pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
void pixDestroy(PIX **ppix)
pixDestroy()
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
char * pixGetText(PIX *pix)
pixGetText()
PIX * pixCreateTemplate(const PIX *pixs)
pixCreateTemplate()
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
PIX * pixClone(PIX *pixs)
pixClone()
l_ok pixSetPadBits(PIX *pix, l_int32 val)
pixSetPadBits()
PIX * pixConvertRGBToColormap(PIX *pixs, l_int32 ditherflag)
pixConvertRGBToColormap()
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
l_uint8 * l_binaryReadStream(FILE *fp, size_t *pnbytes)
l_binaryReadStream()