home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / xloadimg.zip / xloadimage.4.1 / xwd.c < prev    next >
C/C++ Source or Header  |  1993-10-21  |  15KB  |  506 lines

  1. /* xwd.c:
  2.  *
  3.  * XWD file reader.  unfortunately the bozo who thought up this format didn't
  4.  * define anything at all that we can use as an identifier or even to tell
  5.  * what kind of machine dumped the format.  what this does is read the
  6.  * header and look at several fields to decide if this *might* be an XWD
  7.  * file and if it is what byte order machine wrote it.
  8.  *
  9.  * jim frost 07.24.90
  10.  *
  11.  * Copyright 1990 Jim Frost.  See included file "copyright.h" for complete
  12.  * copyright information.
  13.  */
  14.  
  15. #include "copyright.h"
  16. #include "xloadimage.h"
  17. #include "xwd.h"
  18.  
  19. /* SUPPRESS 558 */
  20.  
  21. /* this reads the header and does the magic to determine if it is indeed
  22.  * an XWD file.
  23.  */
  24.  
  25. static int isXWD(name, zf, header, verbose)
  26.      char      *name;
  27.      ZFILE     *zf;
  28.      XWDHeader *header;
  29.      int        verbose;
  30. { GenericXWDHeader  gh;
  31.   int               a;
  32.  
  33.   if (zread(zf, (byte *)&gh, sizeof(GenericXWDHeader)) != sizeof(GenericXWDHeader))
  34.     return(0);
  35.  
  36.   /* first try -- see if XWD version number matches in either MSB or LSB order
  37.    */
  38.  
  39.   if (memToVal(gh.file_version, 4) != XWD_VERSION)
  40.     return(0);
  41.  
  42.   /* convert fields to fill out header.  things we don't care about
  43.    * are commented out.
  44.    */
  45.  
  46.   header->header_size= memToVal(gh.header_size, 4);
  47.   header->file_version= memToVal(gh.file_version, 4);
  48.   header->pixmap_format= memToVal(gh.pixmap_format, 4);
  49.   header->pixmap_depth= memToVal(gh.pixmap_depth, 4);
  50.   header->pixmap_width= memToVal(gh.pixmap_width, 4);
  51.   header->pixmap_height= memToVal(gh.pixmap_height, 4);
  52.   header->xoffset= memToVal(gh.xoffset, 4);
  53.   header->byte_order= memToVal(gh.byte_order, 4);
  54.   header->bitmap_unit= memToVal(gh.bitmap_unit, 4);
  55.   header->bitmap_bit_order= memToVal(gh.bitmap_bit_order, 4);
  56.   header->bitmap_pad= memToVal(gh.bitmap_pad, 4);
  57.   header->bits_per_pixel= memToVal(gh.bits_per_pixel, 4);
  58.   header->bytes_per_line= memToVal(gh.bytes_per_line, 4);
  59.   header->visual_class= memToVal(gh.visual_class, 4);
  60. /*header->red_mask= memToVal(gh.red_mask, 4);*/
  61. /*header->green_mask= memToVal(gh.green_mask, 4);*/
  62. /*header->blue_mask= memToVal(gh.blue_mask, 4);*/
  63. /*header->bits_per_rgb= memToVal(gh.bits_per_rgb, 4);*/
  64.   header->colormap_entries= memToVal(gh.colormap_entries, 4);
  65.   header->ncolors= memToVal(gh.ncolors, 4);
  66. /*header->window_width= memToVal(gh.window_width, 4);*/
  67. /*header->window_height= memToVal(gh.window_height, 4);*/
  68. /*header->window_x= memToVal(gh.window_x, 4);*/
  69. /*header->window_y= memToVal(gh.window_y, 4);*/
  70. /*header->window_bdrwidth= memToVal(gh.window_bdrwidth, 4);*/
  71.  
  72.   /* if header size isn't either 100 or 104 bytes, this isn't an XWD file
  73.    */
  74.  
  75.   if (header->header_size < sizeof(GenericXWDHeader))
  76.     return(0);
  77.  
  78.   for (a= header->header_size - sizeof(GenericXWDHeader); a; a--)
  79.     zgetc(zf);
  80.  
  81.   /* look at a variety of the XImage fields to see if they are sane.  if
  82.    * they are, this passes our tests.
  83.    */
  84.  
  85.   switch (header->pixmap_format) {
  86.   case XYBitmap:
  87.   case XYPixmap:
  88.   case ZPixmap:
  89.     break;
  90.   default:
  91.     return(0);
  92.   }
  93.  
  94.   switch (header->visual_class) {
  95.   case StaticGray:
  96.   case GrayScale:
  97.   case StaticColor:
  98.   case PseudoColor:
  99.  
  100.     /* the following are unsupported but recognized
  101.      */
  102.  
  103.   case TrueColor:
  104.   case DirectColor:
  105.     break;
  106.   default:
  107.     return(0);
  108.   }
  109.  
  110.   if (verbose) {
  111.     printf("%s is a %dx%d XWD image in ",
  112.        name, header->pixmap_width, header->pixmap_height);
  113.     switch (header->pixmap_format) {
  114.     case XYBitmap:
  115.       printf("XYBitmap");
  116.       break;
  117.     case XYPixmap:
  118.       printf("%d bit XYPixmap", header->pixmap_depth);
  119.       break;
  120.     case ZPixmap:
  121.       printf("%d bit ZPixmap", header->pixmap_depth);
  122.       break;
  123.     }
  124.     printf(" format\n");
  125.   }
  126.  
  127.   /* if it got this far, we're pretty damned certain we've got the right
  128.    * file type and know what order it's in.
  129.    */
  130.  
  131.   znocache(zf);
  132.   return(1);
  133. }
  134.  
  135. int xwdIdent(fullname, name)
  136.      char *fullname, *name;
  137. { ZFILE     *zf;
  138.   XWDHeader  header;
  139.   int ret;
  140.  
  141.   if (! (zf= zopen(fullname)))
  142.     return(0);
  143.   ret= isXWD(name, zf, &header, 1);
  144.   zclose(zf);
  145.   return(ret);
  146. }
  147.  
  148. static Image *loadXYBitmap(fullname, zf, header)
  149.      char *fullname;
  150.      ZFILE     *zf;
  151.      XWDHeader  header;
  152. { Image *image;
  153.   int    dlinelen;       /* length of scan line in data file */
  154.   int    ilinelen;       /* length of line within image structure */
  155.   int    unit;           /* # of bytes in a bitmap unit */
  156.   int    xoffset;        /* xoffset within line */
  157.   int    xunits;         /* # of units across the whole scan line */
  158.   int    trailer;        /* # of bytes in last bitmap unit on a line */
  159.   int    shift;          /* # of bits to shift last byte set */
  160.   int    x, y;           /* horizontal and vertical counters */
  161.   byte  *line;           /* input scan line */
  162.   byte  *dptr, *iptr;    /* image data pointers */
  163.   unsigned long (*loader)(); /* unit loading function */
  164.  
  165.   image= newBitImage(header.pixmap_width, header.pixmap_height);
  166.   ilinelen= (header.pixmap_width / 8) + (header.pixmap_width % 8 ? 1 : 0);
  167.   if (header.bitmap_unit > 7)     /* supposed to be 8, 16, or 32 but appears */
  168.     unit= header.bitmap_unit / 8; /* to often be the byte count.  this will */
  169.   else                            /* accept either. */
  170.     unit= header.bitmap_unit;
  171.   xoffset= (header.xoffset / (unit * 8)) * unit;
  172.   if (header.bytes_per_line)
  173.     dlinelen= header.bytes_per_line;
  174.   else
  175.     dlinelen= unit * header.pixmap_width;
  176.   xunits= (header.pixmap_width / (unit * 8)) +
  177.     (header.pixmap_width % (unit * 8) ? 1 : 0);
  178.   trailer= unit - ((xunits * unit) - ilinelen);
  179.   xunits--; /* we want to use one less than the actual # of units */
  180.   shift= (unit - trailer) * 8;
  181.   if (header.byte_order == MSBFirst)
  182.     loader= doMemToVal;
  183.   else
  184.     loader= doMemToValLSB;
  185.   line= (byte *)lmalloc(dlinelen);
  186.  
  187.   for (y= 0; y < header.pixmap_height; y++) {
  188.     if (zread(zf, (byte *)line, dlinelen) != dlinelen) {
  189.       fprintf(stderr,
  190.           "%s: Short read while reading data! (returning partial image)\n",
  191.           fullname);
  192.       lfree(line);
  193.       return(image);
  194.     }
  195.     dptr= line + xoffset;
  196.     iptr= image->data + (y * ilinelen);
  197.  
  198.     if (header.bitmap_bit_order == LSBFirst)
  199.       flipBits(line, dlinelen);
  200.  
  201.     for (x= 0; x < xunits; x++) {
  202.       valToMem(loader(dptr, unit), iptr, unit);
  203.       dptr += unit;
  204.       iptr += unit;
  205.     }
  206.  
  207.     /* take care of last unit on this line
  208.      */
  209.  
  210.     valToMem(loader(dptr, unit) >> shift, iptr, trailer);
  211.   }
  212.  
  213.   lfree(line);
  214.   return(image);
  215. }
  216.  
  217. /* this is a lot like the above function but OR's planes together to
  218.  * build the destination.  1-bit images are handled by XYBitmap.
  219.  */
  220.  
  221. static Image *loadXYPixmap(fullname, zf, header)
  222.      char *fullname;
  223.      ZFILE *zf;
  224.      XWDHeader header;
  225. { Image *image;
  226.   int plane;
  227.   int    dlinelen;       /* length of scan line in data file */
  228.   int    ilinelen;       /* length of line within image structure */
  229.   int    unit;           /* # of bytes in a bitmap unit */
  230.   int    unitbits;       /* # of bits in a bitmap unit */
  231.   int    unitmask;       /* mask for current bit within current unit */
  232.   int    xoffset;        /* xoffset within data */
  233.   int    xunits;         /* # of units across the whole scan line */
  234.   int    x, x2, y;       /* horizontal and vertical counters */
  235.   int    index;          /* index within image scan line */
  236.   byte  *line;           /* input scan line */
  237.   byte  *dptr, *iptr;    /* image data pointers */
  238.   unsigned long pixvals; /* bits for pixels in this unit */
  239.   unsigned long mask;
  240.   unsigned long (*loader)(); /* unit loading function */
  241.  
  242.   image= newRGBImage(header.pixmap_width, header.pixmap_height,
  243.              header.pixmap_depth);
  244.   ilinelen= image->width * image->pixlen;
  245.   if (header.bitmap_unit > 7)     /* supposed to be 8, 16, or 32 but appears */
  246.     unit= header.bitmap_unit / 8; /* to often be the byte count.  this will */
  247.   else                            /* accept either. */
  248.     unit= header.bitmap_unit;
  249.   unitbits= unit * 8;
  250.   unitmask= 1 << (unitbits - 1);
  251.   xoffset= (header.xoffset / unitbits) * unit;
  252.   if (header.bytes_per_line)
  253.     dlinelen= header.bytes_per_line;
  254.   else
  255.     dlinelen= unit * header.pixmap_width;
  256.   xunits= (header.pixmap_width / (unit * 8)) +
  257.     (header.pixmap_width % (unit * 8) ? 1 : 0);
  258.   if (header.byte_order == MSBFirst)
  259.     loader= doMemToVal;
  260.   else
  261.     loader= doMemToValLSB;
  262.   line= (byte *)lmalloc(dlinelen);
  263.  
  264.   /* for each plane, load in the bitmap and or it into the image
  265.    */
  266.  
  267.   for (plane= 0; plane < header.pixmap_depth; plane++) {
  268.     Pixel plane_mask;
  269.  
  270.     plane_mask = (1 << (header.pixmap_depth - plane - 1));
  271.  
  272.     for (y= 0; y < header.pixmap_height; y++) {
  273.       if (zread(zf, (byte *)line, dlinelen) != dlinelen) {
  274.     fprintf(stderr,
  275.         "%s: Short read while reading data! (returning partial image)\n",
  276.         fullname);
  277.     lfree(line);
  278.     return(image);
  279.       }
  280.       dptr= line + xoffset;
  281.       iptr= image->data + (y * ilinelen);
  282.       index= 0;
  283.  
  284.       if (header.bitmap_bit_order == LSBFirst)
  285.     flipBits(line, dlinelen);
  286.       
  287.       for (x= 0; x < xunits; x++) {
  288.     pixvals= loader(dptr, unit);
  289.     mask= unitmask;
  290.     for (x2= 0; x2 < unitbits; x2++) {
  291.       if (pixvals & mask)
  292.         valToMem(memToVal(iptr + index, image->pixlen) | plane_mask,
  293.              iptr + index, image->pixlen);
  294.       index += image->pixlen;
  295.       if (index > ilinelen) {
  296.         x= xunits;
  297.         break;
  298.       }
  299.       if (! (mask >>= 1))
  300.         mask= unitmask;
  301.     }
  302.     dptr += unit;
  303.       }
  304.     }
  305.   }
  306.  
  307.   lfree(line);
  308.   return(image);
  309. }
  310.  
  311. /* this loads a ZPixmap format image.  note that this only supports depths
  312.  * of 4, 8, 16, 24, or 32 bits as does Xlib.  You gotta 6-bit image,
  313.  * you gotta problem.  1-bit images are handled by XYBitmap.
  314.  */
  315.  
  316. static Image *loadZPixmap(fullname, zf, header)
  317.      char *fullname;
  318.      ZFILE *zf;
  319.      XWDHeader header;
  320. { Image *image;
  321.   int    dlinelen;       /* length of scan line in data file */
  322.   int    ilinelen;       /* length of scan line in image file */
  323.   int    depth;          /* depth rounded up to 8-bit value */
  324.   int    pixlen;         /* length of pixel in bytes */
  325.   int    x, y;           /* horizontal and vertical counters */
  326.   byte  *line;           /* input scan line */
  327.   byte  *dptr, *iptr;    /* image data pointers */
  328.   unsigned long pixmask; /* bit mask within pixel */
  329.   unsigned long pixel;   /* pixel we're working on */
  330.   unsigned long (*loader)(); /* unit loading function */
  331.  
  332.   image= newRGBImage(header.pixmap_width, header.pixmap_height,
  333.              header.pixmap_depth);
  334.  
  335.   /* for pixmaps that aren't simple depths, we round to a depth of 8.  this
  336.    * is what Xlib does, be it right nor not.
  337.    */
  338.  
  339.   if ((header.pixmap_depth != 4) && (header.pixmap_depth % 8))
  340.     depth= header.pixmap_depth + 8 - (header.pixmap_depth % 8);
  341.   else
  342.     depth= header.pixmap_depth;
  343.  
  344.   pixmask= 0xffffffff >> (32 - header.pixmap_depth);
  345.   pixlen= image->pixlen;
  346.   if (header.bytes_per_line)
  347.     dlinelen= header.bytes_per_line;
  348.   else
  349.     dlinelen= depth * header.pixmap_width;
  350.   ilinelen= image->width * image->pixlen;
  351.   if (header.byte_order == MSBFirst)
  352.     loader= doMemToVal;
  353.   else
  354.     loader= doMemToValLSB;
  355.  
  356.   line= (byte *)lmalloc(dlinelen);
  357.  
  358.   for (y= 0; y < header.pixmap_height; y++) {
  359.     if (zread(zf, (byte *)line, dlinelen) != dlinelen) {
  360.       fprintf(stderr,
  361.           "%s: Short read while reading data! (returning partial image)\n",
  362.           fullname);
  363.       lfree(line);
  364.       return(image);
  365.     }
  366.     dptr= line;
  367.     iptr= image->data + (y * ilinelen);
  368.  
  369.     if (header.bitmap_bit_order == LSBFirst)
  370.       flipBits(line, dlinelen);
  371.  
  372.     for (x= 0; x < header.pixmap_width; x++) {
  373.       switch (depth) {
  374.       case 4:
  375.     pixel= memToVal(dptr, 1);
  376.     if (header.bitmap_bit_order == LSBFirst) { /* nybbles are reversed */
  377.       valToMem(pixel & 0xf, iptr++, 1);        /* by flipBits */
  378.       if (++x < header.pixmap_width)
  379.         valToMem(pixel >> 4, iptr++, 1);
  380.     }
  381.     else {
  382.       valToMem(pixel >> 4, iptr++, 1);
  383.       if (++x < header.pixmap_width)
  384.         valToMem(pixel & 0xf, iptr++, 1);
  385.     }
  386.     break;
  387.       case 8:
  388.     pixel= ((unsigned long)*(dptr++)) & pixmask; /* loader isn't needed */
  389.     valToMem(pixel, iptr++, 1);
  390.     break;
  391.       case 16:
  392.       case 24:
  393.       case 32:
  394.     valToMem(loader(dptr, pixlen) & pixmask, iptr, pixlen);
  395.     dptr += pixlen;
  396.     iptr += pixlen;
  397.     break;
  398.       default:
  399.     fprintf(stderr,
  400.         "%s: ZPixmaps of depth %d are not supported (sorry).\n",
  401.         fullname, header.pixmap_depth);
  402.     exit(1);
  403.       }
  404.     }
  405.   }
  406.  
  407.   lfree(line);
  408.   return(image);
  409. }
  410.  
  411. Image *xwdLoad(fullname, name, verbose)
  412.      char *fullname, *name;
  413.      int verbose;
  414. { ZFILE     *zf;
  415.   XWDHeader  header;
  416.   int        cmaplen;
  417.   XWDColor  *cmap;
  418.   Image     *image;
  419.   int        a;
  420.  
  421.   if (! (zf= zopen(fullname)))
  422.     return(NULL);
  423.   if (! isXWD(name, zf, &header, verbose)) {
  424.     zclose(zf);
  425.     return(NULL);
  426.   }
  427.  
  428.   /* complain if we don't understand the visual
  429.    */
  430.  
  431.   switch (header.visual_class) {
  432.   case StaticGray:
  433.   case GrayScale:
  434.   case StaticColor:
  435.   case PseudoColor:
  436.     break;
  437.   case TrueColor:
  438.   case DirectColor:
  439.     fprintf(stderr, "Unsupported visual type, sorry\n");
  440.     exit(1);
  441.   }
  442.  
  443.   if ((header.pixmap_width == 0) || (header.pixmap_height == 0)) {
  444.     fprintf(stderr, "Zero-size image -- header might be corrupted.\n");
  445.     exit(1);
  446.   }
  447.  
  448.   /* read in colormap
  449.    */
  450.  
  451.   cmaplen= header.ncolors * sizeof(XWDColor);
  452.   cmap= (XWDColor *)lmalloc(cmaplen);
  453.   if (zread(zf, (byte *)cmap, cmaplen) != cmaplen) {
  454.     fprintf(stderr, "Short read in colormap!\n");
  455.     exit(1);
  456.   }
  457.  
  458.   /* any depth 1 image is basically a XYBitmap so we fake it here
  459.    */
  460.  
  461.   if (header.pixmap_depth == 1)
  462.     header.pixmap_format= XYBitmap;
  463.  
  464.   /* we can't realistically support images of more than depth 16 with the
  465.    * RGB image format so this nukes them for the time being.
  466.    */
  467.  
  468.   if (header.pixmap_depth > 16) {
  469.     fprintf(stderr,
  470.         "%s: Sorry, cannot load images deeper than 16 bits (yet)\n",
  471.         fullname);
  472.     exit(1);
  473.   }
  474.  
  475.   switch (header.pixmap_format) {
  476.   case XYBitmap:
  477.     image= loadXYBitmap(fullname, zf, header);
  478.     zclose(zf);
  479.     image->title= dupString(name);
  480.     return(image); /* we used to goof w/ the cmap but we gave up */
  481.   case XYPixmap:
  482.     image= loadXYPixmap(fullname, zf, header);
  483.     break;
  484.   case ZPixmap:
  485.     image= loadZPixmap(fullname, zf, header);
  486.     break;
  487.   }
  488.   zclose(zf);
  489.   image->title= dupString(name);
  490.  
  491.   /* load the colormap.  we should probably use pixval instead of the color
  492.    * number but the value seems pretty system-dependent and most colormaps
  493.    * seem to be just dumped in order.
  494.    */
  495.  
  496.   image->rgb.used= header.ncolors;
  497.   for (a= 0; a < header.ncolors; a++) {
  498.     image->rgb.red[memToVal(cmap[a].pixel, 4)]= memToVal(cmap[a].red, 2);
  499.     image->rgb.green[memToVal(cmap[a].pixel, 4)]= memToVal(cmap[a].green, 2);
  500.     image->rgb.blue[memToVal(cmap[a].pixel, 4)]= memToVal(cmap[a].blue, 2);
  501.   }
  502.  
  503.   lfree((byte *)cmap);
  504.   return(image);
  505. }
  506.