aboutsummaryrefslogtreecommitdiffstats
path: root/rd/read-xwd.c
diff options
context:
space:
mode:
Diffstat (limited to 'rd/read-xwd.c')
-rw-r--r--rd/read-xwd.c357
1 files changed, 357 insertions, 0 deletions
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);
+}