diff options
Diffstat (limited to 'rd')
-rw-r--r-- | rd/Makefile | 2 | ||||
-rw-r--r-- | rd/magick.c | 85 | ||||
-rw-r--r-- | rd/read-bmp.c | 216 | ||||
-rw-r--r-- | rd/read-gif.c | 220 | ||||
-rw-r--r-- | rd/read-jpeg.c | 187 | ||||
-rw-r--r-- | rd/read-pcd.c | 78 | ||||
-rw-r--r-- | rd/read-png.c | 164 | ||||
-rw-r--r-- | rd/read-ppm.c | 110 | ||||
-rw-r--r-- | rd/read-tiff.c | 195 | ||||
-rw-r--r-- | rd/read-xpm.c | 287 | ||||
-rw-r--r-- | rd/read-xwd.c | 357 |
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); +} |