Logo Search packages:      
Sourcecode: fbi version File versions  Download package

read-xwd.c

#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);
}

Generated by  Doxygen 1.6.0   Back to index