home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / modules / libimg / src / xbm.c < prev   
Encoding:
C/C++ Source or Header  |  1998-04-08  |  18.9 KB  |  650 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /* -*- Mode: C; tab-width: 4 -*-
  20.  *   xbm.c --- Decoding of X bit-map format images
  21.  * $Id: xbm.c,v 3.1 1998/03/28 03:35:04 ltabb Exp $
  22.  */
  23.  
  24.  
  25. /*
  26. #include "xp.h"
  27. */
  28.  
  29. #include "if.h"
  30.  
  31. #define CR '\015'
  32. #define LF '\012'
  33. #include "merrors.h"
  34.  
  35. #include "il.h"
  36.  
  37. extern int MK_OUT_OF_MEMORY;
  38.  
  39. typedef enum {
  40.     xbm_gather,
  41.     xbm_init,
  42.     xbm_width,
  43.     xbm_height,
  44.     xbm_start_data,
  45.     xbm_data,
  46.     xbm_hex,
  47.     xbm_done,
  48.     xbm_oom,
  49.     xbm_error
  50. } xstate;
  51.  
  52. #define MAX_HOLD 512
  53.  
  54. typedef void(*il_xbm_converter)(void *, unsigned char, unsigned int);
  55.  
  56. typedef struct xbm_struct {
  57.     xstate state;
  58.     unsigned char hold[MAX_HOLD];
  59.     intn gathern;                /* gather n chars */
  60.     unsigned char gatherc;        /* gather until char c */
  61.     intn gathered;                /* bytes accumulated */
  62.     xstate gathers;                /* post-gather state */
  63.     uint32 xpos, ypos;
  64.     unsigned char *p;            /* raster position */
  65.     unsigned char *m;           /* mask position (if mask is used) */
  66.     il_xbm_converter converter; /* colorspace converter */
  67.     uint8 bg_pixel;             /* destination image background pixel index */
  68.     uint8 fg_pixel;             /* destination image foreground pixel index */
  69. } xbm_struct;
  70.  
  71. #define MAX_LINE MAX_HOLD        /* XXX really bad xbms will hose us */
  72.  
  73.  
  74. #define GETN(n,s) {xs->state=xbm_gather; xs->gathern=n; xs->gathers=s;}
  75. #define GETC(c,s) {xs->state=xbm_gather; xs->gatherc=c; xs->gathers=s;}
  76.  
  77. char hex_table_initialized = FALSE;
  78. static uint8 hex[256];
  79.  
  80. static void
  81. il_init_hex_table(void)
  82. {
  83.     hex['0'] = 0; hex['1'] = 8;
  84.     hex['2'] = 4; hex['3'] = 12;
  85.     hex['4'] = 2; hex['5'] = 10;
  86.     hex['6'] = 6; hex['7'] = 14;
  87.     hex['8'] = 1; hex['9'] = 9;
  88.     hex['A'] = hex['a'] = 5;
  89.     hex['B'] = hex['b'] = 13;
  90.     hex['C'] = hex['c'] = 3;
  91.     hex['D'] = hex['d'] = 11;
  92.     hex['E'] = hex['e'] = 7;
  93.     hex['F'] = hex['f'] = 15;
  94.  
  95.     hex_table_initialized = TRUE;
  96. }
  97.  
  98. int il_xbm_init(il_container *ic)
  99. {
  100.     xbm_struct *xs;
  101.     NI_ColorSpace *src_color_space = ic->src_header->color_space;
  102.  
  103.     if (!hex_table_initialized)
  104.         il_init_hex_table();
  105.  
  106.     xs = XP_NEW_ZAP (xbm_struct);
  107.     if (xs) 
  108.     {
  109.         xs->state = xbm_init;
  110.         xs->gathers = xbm_error;
  111.         ic->ds = xs;
  112.     }
  113.  
  114.     /* Initialize the container's source image header. */
  115.     src_color_space->type = NI_GreyScale;
  116.     src_color_space->pixmap_depth = 1;
  117.     src_color_space->bit_alloc.index_depth = 1;
  118.     src_color_space->cmap.num_colors = 2;
  119.  
  120.     return xs != 0;
  121. }
  122.  
  123.  
  124. static int
  125. il_xbm_init_transparency(il_container *ic)
  126. {
  127.     IL_IRGB *src_trans_pixel = ic->src_header->transparent_pixel;
  128.     IL_IRGB *img_trans_pixel;
  129.    
  130.     if (!src_trans_pixel) {
  131.         src_trans_pixel = XP_NEW_ZAP(IL_IRGB);
  132.         if (!src_trans_pixel)
  133.             return FALSE;
  134.         ic->src_header->transparent_pixel = src_trans_pixel;
  135.  
  136.         /* Initialize the destination image's transparent pixel. */
  137.         il_init_image_transparent_pixel(ic);
  138.  
  139.         /* Set the source image's transparent pixel color to be the preferred
  140.            transparency color of the destination image. */
  141.         img_trans_pixel = ic->image->header.transparent_pixel;
  142.         src_trans_pixel->red = img_trans_pixel->red;
  143.         src_trans_pixel->green = img_trans_pixel->green;
  144.         src_trans_pixel->blue = img_trans_pixel->blue;
  145.         
  146.         /* Set the source image's transparent pixel index. */
  147.         src_trans_pixel->index = 1;
  148.     }
  149.  
  150.     return TRUE;
  151. }
  152.  
  153.  
  154. /* Since the XBM decoder writes directly to the image bits, we need to provide
  155.    our own color space conversion routines.  ConvertDefault is the preferred
  156.    routine from an efficiency standpoint, but it requires the Front Ends to
  157.    agree to receive 1-bit deep data.  The other routines are provided since
  158.    the Front Ends can request the Image Library to decode to the display
  159.    colorspace, which may not be 1-bit deep. */
  160. static void
  161. ConvertDefault(void *ds, unsigned char val, unsigned int last_bit_mask)
  162. {
  163.     xbm_struct *xs = ds;
  164.  
  165.     *xs->p = val;
  166.     xs->p++;
  167. }
  168.  
  169. static void
  170. ConvertBWToRGB8(void *ds, unsigned char val, unsigned int last_bit_mask)
  171. {
  172.     unsigned int bit_mask;
  173.     xbm_struct *xs = ds;
  174.     uint8 *ptr = (uint8 *)xs->p;
  175.  
  176.     for (bit_mask = 128; bit_mask >= last_bit_mask; bit_mask >>= 1) {
  177.         if (val & bit_mask)
  178.             *ptr = 0;
  179.         else
  180.             *ptr = (uint8)~0;
  181.         ptr++;
  182.     }
  183.     xs->p = (unsigned char *)ptr;
  184. }
  185.  
  186. static void
  187. ConvertBWToRGB16(void *ds, unsigned char val, unsigned int last_bit_mask)
  188. {
  189.     unsigned int bit_mask;
  190.     xbm_struct *xs = ds;
  191.     uint16 *ptr = (uint16 *)xs->p;
  192.  
  193.     for (bit_mask = 128; bit_mask >= last_bit_mask; bit_mask >>= 1) {
  194.         if (val & bit_mask)
  195.             *ptr = 0;
  196.         else
  197.             *ptr = (uint16)~0;
  198.         ptr++;
  199.     }
  200.     xs->p = (unsigned char *)ptr;
  201. }
  202.  
  203. static void
  204. ConvertBWToRGB24(void *ds, unsigned char val, unsigned int last_bit_mask)
  205. {
  206.     unsigned int bit_mask;
  207.     xbm_struct *xs = ds;
  208.     uint8 *ptr = (uint8 *)xs->p;
  209.  
  210.     for (bit_mask = 128; bit_mask >= last_bit_mask; bit_mask >>= 1) {
  211.         if (val & bit_mask) {
  212.             *ptr++ = 0;
  213.             *ptr++ = 0;
  214.             *ptr++ = 0;
  215.         }
  216.         else {
  217.             *ptr++ = (uint8)~0;
  218.             *ptr++ = (uint8)~0;
  219.             *ptr++ = (uint8)~0;
  220.         }
  221.     }
  222.     xs->p = (unsigned char *)ptr;
  223. }
  224.  
  225. static void
  226. ConvertBWToRGB32(void *ds, unsigned char val, unsigned int last_bit_mask)
  227. {
  228.     unsigned int bit_mask;
  229.     xbm_struct *xs = ds;
  230.     uint32 *ptr = (uint32 *)xs->p;
  231.  
  232.     for (bit_mask = 128; bit_mask >= last_bit_mask; bit_mask >>= 1) {
  233.         if (val & bit_mask)
  234.             *ptr = 0;
  235.         else
  236.             *ptr = (uint32)~0;
  237.         ptr++;
  238.     }
  239.     xs->p = (unsigned char *)ptr;
  240. }
  241.  
  242. static void
  243. ConvertBWToCI(void *ds, unsigned char val, unsigned int last_bit_mask)
  244. {
  245.     unsigned int bit_mask;
  246.     xbm_struct *xs = ds;
  247.     uint8 *ptr = (uint8 *)xs->p;
  248.     uint8 bg_pixel = xs->bg_pixel;
  249.     uint8 fg_pixel = xs->fg_pixel;
  250.  
  251.     for (bit_mask = 128; bit_mask >= last_bit_mask; bit_mask >>= 1) {
  252.         if (val & bit_mask)
  253.             *ptr = fg_pixel;
  254.         else
  255.             *ptr = bg_pixel;
  256.         ptr++;
  257.     }
  258.     xs->p = (unsigned char *)ptr;
  259. }
  260.  
  261.  
  262. static void
  263. il_xbm_setup_color_space_converter(il_container *ic)
  264. {
  265.     IL_ColorSpace *img_color_space = ic->image->header.color_space;
  266.     xbm_struct *xs = (xbm_struct *)ic->ds;
  267.  
  268.     switch (img_color_space->type) {
  269.     case NI_GreyScale:
  270.         switch (img_color_space->pixmap_depth) {
  271.         case 1:
  272.             xs->converter = ConvertDefault;
  273.             break;
  274.  
  275.         case 8:
  276.             xs->converter = ConvertBWToRGB8;
  277.             break;
  278.             
  279.         default:
  280.             XP_ASSERT(0);
  281.             break;
  282.         }
  283.         break;
  284.  
  285.     case NI_TrueColor:
  286.         switch (img_color_space->pixmap_depth) {
  287.         case 8:    
  288.             xs->converter = ConvertBWToRGB8;   
  289.             break;
  290.  
  291.         case 16:    
  292.             xs->converter = ConvertBWToRGB16;   
  293.             break;
  294.  
  295.         case 24:    
  296.             xs->converter = ConvertBWToRGB24;   
  297.             break;
  298.  
  299.         case 32:    
  300.             xs->converter = ConvertBWToRGB32;   
  301.             break;
  302.             
  303.         default:
  304.             XP_ASSERT(0);
  305.             break;
  306.         }
  307.         break;
  308.         
  309.     case NI_PseudoColor:
  310.         xs->converter = ConvertBWToCI;   
  311.         break;
  312.         
  313.     default:
  314.         XP_ASSERT(0);
  315.         break;
  316.     }
  317. }
  318.  
  319.  
  320. static void
  321. copyline(char *d, const unsigned char *s)
  322. {
  323.     int i=0;
  324.     while( i++ < MAX_LINE && *s && *s != LF )
  325.         *d++ = *s++;
  326.     *d=0;
  327. }
  328.  
  329. int il_xbm_write(il_container *ic, const unsigned char *buf, int32 len)
  330. {
  331.     int status, input_exhausted;
  332.     xbm_struct *xs = (xbm_struct *)ic->ds;
  333.     const unsigned char *q, *p=buf, *ep=buf+len;
  334.     IL_Pixmap *image = ic->image;
  335.     IL_Pixmap *mask = ic->mask;
  336.     NI_PixmapHeader *img_header = &image->header;
  337.     NI_PixmapHeader *mask_header = mask ? &mask->header : NULL;
  338.     NI_PixmapHeader *src_header = ic->src_header;
  339.     char lbuf[MAX_LINE+1];
  340.  
  341.     /* If this assert fires, chances are the netlib screwed up and
  342.        continued to send data after the image stream was closed. */
  343.     XP_ASSERT(xs);
  344.     if (!xs) {
  345. #ifdef DEBUG
  346.         XP_TRACE(("Netlib just took a shit on the imagelib\n"));
  347. #endif
  348.         return MK_IMAGE_LOSSAGE;
  349.     }
  350.  
  351.     q = NULL;                   /* Initialize to shut up gcc warnings */
  352.     input_exhausted = FALSE;
  353.     
  354.     while(!input_exhausted)
  355.     {
  356.         ILTRACE(9,("il:xbm: state %d len %d buf %u p %u ep %u",xs->state,len,buf,p,ep));
  357.  
  358.         switch(xs->state)
  359.            {
  360.             case xbm_data:
  361.                 GETN(2,xbm_hex);    
  362.                 break;
  363.     
  364.             case xbm_hex:
  365.                 {
  366.                     int num_pixels; /* Number of pixels remaining to be
  367.                                        processed in current scanline. */
  368.                     unsigned char val = (hex[q[1]]<<4) + hex[q[0]];
  369.  
  370.                     if (xs->xpos == 0) {
  371.                         /* XXX -kevina Locking of the bits pointers is
  372.                            currently done on per-scanline basis.  The XBM
  373.                            decoder, however, does not process a full scanline
  374.                            at a time, (only a single byte,) so if we return in
  375.                            the middle of a scanline, the bits pointers will
  376.                            remain locked until the next write call.  I would
  377.                            like to eventually make the XBM decoder process a
  378.                            full scanline at a time, since this would eliminate
  379.                            the locking anomaly, and it would also permit the
  380.                            colorspace converters to be modelled along the
  381.                            lines of (and hence bundled with) the per-scanline
  382.                            colorspace converters in the core image library. */
  383.                         IMGCBIF_ControlPixmapBits(ic->img_cx->img_cb,
  384.                                                   ic->img_cx->dpy_cx,
  385.                                                   ic->image, IL_LOCK_BITS);
  386.                         IMGCBIF_ControlPixmapBits(ic->img_cx->img_cb,
  387.                                                   ic->img_cx->dpy_cx,
  388.                                                   ic->mask, IL_LOCK_BITS);
  389.  
  390. #ifdef _USD
  391.                             xs->p = (unsigned char *)image->bits +
  392.                                 (img_header->height-xs->ypos-1) *
  393.                                 (img_header->widthBytes);
  394.                             if (mask)
  395.                                 xs->m = (unsigned char *)mask->bits +
  396.                                     (mask_header->height-xs->ypos-1) *
  397.                                     (mask_header->widthBytes);
  398. #else
  399.                             xs->p = (unsigned char *)image->bits +
  400.                                 xs->ypos * (img_header->widthBytes);
  401.                             if (mask)
  402.                                 xs->m = (unsigned char *)mask->bits +
  403.                                     xs->ypos * (mask_header->widthBytes);
  404. #endif
  405.                     }
  406.  
  407.                     if (mask) {
  408.                         *xs->m = val;
  409.                         xs->m++;
  410.                     }
  411.                         
  412.                     num_pixels = img_header->width - xs->xpos;
  413.                     if (num_pixels <= 8) {
  414.                         xs->converter((void*)xs, val, 1<<(8-num_pixels));
  415.  
  416.                         IMGCBIF_ControlPixmapBits(ic->img_cx->img_cb,
  417.                                                   ic->img_cx->dpy_cx,
  418.                                                   ic->image, IL_UNLOCK_BITS);
  419.                         IMGCBIF_ControlPixmapBits(ic->img_cx->img_cb,
  420.                                                   ic->img_cx->dpy_cx,
  421.                                                   ic->mask, IL_UNLOCK_BITS);
  422.                         
  423.                         xs->xpos=0;
  424.                         xs->ypos++;
  425.                         /* The image library does not scale XBMs, so if the
  426.                            requested target height does not match the source
  427.                            height, we stop when the smaller of the two is
  428.                            reached. */
  429.                         if (xs->ypos == src_header->height ||
  430.                             xs->ypos == img_header->height) {
  431.                             xs->state = xbm_done;
  432.                         }
  433.                         else {
  434.                             GETC('x',xbm_data);
  435.                         }
  436.                     }
  437.                     else {
  438.                         xs->converter((void*)xs, val, 1);
  439.                         xs->xpos+=8;
  440.                         GETC('x',xbm_data);
  441.                     }
  442.                 }
  443.                 break;
  444.         
  445.             case xbm_init:
  446.                 GETC(LF,xbm_width);
  447.                 break;
  448.  
  449.             case xbm_width:
  450.                 {
  451.                     copyline(lbuf, q);
  452.                     if(sscanf(lbuf, "#define %*s %d",
  453.                               (int *)&ic->src_header->width)==1) 
  454.                     {
  455.                         GETC(LF,xbm_height);
  456.                     }
  457.                     else
  458.                     {
  459.                         /* Accept any of CR/LF, CR, or LF.
  460.                            Allow multiple instances of each. */
  461.                         GETC(LF,xbm_width);
  462.                     }
  463.                 }
  464.                 break;
  465.         
  466.             case xbm_height:
  467.                 {
  468.                     copyline(lbuf, q);
  469.                     if(sscanf(lbuf, "#define %*s %d",
  470.                               (int *)&ic->src_header->height)==1)
  471.                     {
  472.                         IL_RGB* map;
  473.  
  474.                         if (!il_xbm_init_transparency(ic))
  475.                             return MK_OUT_OF_MEMORY; 
  476.                         
  477.                         if ((status = il_size(ic)) < 0)
  478.                         {
  479.                             if (status == MK_OUT_OF_MEMORY)
  480.                                 xs->state = xbm_oom;
  481.                             else
  482.                                 xs->state = xbm_error;
  483.                             break;
  484.                         }
  485.  
  486.                         /* Determine the background and foreground pixel
  487.                            indices of the destination image if this is a
  488.                            PseudoColor display.  Note: it is assumed that
  489.                            the index of the black pixel in the IL_ColorMap
  490.                            is 0. */
  491.                         if (img_header->color_space->type == NI_PseudoColor) {
  492.                             xs->bg_pixel =
  493.                                 img_header->transparent_pixel->index;
  494.                             xs->fg_pixel =
  495.                                 img_header->color_space->cmap.index[0];
  496.                         }
  497.  
  498.                         if (ic->mask) {
  499.                             mask = ic->mask;
  500.                             mask_header = &mask->header;
  501.                         }
  502.  
  503.                         if((map = (IL_RGB*)XP_CALLOC(2, sizeof(IL_RGB)))!=0)
  504.                             {
  505.                             src_header->color_space->cmap.map = map;
  506.                             map++; /* first index is black */
  507.                             map->red = src_header->transparent_pixel->red;
  508.                             map->green = src_header->transparent_pixel->green;
  509.                             map->blue = src_header->transparent_pixel->blue;
  510.                         }
  511.                         GETC('{',xbm_start_data);
  512.                         il_xbm_setup_color_space_converter(ic);
  513.                     }
  514.                     else
  515.                     {
  516.                         /* Accept any of CR/LF, CR, or LF.
  517.                            Allow multiple instances of each. */
  518.                         GETC(LF,xbm_height);
  519.                     }
  520.                 }
  521.                 break;
  522.  
  523.             case xbm_start_data:
  524.                 GETC('x',xbm_data);
  525.                 break;
  526.     
  527.             case xbm_gather:    
  528.                 {
  529.                     if(xs->gatherc)
  530.                     {
  531.                         const unsigned char *s;
  532.                         /* We may need to look ahead one character, so don't point
  533.                            at the last character in the buffer. */
  534.                         for(s = p; s < ep; s++)
  535.                         {
  536.                             if (xs->gatherc == LF) 
  537.                             {
  538.                                 if ((s[0] == LF) || (s[0] == CR))
  539.                                 {
  540.                                     xs->gatherc = 0;
  541.                                     break;
  542.                                 }
  543.                             }
  544.                             else if (s[0] == xs->gatherc)
  545.                             {
  546.                                 xs->gatherc = 0;
  547.                                 break;
  548.                             }
  549.                         }
  550.                             
  551.                         if(xs->gatherc)
  552.                         {
  553.                             if((xs->gathered+ep-p) > MAX_HOLD)
  554.                             {
  555.                                 /* we will never find it */
  556.                                 xs->state = xbm_error;
  557.                             }
  558.                             else
  559.                             {
  560.                                 XP_MEMCPY(xs->hold+xs->gathered, p, ep-p);
  561.                                 xs->gathered += ep-p;
  562.                                 input_exhausted = TRUE;
  563.                             }
  564.                         }
  565.                         else
  566.                         {        /* found it */
  567.                             if(xs->gathered)
  568.                             {
  569.                                 XP_MEMCPY(xs->hold+xs->gathered, p, s-p+1);
  570.                                 q = xs->hold;
  571.                             }
  572.                             else
  573.                             {
  574.                                 q = p;
  575.                             }
  576.                             p = s+1;
  577.                             xs->gathered=0;
  578.                             xs->state=xs->gathers;
  579.                         }
  580.                     }
  581.  
  582.                     if(xs->gathern)
  583.                     {
  584.                         if( (ep - p) >= xs->gathern)
  585.                         {        /* there is enough */
  586.                             if(xs->gathered)
  587.                             {    /* finish a prior gather */
  588.                                 XP_MEMCPY(xs->hold+xs->gathered, p, xs->gathern);
  589.                                 q = xs->hold;
  590.                                 xs->gathered=0;
  591.                             }
  592.                             else
  593.                             {
  594.                                 q = p;
  595.                             }
  596.                             p += xs->gathern;
  597.                             xs->gathern=0;
  598.                             xs->state=xs->gathers;
  599.                         }
  600.                         else
  601.                         { 
  602.                             XP_MEMCPY(xs->hold+xs->gathered, p, ep-p);
  603.                             xs->gathered += ep-p;
  604.                             xs->gathern -= ep-p;
  605.                             input_exhausted = TRUE;
  606.                         }
  607.                     }
  608.                 }
  609.                 break;
  610.  
  611.             case xbm_done:
  612.                 il_partial(ic, 0, img_header->height, 0);
  613.                 return 0;
  614.  
  615.             case xbm_oom: 
  616.                 ILTRACE(1,("il:xbm: reached oom state"));
  617.                 return MK_OUT_OF_MEMORY;
  618.  
  619.             case xbm_error: 
  620.                 ILTRACE(2,("il:xbm: reached error state"));
  621.                 return MK_IMAGE_LOSSAGE;
  622.  
  623.             default: 
  624.                 ILTRACE(0,("il:xbm: unknown state %d", xs->state));
  625.                 XP_ASSERT(0);
  626.                 break;
  627.             }
  628.     }
  629.     return 0;
  630. }
  631.  
  632. void
  633. il_xbm_abort(il_container *ic)
  634. {
  635.     if (ic->ds) 
  636.     {
  637.         xbm_struct *xs = (xbm_struct*) ic->ds;
  638.         XP_FREE(xs);
  639.         ic->ds = 0;
  640.     }
  641. }
  642.  
  643. void
  644. il_xbm_complete(il_container *ic)
  645. {
  646.     il_xbm_abort(ic);
  647.     il_image_complete(ic);
  648.     il_frame_complete_notify(ic);
  649. }
  650.