aboutsummaryrefslogtreecommitdiffstats
path: root/rd
diff options
context:
space:
mode:
Diffstat (limited to 'rd')
-rw-r--r--rd/Makefile2
-rw-r--r--rd/magick.c85
-rw-r--r--rd/read-bmp.c216
-rw-r--r--rd/read-gif.c220
-rw-r--r--rd/read-jpeg.c187
-rw-r--r--rd/read-pcd.c78
-rw-r--r--rd/read-png.c164
-rw-r--r--rd/read-ppm.c110
-rw-r--r--rd/read-tiff.c195
-rw-r--r--rd/read-xpm.c287
-rw-r--r--rd/read-xwd.c357
11 files changed, 1901 insertions, 0 deletions
diff --git a/rd/Makefile b/rd/Makefile
new file mode 100644
index 0000000..4e33e30
--- /dev/null
+++ b/rd/Makefile
@@ -0,0 +1,2 @@
+default:
+ cd ..; $(MAKE)
diff --git a/rd/magick.c b/rd/magick.c
new file mode 100644
index 0000000..f17e5e3
--- /dev/null
+++ b/rd/magick.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <magick/api.h>
+
+#include "loader.h"
+#include "viewer.h"
+
+extern char *binary;
+
+static int first = 1;
+static ExceptionInfo exception;
+
+struct magick_state {
+ ImageInfo *image_info;
+ Image *image;
+};
+
+static void*
+magick_init(FILE *fp, char *filename, int *width, int *height)
+{
+ struct magick_state *h;
+
+ /* libmagick wants a filename */
+ fclose(fp);
+
+ if (first) {
+ /* init library first time */
+ MagickIncarnate(binary);
+ GetExceptionInfo(&exception);
+ first = 0;
+ }
+
+ h = malloc(sizeof(*h));
+ memset(h,0,sizeof(*h));
+
+ h->image_info=CloneImageInfo(NULL);
+ strcpy(h->image_info->filename,filename);
+ h->image = ReadImage(h->image_info,&exception);
+ if (NULL == h->image) {
+ MagickError(exception.severity,exception.reason,exception.description);
+ goto oops;
+ }
+
+ *width = h->image->rows;
+ *height = h->image->columns;
+ return h;
+
+ oops:
+ if (h->image)
+ DestroyImage(h->image);
+ if (h->image_info)
+ DestroyImageInfo(h->image_info);
+ free(h);
+ return NULL;
+}
+
+static void
+magick_read(unsigned char *dst, int line, void *data)
+{
+ struct magick_state *h = data;
+ DispatchImage (h->image,0,line,h->image->columns, 1,
+ "RGB", 0, data);
+}
+
+static void
+magick_done(void *data)
+{
+ struct magick_state *h = data;
+
+ DestroyImageInfo(h->image_info);
+ DestroyImage(h->image);
+ free(h);
+}
+
+static struct ida_loader magick_loader = {
+ name: "libmagick",
+ init: magick_init,
+ read: magick_read,
+ done: magick_done,
+};
+
+static void __init init_rd(void)
+{
+ load_register(&magick_loader);
+}
diff --git a/rd/read-bmp.c b/rd/read-bmp.c
new file mode 100644
index 0000000..30b5574
--- /dev/null
+++ b/rd/read-bmp.c
@@ -0,0 +1,216 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_ENDIAN_H
+# include <endian.h>
+#endif
+
+#include "readers.h"
+
+/* ---------------------------------------------------------------------- */
+
+typedef unsigned int uint32;
+typedef unsigned short uint16;
+
+/* bitmap files are little endian */
+#if BYTE_ORDER == LITTLE_ENDIAN
+# define le16_to_cpu(x) (x)
+# define le32_to_cpu(x) (x)
+#elif BYTE_ORDER == BIG_ENDIAN
+# define le16_to_cpu(x) (((x>>8) & 0x00ff) |\
+ ((x<<8) & 0xff00))
+# define le32_to_cpu(x) (((x>>24) & 0x000000ff) |\
+ ((x>>8) & 0x0000ff00) |\
+ ((x<<8) & 0x00ff0000) |\
+ ((x<<24) & 0xff000000))
+#else
+# error "Oops: unknown byte order"
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* load */
+
+struct bmp_hdr {
+ uint32 foobar;
+
+ uint32 size; /* == BitMapInfoHeader */
+ uint32 width;
+ uint32 height;
+ uint16 planes;
+ uint16 bit_cnt;
+ char compression[4];
+ uint32 image_size;
+ uint32 xpels_meter;
+ uint32 ypels_meter;
+ uint32 num_colors; /* used colors */
+ uint32 imp_colors; /* important colors */
+ /* may be more for some codecs */
+};
+
+struct bmp_cmap {
+ unsigned char blue;
+ unsigned char green;
+ unsigned char red;
+ unsigned char unused;
+};
+
+struct bmp_state {
+ struct bmp_hdr hdr;
+ struct bmp_cmap cmap[256];
+ FILE *fp;
+};
+
+static void*
+bmp_init(FILE *fp, char *filename, unsigned int page,
+ struct ida_image_info *i, int thumbnail)
+{
+ struct bmp_state *h;
+
+ h = malloc(sizeof(*h));
+ memset(h,0,sizeof(*h));
+ h->fp = fp;
+
+ fseek(fp,10,SEEK_SET);
+ fread(&h->hdr,sizeof(struct bmp_hdr),1,fp);
+
+#if BYTE_ORDER == BIG_ENDIAN
+ h->hdr.foobar = le32_to_cpu(h->hdr.foobar);
+ h->hdr.size = le32_to_cpu(h->hdr.size);
+ h->hdr.width = le32_to_cpu(h->hdr.width);
+ h->hdr.height = le32_to_cpu(h->hdr.height);
+
+ h->hdr.planes = le16_to_cpu(h->hdr.planes);
+ h->hdr.bit_cnt = le16_to_cpu(h->hdr.bit_cnt);
+
+ h->hdr.image_size = le32_to_cpu(h->hdr.image_size);
+ h->hdr.xpels_meter = le32_to_cpu(h->hdr.xpels_meter);
+ h->hdr.ypels_meter = le32_to_cpu(h->hdr.ypels_meter);
+ h->hdr.num_colors = le32_to_cpu(h->hdr.num_colors);
+ h->hdr.imp_colors = le32_to_cpu(h->hdr.imp_colors);
+#endif
+
+ if (debug)
+ fprintf(stderr,"bmp: hdr=%d size=%dx%d planes=%d"
+ " bits=%d size=%d res=%dx%d colors=%d/%d | %d\n",
+ h->hdr.size,h->hdr.width,h->hdr.height,
+ h->hdr.planes,h->hdr.bit_cnt,h->hdr.image_size,
+ h->hdr.xpels_meter,h->hdr.ypels_meter,
+ h->hdr.num_colors,h->hdr.imp_colors,h->hdr.foobar);
+ if (h->hdr.bit_cnt != 1 &&
+ h->hdr.bit_cnt != 4 &&
+ h->hdr.bit_cnt != 8 &&
+ h->hdr.bit_cnt != 24) {
+ fprintf(stderr,"bmp: can't handle depth [%d]\n",h->hdr.bit_cnt);
+ goto oops;
+ }
+ if (h->hdr.compression[0] || h->hdr.compression[1] ||
+ h->hdr.compression[2] || h->hdr.compression[3]) {
+ fprintf(stderr,"bmp: can't handle compressed bitmaps [%c%c%c%c]\n",
+ h->hdr.compression[0],
+ h->hdr.compression[1],
+ h->hdr.compression[2],
+ h->hdr.compression[3]);
+ goto oops;
+ }
+
+ if (0 == h->hdr.num_colors && h->hdr.bit_cnt <= 8)
+ h->hdr.num_colors = (1 << h->hdr.bit_cnt);
+ if (h->hdr.num_colors > 256)
+ h->hdr.num_colors = 256;
+ if (h->hdr.num_colors) {
+ fseek(fp,14+h->hdr.size,SEEK_SET);
+ fread(&h->cmap,sizeof(struct bmp_cmap),h->hdr.num_colors,fp);
+ }
+
+ i->width = h->hdr.width;
+ i->height = h->hdr.height;
+ if (h->hdr.xpels_meter)
+ i->dpi = res_m_to_inch(h->hdr.xpels_meter);
+ i->npages = 1;
+ return h;
+
+ oops:
+ free(h);
+ return NULL;
+}
+
+static void
+bmp_read(unsigned char *dst, unsigned int line, void *data)
+{
+ struct bmp_state *h = data;
+ unsigned int ll,y,x,pixel,byte = 0;
+
+ ll = (((h->hdr.width * h->hdr.bit_cnt + 31) & ~0x1f) >> 3);
+ y = h->hdr.height - line - 1;
+ fseek(h->fp,h->hdr.foobar + y * ll,SEEK_SET);
+
+ switch (h->hdr.bit_cnt) {
+ case 1:
+ for (x = 0; x < h->hdr.width; x++) {
+ if (0 == (x & 0x07))
+ byte = fgetc(h->fp);
+ pixel = byte & (0x80 >> (x & 0x07)) ? 1 : 0;
+ *(dst++) = h->cmap[pixel].red;
+ *(dst++) = h->cmap[pixel].green;
+ *(dst++) = h->cmap[pixel].blue;
+ }
+ break;
+ case 4:
+ for (x = 0; x < h->hdr.width; x++) {
+ if (x & 1) {
+ pixel = byte & 0xf;
+ } else {
+ byte = fgetc(h->fp);
+ pixel = byte >> 4;
+ }
+ *(dst++) = h->cmap[pixel].red;
+ *(dst++) = h->cmap[pixel].green;
+ *(dst++) = h->cmap[pixel].blue;
+ }
+ break;
+ case 8:
+ for (x = 0; x < h->hdr.width; x++) {
+ pixel = fgetc(h->fp);
+ *(dst++) = h->cmap[pixel].red;
+ *(dst++) = h->cmap[pixel].green;
+ *(dst++) = h->cmap[pixel].blue;
+ }
+ break;
+ case 24:
+ for (x = 0; x < h->hdr.width; x++) {
+ dst[2] = fgetc(h->fp);
+ dst[1] = fgetc(h->fp);
+ dst[0] = fgetc(h->fp);
+ dst += 3;
+ }
+ break;
+ default:
+ memset(dst,128,h->hdr.width*3);
+ break;
+ }
+}
+
+static void
+bmp_done(void *data)
+{
+ struct bmp_state *h = data;
+
+ fclose(h->fp);
+ free(h);
+}
+
+static struct ida_loader bmp_loader = {
+ magic: "BM",
+ moff: 0,
+ mlen: 2,
+ name: "bmp",
+ init: bmp_init,
+ read: bmp_read,
+ done: bmp_done,
+};
+
+static void __init init_rd(void)
+{
+ load_register(&bmp_loader);
+}
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);
+}
diff --git a/rd/read-jpeg.c b/rd/read-jpeg.c
new file mode 100644
index 0000000..d12fb40
--- /dev/null
+++ b/rd/read-jpeg.c
@@ -0,0 +1,187 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <jpeglib.h>
+
+#include <libexif/exif-data.h>
+
+#include "readers.h"
+#include "misc.h"
+
+/* ---------------------------------------------------------------------- */
+/* load */
+
+struct jpeg_state {
+ FILE * infile; /* source file */
+
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ JSAMPARRAY buffer; /* Output row buffer */
+ int row_stride,linelength; /* physical row width in output buffer */
+ unsigned char *image,*ptr;
+
+ /* thumbnail */
+ unsigned char *thumbnail;
+ unsigned int tpos, tsize;
+};
+
+/* ---------------------------------------------------------------------- */
+/* data source manager for thumbnail images */
+
+static void thumbnail_src_init(struct jpeg_decompress_struct *cinfo)
+{
+ struct jpeg_state *h = container_of(cinfo, struct jpeg_state, cinfo);
+ cinfo->src->next_input_byte = h->thumbnail;
+ cinfo->src->bytes_in_buffer = h->tsize;
+}
+
+static int thumbnail_src_fill(struct jpeg_decompress_struct *cinfo)
+{
+ fprintf(stderr,"jpeg: panic: no more thumbnail input data\n");
+ exit(1);
+}
+
+static void thumbnail_src_skip(struct jpeg_decompress_struct *cinfo,
+ long num_bytes)
+{
+ cinfo->src->next_input_byte += num_bytes;
+}
+
+static void thumbnail_src_term(struct jpeg_decompress_struct *cinfo)
+{
+ /* nothing */
+}
+
+static struct jpeg_source_mgr thumbnail_mgr = {
+ .init_source = thumbnail_src_init,
+ .fill_input_buffer = thumbnail_src_fill,
+ .skip_input_data = thumbnail_src_skip,
+ .resync_to_restart = jpeg_resync_to_restart,
+ .term_source = thumbnail_src_term,
+};
+
+/* ---------------------------------------------------------------------- */
+/* jpeg loader */
+
+static void*
+jpeg_init(FILE *fp, char *filename, unsigned int page,
+ struct ida_image_info *i, int thumbnail)
+{
+ struct jpeg_state *h;
+ jpeg_saved_marker_ptr mark;
+
+ h = malloc(sizeof(*h));
+ memset(h,0,sizeof(*h));
+ h->infile = fp;
+
+ h->cinfo.err = jpeg_std_error(&h->jerr);
+ jpeg_create_decompress(&h->cinfo);
+ jpeg_save_markers(&h->cinfo, JPEG_COM, 0xffff); /* comment */
+ jpeg_save_markers(&h->cinfo, JPEG_APP0+1, 0xffff); /* EXIF */
+ jpeg_stdio_src(&h->cinfo, h->infile);
+ jpeg_read_header(&h->cinfo, TRUE);
+
+ for (mark = h->cinfo.marker_list; NULL != mark; mark = mark->next) {
+ switch (mark->marker) {
+ case JPEG_COM:
+ if (debug)
+ fprintf(stderr,"jpeg: comment found (COM marker) [%.*s]\n",
+ (int)mark->data_length, mark->data);
+ load_add_extra(i,EXTRA_COMMENT,mark->data,mark->data_length);
+ break;
+ case JPEG_APP0 +1:
+ if (debug)
+ fprintf(stderr,"jpeg: exif data found (APP1 marker)\n");
+ load_add_extra(i,EXTRA_COMMENT,mark->data,mark->data_length);
+
+ if (thumbnail) {
+ ExifData *ed;
+
+ ed = exif_data_new_from_data(mark->data,mark->data_length);
+ if (ed->data &&
+ ed->data[0] == 0xff &&
+ ed->data[1] == 0xd8) {
+ if (debug)
+ fprintf(stderr,"jpeg: exif thumbnail found\n");
+
+ /* save away thumbnail data */
+ h->thumbnail = malloc(ed->size);
+ h->tsize = ed->size;
+ memcpy(h->thumbnail,ed->data,ed->size);
+ }
+ exif_data_unref(ed);
+ }
+ break;
+ }
+ }
+
+ if (h->thumbnail) {
+ /* save image size */
+ i->thumbnail = 1;
+ i->real_width = h->cinfo.image_width;
+ i->real_height = h->cinfo.image_height;
+
+ /* re-setup jpeg */
+ jpeg_destroy_decompress(&h->cinfo);
+ fclose(h->infile);
+ h->infile = NULL;
+ jpeg_create_decompress(&h->cinfo);
+ h->cinfo.src = &thumbnail_mgr;
+ jpeg_read_header(&h->cinfo, TRUE);
+ }
+
+ h->cinfo.out_color_space = JCS_RGB;
+ jpeg_start_decompress(&h->cinfo);
+ i->width = h->cinfo.image_width;
+ i->height = h->cinfo.image_height;
+ i->npages = 1;
+ switch (h->cinfo.density_unit) {
+ case 0: /* unknown */
+ break;
+ case 1: /* dot per inch */
+ i->dpi = h->cinfo.X_density;
+ break;
+ case 2: /* dot per cm */
+ i->dpi = res_cm_to_inch(h->cinfo.X_density);
+ break;
+ }
+
+ return h;
+}
+
+static void
+jpeg_read(unsigned char *dst, unsigned int line, void *data)
+{
+ struct jpeg_state *h = data;
+ JSAMPROW row = dst;
+ jpeg_read_scanlines(&h->cinfo, &row, 1);
+}
+
+static void
+jpeg_done(void *data)
+{
+ struct jpeg_state *h = data;
+ jpeg_destroy_decompress(&h->cinfo);
+ if (h->infile)
+ fclose(h->infile);
+ if (h->thumbnail)
+ free(h->thumbnail);
+ free(h);
+}
+
+struct ida_loader jpeg_loader = {
+ magic: "\xff\xd8",
+ moff: 0,
+ mlen: 2,
+ name: "libjpeg",
+ init: jpeg_init,
+ read: jpeg_read,
+ done: jpeg_done,
+};
+
+static void __init init_rd(void)
+{
+ load_register(&jpeg_loader);
+}
diff --git a/rd/read-pcd.c b/rd/read-pcd.c
new file mode 100644
index 0000000..40c43d5
--- /dev/null
+++ b/rd/read-pcd.c
@@ -0,0 +1,78 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "pcd.h"
+
+#include "readers.h"
+
+extern int pcd_res;
+
+/* ---------------------------------------------------------------------- */
+/* load */
+
+struct pcd_state {
+ struct PCD_IMAGE img;
+ int left,top,width,height;
+};
+
+static void*
+pcd_init(FILE *fp, char *filename, unsigned int page,
+ struct ida_image_info *i, int thumbnail)
+{
+ struct pcd_state *h;
+
+ fclose(fp);
+ h = malloc(sizeof(*h));
+ memset(h,0,sizeof(*h));
+
+ if (0 != pcd_open(&h->img, filename))
+ goto oops;
+ if (-1 == pcd_select(&h->img, thumbnail ? 1 : pcd_res,
+ 0,0,0, pcd_get_rot(&h->img, 0),
+ &h->left, &h->top, &h->width, &h->height))
+ goto oops;
+ if (-1 == pcd_decode(&h->img))
+ goto oops;
+
+ i->width = h->width;
+ i->height = h->height;
+ i->npages = 1;
+ return h;
+
+ oops:
+ free(h);
+ return NULL;
+}
+
+static void
+pcd_read(unsigned char *dst, unsigned int line, void *data)
+{
+ struct pcd_state *h = data;
+
+ pcd_get_image_line(&h->img, line, dst, PCD_TYPE_RGB, 0);
+}
+
+static void
+pcd_done(void *data)
+{
+ struct pcd_state *h = data;
+
+ pcd_close(&h->img);
+ free(h);
+}
+
+static struct ida_loader pcd_loader = {
+ magic: "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
+ moff: 0,
+ mlen: 16,
+ name: "libpcd",
+ init: pcd_init,
+ read: pcd_read,
+ done: pcd_done,
+};
+
+static void __init init_rd(void)
+{
+ load_register(&pcd_loader);
+}
diff --git a/rd/read-png.c b/rd/read-png.c
new file mode 100644
index 0000000..c4f82d2
--- /dev/null
+++ b/rd/read-png.c
@@ -0,0 +1,164 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <png.h>
+
+#include "readers.h"
+
+static const char *ct[] = {
+ "gray", "X1", "rgb", "palette",
+ "graya", "X5", "rgba", "X7",
+};
+
+struct png_state {
+ FILE *infile;
+ png_structp png;
+ png_infop info;
+ png_bytep image;
+ png_uint_32 w,h;
+ int color_type;
+};
+
+static void*
+png_init(FILE *fp, char *filename, unsigned int page,
+ struct ida_image_info *i, int thumbnail)
+{
+ struct png_state *h;
+ int bit_depth, interlace_type;
+ int pass, number_passes;
+ unsigned int y;
+ png_uint_32 resx, resy;
+ png_color_16 *file_bg, my_bg = {
+ .red = 192,
+ .green = 192,
+ .blue = 192,
+ .gray = 192,
+ };
+ int unit;
+
+ h = malloc(sizeof(*h));
+ memset(h,0,sizeof(*h));
+
+ h->infile = fp;
+
+ h->png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+ NULL, NULL, NULL);
+ if (NULL == h->png)
+ goto oops;
+ h->info = png_create_info_struct(h->png);
+ if (NULL == h->info)
+ goto oops;
+
+ png_init_io(h->png, h->infile);
+ png_read_info(h->png, h->info);
+ png_get_IHDR(h->png, h->info, &h->w, &h->h,
+ &bit_depth,&h->color_type,&interlace_type, NULL,NULL);
+ png_get_pHYs(h->png, h->info, &resx, &resy, &unit);
+ i->width = h->w;
+ i->height = h->h;
+ if (PNG_RESOLUTION_METER == unit)
+ i->dpi = res_m_to_inch(resx);
+ if (debug)
+ fprintf(stderr,"png: color_type=%s #1\n",ct[h->color_type]);
+ i->npages = 1;
+
+ png_set_packing(h->png);
+ if (bit_depth == 16)
+ png_set_strip_16(h->png);
+ if (h->color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_palette_to_rgb(h->png);
+ if (h->color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+ png_set_gray_1_2_4_to_8(h->png);
+
+ if (png_get_bKGD(h->png, h->info, &file_bg)) {
+ png_set_background(h->png,file_bg,PNG_BACKGROUND_GAMMA_FILE,1,1.0);
+ } else {
+ png_set_background(h->png,&my_bg,PNG_BACKGROUND_GAMMA_SCREEN,0,1.0);
+ }
+
+ number_passes = png_set_interlace_handling(h->png);
+ png_read_update_info(h->png, h->info);
+
+ h->color_type = png_get_color_type(h->png, h->info);
+ if (debug)
+ fprintf(stderr,"png: color_type=%s #2\n",ct[h->color_type]);
+
+ h->image = malloc(i->width * i->height * 4);
+
+ for (pass = 0; pass < number_passes-1; pass++) {
+ if (debug)
+ fprintf(stderr,"png: pass #%d\n",pass);
+ for (y = 0; y < i->height; y++) {
+ png_bytep row = h->image + y * i->width * 4;
+ png_read_rows(h->png, &row, NULL, 1);
+ }
+ }
+
+ return h;
+
+ oops:
+ if (h->image)
+ free(h->image);
+ if (h->png)
+ png_destroy_read_struct(&h->png, NULL, NULL);
+ fclose(h->infile);
+ free(h);
+ return NULL;
+}
+
+static void
+png_read(unsigned char *dst, unsigned int line, void *data)
+{
+ struct png_state *h = data;
+
+ png_bytep row = h->image + line * h->w * 4;
+ switch (h->color_type) {
+ case PNG_COLOR_TYPE_GRAY:
+ png_read_rows(h->png, &row, NULL, 1);
+ load_gray(dst,row,h->w);
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ png_read_rows(h->png, &row, NULL, 1);
+ memcpy(dst,row,3*h->w);
+ break;
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ png_read_rows(h->png, &row, NULL, 1);
+ load_rgba(dst,row,h->w);
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ png_read_rows(h->png, &row, NULL, 1);
+ load_graya(dst,row,h->w);
+ break;
+ default:
+ /* shouldn't happen */
+ fprintf(stderr,"Oops: %s:%d\n",__FILE__,__LINE__);
+ exit(1);
+ }
+}
+
+static void
+png_done(void *data)
+{
+ struct png_state *h = data;
+
+ free(h->image);
+ png_destroy_read_struct(&h->png, &h->info, NULL);
+ fclose(h->infile);
+ free(h);
+}
+
+static struct ida_loader png_loader = {
+ magic: "\x89PNG",
+ moff: 0,
+ mlen: 4,
+ name: "libpng",
+ init: png_init,
+ read: png_read,
+ done: png_done,
+};
+
+static void __init init_rd(void)
+{
+ load_register(&png_loader);
+}
diff --git a/rd/read-ppm.c b/rd/read-ppm.c
new file mode 100644
index 0000000..b7eb326
--- /dev/null
+++ b/rd/read-ppm.c
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "readers.h"
+
+/* ---------------------------------------------------------------------- */
+/* load */
+
+struct ppm_state {
+ FILE *infile;
+ int width,height;
+ unsigned char *row;
+};
+
+static void*
+pnm_init(FILE *fp, char *filename, unsigned int page,
+ struct ida_image_info *i, int thumbnail)
+{
+ struct ppm_state *h;
+ char line[1024];
+
+ h = malloc(sizeof(*h));
+ memset(h,0,sizeof(*h));
+
+ h->infile = fp;
+ fgets(line,sizeof(line),fp); /* Px */
+ fgets(line,sizeof(line),fp); /* width height */
+ while ('#' == line[0])
+ fgets(line,sizeof(line),fp); /* skip comments */
+ sscanf(line,"%d %d",&h->width,&h->height);
+ fgets(line,sizeof(line),fp); /* ??? */
+ if (0 == h->width || 0 == h->height)
+ goto oops;
+ i->width = h->width;
+ i->height = h->height;
+ i->npages = 1;
+ h->row = malloc(h->width*3);
+
+ return h;
+
+ oops:
+ fclose(fp);
+ free(h);
+ return NULL;
+}
+
+static void
+ppm_read(unsigned char *dst, unsigned int line, void *data)
+{
+ struct ppm_state *h = data;
+
+ fread(dst,h->width,3,h->infile);
+}
+
+static void
+pgm_read(unsigned char *dst, unsigned int line, void *data)
+{
+ struct ppm_state *h = data;
+ unsigned char *src;
+ int x;
+
+ fread(h->row,h->width,1,h->infile);
+ src = h->row;
+ for (x = 0; x < h->width; x++) {
+ dst[0] = src[0];
+ dst[1] = src[0];
+ dst[2] = src[0];
+ dst += 3;
+ src += 1;
+ }
+}
+
+static void
+pnm_done(void *data)
+{
+ struct ppm_state *h = data;
+
+ fclose(h->infile);
+ free(h->row);
+ free(h);
+}
+
+struct ida_loader ppm_loader = {
+ magic: "P6",
+ moff: 0,
+ mlen: 2,
+ name: "ppm parser",
+ init: pnm_init,
+ read: ppm_read,
+ done: pnm_done,
+};
+
+static struct ida_loader pgm_loader = {
+ magic: "P5",
+ moff: 0,
+ mlen: 2,
+ name: "pgm parser",
+ init: pnm_init,
+ read: pgm_read,
+ done: pnm_done,
+};
+
+static void __init init_rd(void)
+{
+ load_register(&ppm_loader);
+ load_register(&pgm_loader);
+}
+
diff --git a/rd/read-tiff.c b/rd/read-tiff.c
new file mode 100644
index 0000000..3f75b83
--- /dev/null
+++ b/rd/read-tiff.c
@@ -0,0 +1,195 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <tiffio.h>
+
+#include "readers.h"
+
+struct tiff_state {
+ TIFF* tif;
+ char emsg[1024];
+ tdir_t ndirs; /* Number of directories */
+ /* (could be interpreted as number of pages) */
+ uint32 width,height;
+ uint16 config,nsamples,depth,fillorder,photometric;
+ uint32* row;
+ uint32* image;
+ uint16 resunit;
+ float xres,yres;
+};
+
+static void*
+tiff_init(FILE *fp, char *filename, unsigned int page,
+ struct ida_image_info *i, int thumbnail)
+{
+ struct tiff_state *h;
+
+ fclose(fp);
+ h = malloc(sizeof(*h));
+ memset(h,0,sizeof(*h));
+
+ TIFFSetWarningHandler(NULL);
+ h->tif = TIFFOpen(filename,"r");
+ if (NULL == h->tif)
+ goto oops;
+ /* Determine number of directories */
+ h->ndirs = 1;
+ while (TIFFReadDirectory(h->tif))
+ h->ndirs++;
+ i->npages = h->ndirs;
+ /* Select requested directory (page) */
+ if (!TIFFSetDirectory(h->tif, (tdir_t)page))
+ goto oops;
+
+ TIFFGetField(h->tif, TIFFTAG_IMAGEWIDTH, &h->width);
+ TIFFGetField(h->tif, TIFFTAG_IMAGELENGTH, &h->height);
+ TIFFGetField(h->tif, TIFFTAG_PLANARCONFIG, &h->config);
+ TIFFGetField(h->tif, TIFFTAG_SAMPLESPERPIXEL, &h->nsamples);
+ TIFFGetField(h->tif, TIFFTAG_BITSPERSAMPLE, &h->depth);
+ TIFFGetField(h->tif, TIFFTAG_FILLORDER, &h->fillorder);
+ TIFFGetField(h->tif, TIFFTAG_PHOTOMETRIC, &h->photometric);
+ h->row = malloc(TIFFScanlineSize(h->tif));
+ if (debug)
+ fprintf(stderr,"tiff: %" PRId32 "x%" PRId32 ", planar=%d, "
+ "nsamples=%d, depth=%d fo=%d pm=%d scanline=%" PRId32 "\n",
+ h->width,h->height,h->config,h->nsamples,h->depth,
+ h->fillorder,h->photometric,
+ TIFFScanlineSize(h->tif));
+
+ if (PHOTOMETRIC_PALETTE == h->photometric ||
+ PHOTOMETRIC_YCBCR == h->photometric ||
+ PHOTOMETRIC_SEPARATED == h->photometric ||
+ TIFFIsTiled(h->tif) ||
+ (1 != h->depth && 8 != h->depth)) {
+ /* for the more difficuilt cases we let libtiff
+ * do all the hard work. Drawback is that we lose
+ * progressive loading and decode everything here */
+ if (debug)
+ fprintf(stderr,"tiff: reading whole image [TIFFReadRGBAImage]\n");
+ h->image=malloc(4*h->width*h->height);
+ TIFFReadRGBAImage(h->tif, h->width, h->height, h->image, 0);
+ } else {
+ if (debug)
+ fprintf(stderr,"tiff: reading scanline by scanline\n");
+ h->row = malloc(TIFFScanlineSize(h->tif));
+ }
+
+ i->width = h->width;
+ i->height = h->height;
+
+ if (TIFFGetField(h->tif, TIFFTAG_RESOLUTIONUNIT, &h->resunit) &&
+ TIFFGetField(h->tif, TIFFTAG_XRESOLUTION, &h->xres) &&
+ TIFFGetField(h->tif, TIFFTAG_YRESOLUTION, &h->yres)) {
+ switch (h->resunit) {
+ case RESUNIT_NONE:
+ break;
+ case RESUNIT_INCH:
+ i->dpi = h->xres;
+ break;
+ case RESUNIT_CENTIMETER:
+ i->dpi = res_cm_to_inch(h->xres);
+ break;
+ }
+ }
+
+ return h;
+
+ oops:
+ if (h->tif)
+ TIFFClose(h->tif);
+ free(h);
+ return NULL;
+}
+
+static void
+tiff_read(unsigned char *dst, unsigned int line, void *data)
+{
+ struct tiff_state *h = data;
+ int s,on,off;
+
+ if (h->image) {
+ /* loaded whole image using TIFFReadRGBAImage() */
+ uint32 *row = h->image + h->width * (h->height - line -1);
+ load_rgba(dst,(unsigned char*)row,h->width);
+ return;
+ }
+
+ if (h->config == PLANARCONFIG_CONTIG) {
+ TIFFReadScanline(h->tif, h->row, line, 0);
+ } else if (h->config == PLANARCONFIG_SEPARATE) {
+ for (s = 0; s < h->nsamples; s++)
+ TIFFReadScanline(h->tif, h->row, line, s);
+ }
+
+ switch (h->nsamples) {
+ case 1:
+ if (1 == h->depth) {
+ /* black/white */
+ on = 0, off = 0;
+ if (PHOTOMETRIC_MINISWHITE == h->photometric)
+ on = 0, off = 255;
+ if (PHOTOMETRIC_MINISBLACK == h->photometric)
+ on = 255, off = 0;
+#if 0
+ /* Huh? Does TIFFReadScanline handle this already ??? */
+ if (FILLORDER_MSB2LSB == h->fillorder)
+ load_bits_msb(dst,(unsigned char*)(h->row),h->width,on,off);
+ else
+ load_bits_lsb(dst,(unsigned char*)(h->row),h->width,on,off);
+#else
+ load_bits_msb(dst,(unsigned char*)(h->row),h->width,on,off);
+#endif
+ } else {
+ /* grayscaled */
+ load_gray(dst,(unsigned char*)(h->row),h->width);
+ }
+ break;
+ case 3:
+ /* rgb */
+ memcpy(dst,h->row,3*h->width);
+ break;
+ case 4:
+ /* rgb+alpha */
+ load_rgba(dst,(unsigned char*)(h->row),h->width);
+ break;
+ }
+}
+
+static void
+tiff_done(void *data)
+{
+ struct tiff_state *h = data;
+
+ TIFFClose(h->tif);
+ if (h->row)
+ free(h->row);
+ if (h->image)
+ free(h->image);
+ free(h);
+}
+
+static struct ida_loader tiff1_loader = {
+ magic: "MM\x00\x2a",
+ moff: 0,
+ mlen: 4,
+ name: "libtiff",
+ init: tiff_init,
+ read: tiff_read,
+ done: tiff_done,
+};
+static struct ida_loader tiff2_loader = {
+ magic: "II\x2a\x00",
+ moff: 0,
+ mlen: 4,
+ name: "libtiff",
+ init: tiff_init,
+ read: tiff_read,
+ done: tiff_done,
+};
+
+static void __init init_rd(void)
+{
+ load_register(&tiff1_loader);
+ load_register(&tiff2_loader);
+}
diff --git a/rd/read-xpm.c b/rd/read-xpm.c
new file mode 100644
index 0000000..affdce6
--- /dev/null
+++ b/rd/read-xpm.c
@@ -0,0 +1,287 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <X11/Xlib.h>
+#include <X11/Intrinsic.h>
+
+#include "ida.h"
+
+#include "readers.h"
+#include "viewer.h"
+
+/* ---------------------------------------------------------------------- */
+/* load */
+
+struct xpm_color {
+ char name[8];
+ XColor color;
+};
+
+struct xpm_state {
+ FILE *infile;
+ int width,height,colors,chars;
+ struct xpm_color *cmap;
+ char *charline;
+ char *rgbrow;
+};
+
+static void*
+xpm_init(FILE *fp, char *filename, unsigned int page,
+ struct ida_image_info *info, int thumbnail)
+{
+ struct xpm_state *h;
+ char line[1024],cname[32],*tmp;
+ XColor dummy;
+ int i;
+ Colormap cmap = DefaultColormapOfScreen(XtScreen(app_shell));
+
+ h = malloc(sizeof(*h));
+ memset(h,0,sizeof(*h));
+ h->infile = fp;
+
+ fgets(line,sizeof(line)-1,fp); /* XPM */
+ fgets(line,sizeof(line)-1,fp); /* static char ... */
+ while (0 == strncmp(line,"/*",2)) {
+ while (NULL == strstr(line,"*/"))
+ fgets(line,sizeof(line)-1,fp);
+ fgets(line,sizeof(line)-1,fp);
+ }
+
+ /* size, colors */
+ fgets(line,sizeof(line)-1,fp);
+ if (0 == strncmp(line,"/*",2)) {
+ while (NULL == strstr(line,"*/"))
+ fgets(line,sizeof(line)-1,fp);
+ fgets(line,sizeof(line)-1,fp);
+ }
+ if (4 != sscanf(line,"\"%d %d %d %d",
+ &h->width,&h->height,&h->colors,&h->chars))
+ goto oops;
+ if (h->chars > 7)
+ goto oops;
+
+ /* read color table */
+ h->cmap = malloc(h->colors * sizeof(struct xpm_color));
+ memset(h->cmap,0,h->colors * sizeof(struct xpm_color));
+ for (i = 0; i < h->colors; i++) {
+ fgets(line,sizeof(line)-1,fp);
+ while (0 == strncmp(line,"/*",2)) {
+ while (NULL == strstr(line,"*/"))
+ fgets(line,sizeof(line)-1,fp);
+ fgets(line,sizeof(line)-1,fp);
+ }
+ memcpy(h->cmap[i].name,line+1,h->chars);
+
+ if (NULL != (tmp = strstr(line+1+h->chars,"c "))) {
+ /* color */
+ sscanf(tmp+2,"%32[^\" ]",cname);
+ } else if (NULL != (tmp = strstr(line+h->chars,"m "))) {
+ /* mono */
+ sscanf(tmp+2,"%32[^\" ]",cname);
+ } else if (NULL != (tmp = strstr(line+h->chars,"g "))) {
+ /* gray? */
+ sscanf(tmp+2,"%32[^\" ]",cname);
+ } else
+ goto oops;
+ if (0 == strcasecmp(cname,"none"))
+ /* transparent */
+ strcpy(cname,"lightgray");
+ if (debug)
+ fprintf(stderr,"xpm: cmap: \"%*.*s\" => %s\n",
+ h->chars,h->chars,h->cmap[i].name,cname);
+#if 0
+ if (1 != sscanf(line+1+h->chars," c %32[^\"]",cname))
+ goto oops;
+#endif
+ XLookupColor(dpy,cmap,cname,&h->cmap[i].color,&dummy);
+ }
+ h->charline = malloc(h->width * h->chars + 8);
+ h->rgbrow = malloc(h->width * 3);
+
+ info->width = h->width;
+ info->height = h->height;
+ info->npages = 1;
+ return h;
+
+ oops:
+ fclose(fp);
+ free(h);
+ return NULL;
+}
+
+static void
+xpm_read(unsigned char *dst, unsigned int line, void *data)
+{
+ struct xpm_state *h = data;
+ char *src;
+ int i,c;
+
+ fgets(h->charline,h->width * h->chars + 8,h->infile);
+ while (0 == strncmp(h->charline,"/*",2)) {
+ while (NULL == strstr(h->charline,"*/"))
+ fgets(h->charline,h->width * h->chars + 8,h->infile);
+ fgets(h->charline,h->width * h->chars + 8,h->infile);
+ }
+ src = h->charline+1;
+ for (i = 0; i < h->width; i++) {
+ for (c = 0; c < h->colors; c++) {
+ char *name = h->cmap[c].name;
+ if (src[0] != name[0])
+ continue;
+ if (1 == h->chars)
+ break;
+ if (src[1] != name[1])
+ continue;
+ if (2 == h->chars)
+ break;
+ if (0 == strncmp(src+2,name+2,h->chars-2))
+ break;
+ }
+ if (c == h->colors)
+ continue;
+ dst[0] = h->cmap[c].color.red >> 8;
+ dst[1] = h->cmap[c].color.green >> 8;
+ dst[2] = h->cmap[c].color.blue >> 8;
+ src += h->chars;
+ dst += 3;
+ }
+}
+
+static void
+xpm_done(void *data)
+{
+ struct xpm_state *h = data;
+
+ fclose(h->infile);
+ free(h->charline);
+ free(h->rgbrow);
+ free(h->cmap);
+ free(h);
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct xbm_state {
+ FILE *infile;
+ int width,height;
+};
+
+static void*
+xbm_init(FILE *fp, char *filename, unsigned int page,
+ struct ida_image_info *info, int thumbnail)
+{
+ struct xbm_state *h;
+ char line[256],dummy[128];
+ int i;
+
+ h = malloc(sizeof(*h));
+ memset(h,0,sizeof(*h));
+ h->infile = fp;
+
+ for (i = 0; i < 128; i++) {
+ fgets(line,sizeof(line)-1,fp);
+ if (0 == strncmp(line,"#define",7))
+ break;
+ }
+ if (128 == i)
+ goto oops;
+
+ if (2 != sscanf(line,"#define %127s %d",dummy,&h->width))
+ goto oops;
+ fgets(line,sizeof(line)-1,fp);
+ if (2 != sscanf(line,"#define %127s %d",dummy,&h->height))
+ goto oops;
+ if (debug)
+ fprintf(stderr,"xbm: %dx%d\n",h->width,h->height);
+
+ for (i = 0; i < 4; i++) {
+ fgets(line,sizeof(line)-1,fp);
+ if (strstr(line,"[] = {"))
+ break;
+ }
+ if (4 == i)
+ goto oops;
+
+ info->width = h->width;
+ info->height = h->height;
+ info->npages = 1;
+ return h;
+
+ oops:
+ if (debug)
+ fprintf(stderr,"xbm: %s",line);
+ fclose(fp);
+ free(h);
+ return NULL;
+}
+
+static void
+xbm_read(unsigned char *dst, unsigned int line, void *data)
+{
+ struct xbm_state *h = data;
+ int x,val;
+
+ for (x = 0; x < h->width; x++) {
+ if (0 == (x % 8))
+ fscanf(h->infile," 0x%x,",&val);
+ if (val & (1 << (x % 8))) {
+ *(dst++) = 0;
+ *(dst++) = 0;
+ *(dst++) = 0;
+ } else {
+ *(dst++) = 255;
+ *(dst++) = 255;
+ *(dst++) = 255;
+ }
+ }
+}
+
+static void
+xbm_done(void *data)
+{
+ struct xpm_state *h = data;
+
+ fclose(h->infile);
+ free(h);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static struct ida_loader xpm_loader = {
+ magic: "/* XPM */",
+ moff: 0,
+ mlen: 9,
+ name: "xpm parser",
+ init: xpm_init,
+ read: xpm_read,
+ done: xpm_done,
+};
+
+static struct ida_loader xbm1_loader = {
+ magic: "#define",
+ moff: 0,
+ mlen: 7,
+ name: "xbm parser",
+ init: xbm_init,
+ read: xbm_read,
+ done: xbm_done,
+};
+
+static struct ida_loader xbm2_loader = {
+ magic: "/*",
+ moff: 0,
+ mlen: 2,
+ name: "xbm parser",
+ init: xbm_init,
+ read: xbm_read,
+ done: xbm_done,
+};
+
+static void __init init_rd(void)
+{
+ load_register(&xpm_loader);
+ load_register(&xbm1_loader);
+ load_register(&xbm2_loader);
+}
diff --git a/rd/read-xwd.c b/rd/read-xwd.c
new file mode 100644
index 0000000..8d15cf3
--- /dev/null
+++ b/rd/read-xwd.c
@@ -0,0 +1,357 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/XWDFile.h>
+#ifdef HAVE_ENDIAN_H
+# include <endian.h>
+#endif
+
+#include "readers.h"
+#include "viewer.h"
+#include "xwd.h"
+#include "x11.h"
+#include "ida.h"
+
+/* xwd files are big endian */
+#if BYTE_ORDER == BIG_ENDIAN
+# define be16_to_cpu(x) (x)
+# define be32_to_cpu(x) (x)
+#elif BYTE_ORDER == LITTLE_ENDIAN
+# define be16_to_cpu(x) (((x>>8) & 0x00ff) |\
+ ((x<<8) & 0xff00))
+# define be32_to_cpu(x) (((x>>24) & 0x000000ff) |\
+ ((x>>8) & 0x0000ff00) |\
+ ((x<<8) & 0x00ff0000) |\
+ ((x<<24) & 0xff000000))
+#else
+# error "Oops: unknown byte order"
+#endif
+
+static char *vclass[] = {
+ "StaticGray",
+ "GrayScale",
+ "StaticColor",
+ "PseudoColor",
+ "TrueColor",
+ "DirectColor",
+};
+static char *order[] = {
+ "LSBFirst",
+ "MSBFirst",
+};
+static char *fmt[] = {
+ "XYBitmap",
+ "XYPixmap",
+ "ZPixmap",
+};
+
+/* ----------------------------------------------------------------------- */
+
+struct xwd_state {
+ FILE *infile;
+ XWDFileHeader header;
+ XWDColor cmap[256];
+ int width,bpp;
+ unsigned char *row;
+ unsigned long *pix;
+ unsigned long r_mask,g_mask,b_mask;
+ int r_shift,g_shift,b_shift;
+ int r_bits,g_bits,b_bits;
+};
+
+static void
+xwd_map(struct xwd_state *h)
+{
+ int i;
+ unsigned long mask;
+
+ h->r_mask = be32_to_cpu(h->header.red_mask);
+ h->g_mask = be32_to_cpu(h->header.green_mask);
+ h->b_mask = be32_to_cpu(h->header.blue_mask);
+ for (i = 0; i < 32; i++) {
+ mask = (1 << i);
+ if (h->r_mask & mask)
+ h->r_bits++;
+ else if (!h->r_bits)
+ h->r_shift++;
+ if (h->g_mask & mask)
+ h->g_bits++;
+ else if (!h->g_bits)
+ h->g_shift++;
+ if (h->b_mask & mask)
+ h->b_bits++;
+ else if (!h->b_bits)
+ h->b_shift++;
+ }
+ h->r_shift -= (8 - h->r_bits);
+ h->g_shift -= (8 - h->g_bits);
+ h->b_shift -= (8 - h->b_bits);
+#if 0
+ fprintf(stderr,"xwd: color: bits shift\n");
+ fprintf(stderr,"xwd: red : %04i %05i\n", h->r_bits, h->r_shift);
+ fprintf(stderr,"xwd: green: %04i %05i\n", h->g_bits, h->g_shift);
+ fprintf(stderr,"xwd: blue : %04i %05i\n", h->b_bits, h->b_shift);
+#endif
+}
+
+
+static void*
+xwd_init(FILE *fp, char *filename, unsigned int page,
+ struct ida_image_info *i, int thumbnail)
+{
+ struct xwd_state *h;
+ char *buf;
+ int size;
+
+ h = malloc(sizeof(*h));
+ memset(h,0,sizeof(*h));
+ h->infile = fp;
+
+ fread(&h->header,sizeof(h->header),1,fp);
+
+ if ((be32_to_cpu(h->header.pixmap_format) >sizeof(fmt)/sizeof(char*)) ||
+ (be32_to_cpu(h->header.byte_order) >sizeof(order)/sizeof(char*)) ||
+ (be32_to_cpu(h->header.visual_class) >sizeof(vclass)/sizeof(char*))) {
+ fprintf(stderr,"xwd: invalid file\n");
+ goto oops;
+ }
+
+ if (debug)
+ fprintf(stderr,
+ "xwd: fmt=%s depth=%" PRId32 " size=%" PRId32 "x%" PRId32
+ " bpp=%" PRId32 " bpl=%" PRId32 "\n"
+ "xwd: order=%s vclass=%s masks=%" PRIx32 "/%" PRIx32
+ "/%" PRIx32 " cmap=%" PRId32 "\n",
+ fmt[be32_to_cpu(h->header.pixmap_format)],
+ be32_to_cpu(h->header.pixmap_depth),
+ be32_to_cpu(h->header.pixmap_width),
+ be32_to_cpu(h->header.pixmap_height),
+ be32_to_cpu(h->header.bits_per_pixel),
+ be32_to_cpu(h->header.bytes_per_line),
+ order[be32_to_cpu(h->header.byte_order)],
+ vclass[be32_to_cpu(h->header.visual_class)],
+ be32_to_cpu(h->header.red_mask),
+ be32_to_cpu(h->header.green_mask),
+ be32_to_cpu(h->header.blue_mask),
+ be32_to_cpu(h->header.colormap_entries));
+
+ size = be32_to_cpu(h->header.header_size)-sizeof(h->header);
+ buf = malloc(size);
+ fread(buf,size,1,fp);
+ if (debug)
+ fprintf(stderr,"xwd: name=%s\n",buf);
+ free(buf);
+
+ /* check format */
+ if (8 != be32_to_cpu(h->header.bits_per_pixel) &&
+ 16 != be32_to_cpu(h->header.bits_per_pixel) &&
+ 24 != be32_to_cpu(h->header.bits_per_pixel) &&
+ 32 != be32_to_cpu(h->header.bits_per_pixel)) {
+ fprintf(stderr,"xwd: Oops: bpp != 8/16/24/32\n");
+ goto oops;
+ }
+ if (be32_to_cpu(h->header.pixmap_format) != ZPixmap) {
+ fprintf(stderr,"xwd: Oops: can read only ZPixmap format\n");
+ goto oops;
+ }
+
+ /* color map */
+ if (be32_to_cpu(h->header.colormap_entries) > 256) {
+ fprintf(stderr,"xwd: colormap too big (%" PRId32 " > 256)\n",
+ be32_to_cpu(h->header.colormap_entries));
+ goto oops;
+ }
+ fread(&h->cmap,sizeof(XWDColor),be32_to_cpu(h->header.colormap_entries),fp);
+#if 0
+ for (i = 0; i < be32_to_cpu(h->header.colormap_entries); i++)
+ fprintf(stderr, "xwd cmap: %d: "
+ "pix=%ld rgb=%d/%d/%d flags=%d pad=%d\n",i,
+ be32_to_cpu(h->cmap[i].pixel),
+ be16_to_cpu(h->cmap[i].red),
+ be16_to_cpu(h->cmap[i].green),
+ be16_to_cpu(h->cmap[i].blue),
+ h->cmap[i].flags,
+ h->cmap[i].pad);
+#endif
+
+ switch (be32_to_cpu(h->header.visual_class)) {
+ case StaticGray:
+ case PseudoColor:
+ /* nothing */
+ break;
+ case TrueColor:
+ case DirectColor:
+ xwd_map(h);
+ break;
+ default:
+ fprintf(stderr,"xwd: Oops: visual not implemented [%s]\n",
+ vclass[be32_to_cpu(h->header.visual_class)]);
+ goto oops;
+ }
+
+ h->bpp = be32_to_cpu(h->header.bits_per_pixel);
+ h->width = be32_to_cpu(h->header.pixmap_width);
+ h->pix = malloc(h->width*sizeof(unsigned long));
+ h->row = malloc(be32_to_cpu(h->header.bytes_per_line));
+ i->width = be32_to_cpu(h->header.pixmap_width);
+ i->height = be32_to_cpu(h->header.pixmap_height);
+ i->npages = 1;
+ return h;
+
+ oops:
+ fclose(h->infile);
+ free(h);
+ return NULL;
+}
+
+static void
+xwd_parse(unsigned char *dst, unsigned int line, void *data)
+{
+ struct xwd_state *h = data;
+ unsigned long r,g,b;
+ int x,i,bits;
+
+ /* data to 32bit values */
+ memset(h->pix,0,h->width * sizeof(unsigned long));
+ if (be32_to_cpu(h->header.byte_order) == LSBFirst) {
+ for (i = 0, x = 0; x < h->width; x++)
+ for (bits = 0; bits < h->bpp; bits += 8)
+ h->pix[x] |= h->row[i++] << bits;
+ } else {
+ for (i = 0, x = 0; x < h->width; x++)
+ for (bits = 0; bits < h->bpp; bits += 8)
+ h->pix[x] <<= 8, h->pix[x] |= h->row[i++];
+ }
+
+ /* transform to rgb */
+ switch (be32_to_cpu(h->header.visual_class)) {
+ case StaticGray:
+ for (x = 0; x < h->width; x++) {
+ dst[0] = h->pix[x];
+ dst[1] = h->pix[x];
+ dst[2] = h->pix[x];
+ dst += 3;
+ }
+ break;
+ case PseudoColor:
+ for (x = 0; x < h->width; x++) {
+ dst[0] = be16_to_cpu(h->cmap[h->pix[x]].red) >> 8;
+ dst[1] = be16_to_cpu(h->cmap[h->pix[x]].green) >> 8;
+ dst[2] = be16_to_cpu(h->cmap[h->pix[x]].blue) >> 8;
+ dst += 3;
+ }
+ break;
+ case TrueColor:
+ case DirectColor:
+ for (x = 0; x < h->width; x++) {
+ r = h->pix[x] & h->r_mask;
+ if (h->r_shift > 0)
+ r >>= h->r_shift;
+ if (h->r_shift < 0)
+ r <<= -h->r_shift;
+ g = h->pix[x] & h->g_mask;
+ if (h->g_shift > 0)
+ g >>= h->g_shift;
+ if (h->g_shift < 0)
+ g <<= -h->g_shift;
+ b = h->pix[x] & h->b_mask;
+ if (h->b_shift > 0)
+ b >>= h->b_shift;
+ if (h->b_shift < 0)
+ b <<= -h->b_shift;
+ dst[0] = r;
+ dst[1] = g;
+ dst[2] = b;
+ dst += 3;
+ }
+ break;
+ }
+}
+
+static void
+xwd_read(unsigned char *dst, unsigned int line, void *data)
+{
+ struct xwd_state *h = data;
+
+ fread(h->row,be32_to_cpu(h->header.bytes_per_line),1,h->infile);
+ xwd_parse(dst, line, data);
+}
+
+static void
+xwd_done(void *data)
+{
+ struct xwd_state *h = data;
+
+ fclose(h->infile);
+ free(h->pix);
+ free(h->row);
+ free(h);
+}
+
+static struct ida_loader xwd_loader = {
+ magic: "\0\0\0\7",
+ moff: 4,
+ mlen: 4,
+ name: "xwd",
+ init: xwd_init,
+ read: xwd_read,
+ done: xwd_done,
+};
+
+static void __init init_rd(void)
+{
+ load_register(&xwd_loader);
+}
+
+/* ----------------------------------------------------------------------- */
+
+void
+parse_ximage(struct ida_image *dest, XImage *src)
+{
+ struct xwd_state h;
+ Colormap cmap;
+ XColor col;
+ int y,i;
+
+ memset(&h,0,sizeof(h));
+ h.width = src->width;
+ h.bpp = src->bits_per_pixel;
+ h.header.red_mask = be32_to_cpu(info->red_mask);
+ h.header.green_mask = be32_to_cpu(info->green_mask);
+ h.header.blue_mask = be32_to_cpu(info->blue_mask);
+ h.header.visual_class = be32_to_cpu(info->class);
+ h.header.byte_order = be32_to_cpu(ImageByteOrder(dpy));
+ h.pix = malloc(src->width * sizeof(unsigned long));
+
+ switch (be32_to_cpu(h.header.visual_class)) {
+ case PseudoColor:
+ cmap = DefaultColormapOfScreen(XtScreen(app_shell));
+ for (i = 0; i < 256; i++) {
+ col.pixel = i;
+ XQueryColor(dpy,cmap,&col);
+ h.cmap[i].red = be16_to_cpu(col.red);
+ h.cmap[i].green = be16_to_cpu(col.green);
+ h.cmap[i].blue = be16_to_cpu(col.blue);
+ }
+ break;
+ case TrueColor:
+ case DirectColor:
+ xwd_map(&h);
+ break;
+ }
+
+ memset(dest,0,sizeof(*dest));
+ dest->i.width = src->width;
+ dest->i.height = src->height;
+ dest->data = malloc(dest->i.width * dest->i.height * 3);
+ memset(dest->data,0,dest->i.width * dest->i.height * 3);
+
+ for (y = 0; y < src->height; y++) {
+ h.row = src->data + y*src->bytes_per_line;
+ xwd_parse(dest->data + 3*y*dest->i.width, y, &h);
+ }
+ free(h.pix);
+}