76#include <config_auto.h>
80#include "allheaders.h"
83#if HAVE_LIBGIF || HAVE_LIBUNGIF
89static PIX * gifToPix(GifFileType *gif);
91static l_int32 pixToGif(
PIX *pix, GifFileType *gif);
94typedef struct GifReadBuffer
102static l_int32 gifReadFunc(GifFileType *gif, GifByteType *dest,
103 l_int32 bytesToRead);
105static l_int32 gifWriteFunc(GifFileType *gif,
const GifByteType *src,
106 l_int32 bytesToWrite);
119pixReadStreamGif(FILE *fp)
126 return (
PIX *)ERROR_PTR(
"fp not defined", __func__, NULL);
130 if ((filedata = l_binaryReadStream(fp, &filesize)) == NULL)
131 return (
PIX *)ERROR_PTR(
"filedata not read", __func__, NULL);
134 pix = pixReadMemGif(filedata, filesize);
137 L_ERROR(
"failed to read gif from file data\n", __func__);
160pixReadMemGif(
const l_uint8 *cdata,
167#if (GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0))
168 L_ERROR(
"Require giflib-5.1 or later\n", __func__);
171#if GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 1 && GIFLIB_RELEASE == 2
172 L_ERROR(
"Can't use giflib-5.1.2; suggest 5.1.3 or later\n", __func__);
177 return (
PIX *)ERROR_PTR(
"cdata not defined", __func__, NULL);
179 buffer.cdata = cdata;
182 if ((gif = DGifOpen((
void*)&buffer, gifReadFunc, NULL)) == NULL)
183 return (
PIX *)ERROR_PTR(
"could not open gif stream from memory",
186 return gifToPix(gif);
191gifReadFunc(GifFileType *gif,
195GifReadBuffer *buffer;
198 if ((buffer = (GifReadBuffer*)gif->UserData) == NULL)
199 return ERROR_INT(
"UserData not set", __func__, -1);
201 if(buffer->pos >= buffer->size || bytesToRead > buffer->size)
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;
227gifToPix(GifFileType *gif)
229l_int32 wpl, i, j, w, h, d, cindex, ncolors, valid, nimages;
230l_int32 rval, gval, bval;
231l_uint32 *data, *line;
234ColorMapObject *gif_cmap;
239 if (DGifSlurp(gif) != GIF_OK) {
240 DGifCloseFile(gif, &giferr);
241 return (
PIX *)ERROR_PTR(
"failed to read GIF data", __func__, NULL);
244 if (gif->SavedImages == NULL) {
245 DGifCloseFile(gif, &giferr);
246 return (
PIX *)ERROR_PTR(
"no images found in GIF", __func__, NULL);
249 nimages = gif->ImageCount;
251 DGifCloseFile(gif, &giferr);
252 L_ERROR(
"There are %d images in the file; gifanim is not supported\n",
257 si = gif->SavedImages[0];
258 w = si.ImageDesc.Width;
259 h = si.ImageDesc.Height;
260 if (w <= 0 || h <= 0) {
261 DGifCloseFile(gif, &giferr);
262 return (
PIX *)ERROR_PTR(
"invalid image dimensions", __func__, NULL);
265 if (si.RasterBits == NULL) {
266 DGifCloseFile(gif, &giferr);
267 return (
PIX *)ERROR_PTR(
"no raster data in GIF", __func__, NULL);
270 if (si.ImageDesc.ColorMap) {
272 gif_cmap = si.ImageDesc.ColorMap;
273 }
else if (gif->SColorMap) {
275 gif_cmap = gif->SColorMap;
278 DGifCloseFile(gif, &giferr);
279 return (
PIX *)ERROR_PTR(
"color map is missing", __func__, NULL);
282 ncolors = gif_cmap->ColorCount;
283 if (ncolors <= 0 || ncolors > 256) {
284 DGifCloseFile(gif, &giferr);
285 return (
PIX *)ERROR_PTR(
"ncolors is invalid", __func__, NULL);
289 else if (ncolors <= 4)
291 else if (ncolors <= 16)
295 cmap = pixcmapCreate(d);
296 for (cindex = 0; cindex < ncolors; cindex++) {
297 rval = gif_cmap->Colors[cindex].Red;
298 gval = gif_cmap->Colors[cindex].Green;
299 bval = gif_cmap->Colors[cindex].Blue;
300 pixcmapAddColor(cmap, rval, gval, bval);
303 if ((pixd = pixCreate(w, h, d)) == NULL) {
304 DGifCloseFile(gif, &giferr);
305 pixcmapDestroy(&cmap);
306 return (
PIX *)ERROR_PTR(
"failed to allocate pixd", __func__, NULL);
308 pixSetInputFormat(pixd, IFF_GIF);
309 pixSetColormap(pixd, cmap);
310 pixcmapIsValid(cmap, pixd, &valid);
312 DGifCloseFile(gif, &giferr);
314 pixcmapDestroy(&cmap);
315 return (
PIX *)ERROR_PTR(
"colormap is invalid", __func__, NULL);
318 wpl = pixGetWpl(pixd);
319 data = pixGetData(pixd);
320 for (i = 0; i < h; i++) {
321 line = data + i * wpl;
323 for (j = 0; j < w; j++) {
324 if (si.RasterBits[i * w + j])
328 for (j = 0; j < w; j++)
331 for (j = 0; j < w; j++)
334 for (j = 0; j < w; j++)
348 DGifCloseFile(gif, &giferr);
371pixWriteStreamGif(FILE *fp,
375size_t filebytes, nbytes;
378 return ERROR_INT(
"stream not open", __func__, 1);
380 return ERROR_INT(
"pix not defined", __func__, 1);
382 pixSetPadBits(pix, 0);
383 if (pixWriteMemGif(&filedata, &filebytes, pix) != 0) {
385 return ERROR_INT(
"failure to gif encode pix", __func__, 1);
389 nbytes = fwrite(filedata, 1, filebytes, fp);
391 if (nbytes != filebytes)
392 return ERROR_INT(
"write error", __func__, 1);
411pixWriteMemGif(l_uint8 **pdata,
421#if (GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0))
422 L_ERROR(
"Require giflib-5.1 or later\n", __func__);
425#if GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 1 && GIFLIB_RELEASE == 2
426 L_ERROR(
"Can't use giflib-5.1.2; suggest 5.1.3 or later\n", __func__);
431 return ERROR_INT(
"&data not defined", __func__, 1 );
434 return ERROR_INT(
"&size not defined", __func__, 1 );
437 return ERROR_INT(
"&pix not defined", __func__, 1 );
439 if ((buffer = bbufferCreate(NULL, 0)) == NULL)
440 return ERROR_INT(
"failed to create buffer", __func__, 1);
442 if ((gif = EGifOpen((
void*)buffer, gifWriteFunc, NULL)) == NULL) {
443 bbufferDestroy(&buffer);
444 return ERROR_INT(
"failed to create GIF image handle", __func__, 1);
447 result = pixToGif(pix, gif);
448 EGifCloseFile(gif, &giferr);
451 *pdata = bbufferDestroyAndSaveData(&buffer, psize);
453 bbufferDestroy(&buffer);
460gifWriteFunc(GifFileType *gif,
461 const GifByteType *src,
462 l_int32 bytesToWrite)
466 if ((buffer = (
L_BBUFFER*)gif->UserData) == NULL)
467 return ERROR_INT(
"UserData not set", __func__, -1);
469 if(bbufferRead(buffer, (l_uint8*)src, bytesToWrite) == 0)
494l_int32 wpl, i, j, w, h, d, ncolor, rval, gval, bval, valid;
495l_int32 gif_ncolor = 0;
496l_uint32 *data, *line;
499ColorMapObject *gif_cmap;
500GifByteType *gif_line;
503 return ERROR_INT(
"pix not defined", __func__, 1);
505 return ERROR_INT(
"gif not defined", __func__, 1);
507 d = pixGetDepth(pix);
509 pixd = pixConvertRGBToColormap(pix, 1);
511 pixd = pixConvertTo8(pix, TRUE);
513 pixd = pixClone(pix);
514 if (!pixGetColormap(pixd)) {
515 cmap = pixcmapCreate(1);
516 pixcmapAddColor(cmap, 255, 255, 255);
517 pixcmapAddColor(cmap, 0, 0, 0);
518 pixSetColormap(pixd, cmap);
523 return ERROR_INT(
"failed to convert to colormapped pix", __func__, 1);
524 d = pixGetDepth(pixd);
525 cmap = pixGetColormap(pixd);
528 return ERROR_INT(
"cmap is missing", __func__, 1);
530 pixcmapIsValid(cmap, pixd, &valid);
533 return ERROR_INT(
"colormap is not valid", __func__, 1);
537 ncolor = pixcmapGetCount(cmap);
538 for (i = 0; i <= 8; i++) {
539 if ((1 << i) >= ncolor) {
540 gif_ncolor = (1 << i);
544 if (gif_ncolor < 1) {
546 return ERROR_INT(
"number of colors is invalid", __func__, 1);
550 if ((gif_cmap = GifMakeMapObject(gif_ncolor, NULL)) == NULL) {
552 return ERROR_INT(
"failed to create GIF color map", __func__, 1);
554 for (i = 0; i < gif_ncolor; i++) {
555 rval = gval = bval = 0;
557 if (pixcmapGetColor(cmap, i, &rval, &gval, &bval) != 0) {
559 GifFreeMapObject(gif_cmap);
560 return ERROR_INT(
"failed to get color from color map",
565 gif_cmap->Colors[i].Red = rval;
566 gif_cmap->Colors[i].Green = gval;
567 gif_cmap->Colors[i].Blue = bval;
570 pixGetDimensions(pixd, &w, &h, NULL);
571 if (EGifPutScreenDesc(gif, w, h, gif_cmap->BitsPerPixel, 0, gif_cmap)
574 GifFreeMapObject(gif_cmap);
575 return ERROR_INT(
"failed to write screen description", __func__, 1);
577 GifFreeMapObject(gif_cmap);
579 if (EGifPutImageDesc(gif, 0, 0, w, h, FALSE, NULL) != GIF_OK) {
581 return ERROR_INT(
"failed to image screen description", __func__, 1);
584 data = pixGetData(pixd);
585 wpl = pixGetWpl(pixd);
586 if (d != 1 && d != 2 && d != 4 && d != 8) {
588 return ERROR_INT(
"image depth is not in {1, 2, 4, 8}", __func__, 1);
591 if ((gif_line = (GifByteType *)LEPT_CALLOC(
sizeof(GifByteType), w))
594 return ERROR_INT(
"mem alloc fail for data line", __func__, 1);
597 for (i = 0; i < h; i++) {
598 line = data + i * wpl;
600 for (j = 0; j < w; j++) {
619 if (EGifPutLine(gif, gif_line, w) != GIF_OK) {
622 return ERROR_INT(
"failed to write data line into GIF", __func__, 1);
630 if ((text = pixGetText(pix)) != NULL) {
631 if (EGifPutComment(gif, text) != GIF_OK)
632 L_WARNING(
"gif comment not written\n", __func__);
650static const l_int32 InterlacedOffset[] = {0, 4, 2, 1};
651static const l_int32 InterlacedJumps[] = {8, 8, 4, 2};
654pixUninterlaceGIF(
PIX *pixs)
656l_int32 w, h, d, wpl, j, k, srow, drow;
657l_uint32 *datas, *datad, *lines, *lined;
661 return (
PIX *)ERROR_PTR(
"pixs not defined", __func__, NULL);
663 pixGetDimensions(pixs, &w, &h, &d);
664 wpl = pixGetWpl(pixs);
665 pixd = pixCreateTemplate(pixs);
666 datas = pixGetData(pixs);
667 datad = pixGetData(pixd);
668 for (k = 0, srow = 0; k < 4; k++) {
669 for (drow = InterlacedOffset[k]; drow < h;
670 drow += InterlacedJumps[k], srow++) {
671 lines = datas + srow * wpl;
672 lined = datad + drow * wpl;
673 for (j = 0; j < w; j++)
674 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)