aboutsummaryrefslogtreecommitdiffstats
path: root/rd/read-gif.c
diff options
context:
space:
mode:
Diffstat (limited to 'rd/read-gif.c')
-rw-r--r--rd/read-gif.c220
1 files changed, 220 insertions, 0 deletions
diff --git a/rd/read-gif.c b/rd/read-gif.c
new file mode 100644
index 0000000..b841dc7
--- /dev/null
+++ b/rd/read-gif.c
@@ -0,0 +1,220 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gif_lib.h>
+
+#include "readers.h"
+
+struct gif_state {
+ FILE *infile;
+ GifFileType *gif;
+ GifPixelType *row;
+ GifPixelType *il;
+ int w,h;
+};
+
+static GifRecordType
+gif_fileread(struct gif_state *h)
+{
+ GifRecordType RecordType;
+ GifByteType *Extension;
+ int ExtCode, rc;
+ char *type;
+
+ for (;;) {
+ if (GIF_ERROR == DGifGetRecordType(h->gif,&RecordType)) {
+ if (debug)
+ fprintf(stderr,"gif: DGifGetRecordType failed\n");
+ PrintGifError();
+ return -1;
+ }
+ switch (RecordType) {
+ case IMAGE_DESC_RECORD_TYPE:
+ if (debug)
+ fprintf(stderr,"gif: IMAGE_DESC_RECORD_TYPE found\n");
+ return RecordType;
+ case EXTENSION_RECORD_TYPE:
+ if (debug)
+ fprintf(stderr,"gif: EXTENSION_RECORD_TYPE found\n");
+ for (rc = DGifGetExtension(h->gif,&ExtCode,&Extension);
+ NULL != Extension;
+ rc = DGifGetExtensionNext(h->gif,&Extension)) {
+ if (rc == GIF_ERROR) {
+ if (debug)
+ fprintf(stderr,"gif: DGifGetExtension failed\n");
+ PrintGifError();
+ return -1;
+ }
+ if (debug) {
+ switch (ExtCode) {
+ case COMMENT_EXT_FUNC_CODE: type="comment"; break;
+ case GRAPHICS_EXT_FUNC_CODE: type="graphics"; break;
+ case PLAINTEXT_EXT_FUNC_CODE: type="plaintext"; break;
+ case APPLICATION_EXT_FUNC_CODE: type="appl"; break;
+ default: type="???"; break;
+ }
+ fprintf(stderr,"gif: extcode=0x%x [%s]\n",ExtCode,type);
+ }
+ }
+ break;
+ case TERMINATE_RECORD_TYPE:
+ if (debug)
+ fprintf(stderr,"gif: TERMINATE_RECORD_TYPE found\n");
+ return RecordType;
+ default:
+ if (debug)
+ fprintf(stderr,"gif: unknown record type [%d]\n",RecordType);
+ return -1;
+ }
+ }
+}
+
+#if 0
+static void
+gif_skipimage(struct gif_state *h)
+{
+ unsigned char *line;
+ int i;
+
+ if (debug)
+ fprintf(stderr,"gif: skipping image record ...\n");
+ DGifGetImageDesc(h->gif);
+ line = malloc(h->gif->SWidth);
+ for (i = 0; i < h->gif->SHeight; i++)
+ DGifGetLine(h->gif, line, h->gif->SWidth);
+ free(line);
+}
+#endif
+
+static void*
+gif_init(FILE *fp, char *filename, unsigned int page,
+ struct ida_image_info *info, int thumbnail)
+{
+ struct gif_state *h;
+ GifRecordType RecordType;
+ int i, image = 0;
+
+ h = malloc(sizeof(*h));
+ memset(h,0,sizeof(*h));
+
+ h->infile = fp;
+ h->gif = DGifOpenFileHandle(fileno(fp));
+ h->row = malloc(h->gif->SWidth * sizeof(GifPixelType));
+
+ while (0 == image) {
+ RecordType = gif_fileread(h);
+ switch (RecordType) {
+ case IMAGE_DESC_RECORD_TYPE:
+ if (GIF_ERROR == DGifGetImageDesc(h->gif)) {
+ if (debug)
+ fprintf(stderr,"gif: DGifGetImageDesc failed\n");
+ PrintGifError();
+ }
+ if (NULL == h->gif->SColorMap &&
+ NULL == h->gif->Image.ColorMap) {
+ if (debug)
+ fprintf(stderr,"gif: oops: no colormap found\n");
+ goto oops;
+ }
+#if 0
+ info->width = h->w = h->gif->SWidth;
+ info->height = h->h = h->gif->SHeight;
+#else
+ info->width = h->w = h->gif->Image.Width;
+ info->height = h->h = h->gif->Image.Height;
+#endif
+ info->npages = 1;
+ image = 1;
+ if (debug)
+ fprintf(stderr,"gif: reading image record ...\n");
+ if (h->gif->Image.Interlace) {
+ if (debug)
+ fprintf(stderr,"gif: interlaced\n");
+ h->il = malloc(h->w * h->h * sizeof(GifPixelType));
+ for (i = 0; i < h->h; i += 8)
+ DGifGetLine(h->gif, h->il + h->w*i,h->w);
+ for (i = 4; i < h->gif->SHeight; i += 8)
+ DGifGetLine(h->gif, h->il + h->w*i,h->w);
+ for (i = 2; i < h->gif->SHeight; i += 4)
+ DGifGetLine(h->gif, h->il + h->w*i,h->w);
+ }
+ break;
+ case TERMINATE_RECORD_TYPE:
+ default:
+ goto oops;
+ }
+ }
+ if (0 == info->width || 0 == info->height)
+ goto oops;
+
+ if (debug)
+ fprintf(stderr,"gif: s=%dx%d i=%dx%d\n",
+ h->gif->SWidth,h->gif->SHeight,
+ h->gif->Image.Width,h->gif->Image.Height);
+ return h;
+
+ oops:
+ if (debug)
+ fprintf(stderr,"gif: fatal error, aborting\n");
+ DGifCloseFile(h->gif);
+ fclose(h->infile);
+ free(h->row);
+ free(h);
+ return NULL;
+}
+
+static void
+gif_read(unsigned char *dst, unsigned int line, void *data)
+{
+ struct gif_state *h = data;
+ GifColorType *cmap;
+ int x;
+
+ if (h->gif->Image.Interlace) {
+ if (line % 2) {
+ DGifGetLine(h->gif, h->row, h->w);
+ } else {
+ memcpy(h->row, h->il + h->w * line, h->w);
+ }
+ } else {
+ DGifGetLine(h->gif, h->row, h->w);
+ }
+ cmap = h->gif->Image.ColorMap ?
+ h->gif->Image.ColorMap->Colors : h->gif->SColorMap->Colors;
+ for (x = 0; x < h->w; x++) {
+ dst[0] = cmap[h->row[x]].Red;
+ dst[1] = cmap[h->row[x]].Green;
+ dst[2] = cmap[h->row[x]].Blue;
+ dst += 3;
+ }
+}
+
+static void
+gif_done(void *data)
+{
+ struct gif_state *h = data;
+
+ if (debug)
+ fprintf(stderr,"gif: done, cleaning up\n");
+ DGifCloseFile(h->gif);
+ fclose(h->infile);
+ if (h->il)
+ free(h->il);
+ free(h->row);
+ free(h);
+}
+
+static struct ida_loader gif_loader = {
+ magic: "GIF",
+ moff: 0,
+ mlen: 3,
+ name: "libungif",
+ init: gif_init,
+ read: gif_read,
+ done: gif_done,
+};
+
+static void __init init_rd(void)
+{
+ load_register(&gif_loader);
+}