home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / rexx / library2 / gbmrexx / gbm / gbmpcx.c < prev    next >
C/C++ Source or Header  |  1993-09-12  |  12KB  |  576 lines

  1. /*
  2.  
  3. GBMPCX.C  ZSoft PC Paintbrush support
  4.  
  5. Reads and writes 1,4,8 and 24 bit colour files.
  6.  
  7. */
  8.  
  9. /*...sincludes:0:*/
  10. #include <stdio.h>
  11. #include <ctype.h>
  12. #include <stddef.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <memory.h>
  16. #include <malloc.h>
  17. #ifdef AIX
  18. #include <unistd.h>
  19. #else
  20. #include <io.h>
  21. #endif
  22. #include <fcntl.h>
  23. #include <sys/types.h>
  24. #include <sys/stat.h>
  25. #include "standard.h"
  26. #include "gbm.h"
  27.  
  28. /*...vgbm\46\h:0:*/
  29. /*...e*/
  30.  
  31. /*...suseful:0:*/
  32. #define    low_byte(w)    ((byte)  ((w)&0x00ff)    )
  33. #define    high_byte(w)    ((byte) (((w)&0xff00)>>8))
  34. #define    make_word(a,b)    (((word)a) + (((word)b) << 8))
  35. /*...e*/
  36. /*...ssame:0:*/
  37. static BOOLEAN same(char *s1, char *s2, int n)
  38.     {
  39.     for ( ; n--; s1++, s2++ )
  40.         if ( tolower(*s1) != tolower(*s2) )
  41.             return ( FALSE );
  42.     return ( TRUE );
  43.     }
  44. /*...e*/
  45. /*...sfind_word:0:*/
  46. static char *find_word(char *str, char *substr)
  47.     {
  48.     char    buf [100+1], *s;
  49.     int    len = strlen(substr);
  50.  
  51.     for ( s  = strtok(strcpy(buf, str), " \t,");
  52.           s != NULL;
  53.           s  = strtok(NULL, " \t,") )
  54.         if ( same(s, substr, len) && s [len] == '\0' )
  55.             return ( str + (s - buf) );
  56.     return ( NULL );
  57.     }
  58. /*...e*/
  59. /*...sreading ahead:0:*/
  60. #define    AHEAD_BUF    0x4000
  61.  
  62. typedef struct
  63.     {
  64.     byte    buf [AHEAD_BUF];
  65.     int    inx, cnt;
  66.     int    fd;
  67.     } AHEAD;
  68.  
  69. static AHEAD *create_ahead(int fd)
  70.     {
  71.     AHEAD *ahead;
  72.  
  73.     if ( (ahead = malloc(sizeof(AHEAD))) == NULL )
  74.         return ( NULL );
  75.  
  76.     ahead -> inx = 0;
  77.     ahead -> cnt = 0;
  78.     ahead -> fd  = fd;
  79.  
  80.     return ( ahead );
  81.     }
  82.  
  83. static void destroy_ahead(AHEAD *ahead)
  84.     {
  85.     free(ahead);
  86.     }    
  87.  
  88. static byte next(AHEAD *ahead)
  89.     {
  90.     if ( ahead -> inx >= ahead -> cnt )
  91.         {
  92.         ahead -> cnt = read(ahead -> fd, (char *) ahead -> buf, AHEAD_BUF);
  93.         ahead -> inx = 0;
  94.         }
  95.     return ( ahead -> buf [ahead -> inx++] );
  96.     }
  97. /*...e*/
  98.  
  99. static GBMFT pcx_gbmft =
  100.     {
  101.     "PCX",
  102.     "ZSoft PC Paintbrush Image format",
  103.     "PCX",
  104.     GBM_FT_R1|GBM_FT_R4|GBM_FT_R8|GBM_FT_R24|
  105.     GBM_FT_W1|GBM_FT_W4|GBM_FT_W8|GBM_FT_W24,
  106.     };
  107.  
  108. #define    GBM_ERR_PCX_BAD_VERSION    ((GBM_ERR) 700)
  109. #define    GBM_ERR_PCX_BAD_ENCMODE    ((GBM_ERR) 701)
  110. #define    GBM_ERR_PCX_BAD_BITS    ((GBM_ERR) 702)
  111. #define    GBM_ERR_PCX_BAD_TRAILER    ((GBM_ERR) 703)
  112.  
  113. typedef struct
  114.     {
  115.     byte version, bpppp, planes;
  116.     int bytes_per_line;
  117.     BOOLEAN    trunc;
  118.     } PCX_PRIV;
  119.  
  120. /*...spcx_qft:0:*/
  121. GBM_ERR pcx_qft(GBMFT *gbmft)
  122.     {
  123.     *gbmft = pcx_gbmft;
  124.     return ( GBM_ERR_OK );
  125.     }
  126. /*...e*/
  127. /*...spcx_rhdr:0:*/
  128. GBM_ERR pcx_rhdr(char *fn, int fd, GBM *gbm, char *opt)
  129.     {
  130.     PCX_PRIV *pcx_priv = (PCX_PRIV *) gbm -> priv;
  131.     byte    hdr [70];
  132.     word    x1, y1, x2, y2;
  133.     int    w, h, bpp;
  134.  
  135.     fn=fn; /* Suppress 'unref arg' compiler warning */
  136.  
  137.     pcx_priv -> trunc = ( find_word(opt, "trunc" ) != NULL );
  138.  
  139.     lseek(fd, 0L, SEEK_SET);
  140.     
  141.     read(fd, hdr, 70);
  142.     if ( hdr [0] != 0x0a )
  143.         return ( GBM_ERR_BAD_MAGIC );
  144.     pcx_priv -> version = hdr [1];
  145.     if ( pcx_priv -> version == 4 || pcx_priv -> version > 5 )
  146.         return ( GBM_ERR_PCX_BAD_VERSION );
  147.     if ( hdr [2] != 1 )
  148.         return ( GBM_ERR_PCX_BAD_ENCMODE );
  149.  
  150.     pcx_priv -> bpppp = hdr [3]; pcx_priv -> planes = hdr [65];
  151. #define    SWITCH2(a,b)    (((a)<<8)|(b))
  152.     switch ( SWITCH2(pcx_priv -> bpppp, pcx_priv -> planes) )
  153.         {
  154.         case SWITCH2(1,1): bpp =  1; break;
  155.         case SWITCH2(4,1): bpp =  4; break;
  156.         case SWITCH2(8,1): bpp =  8; break;
  157.         case SWITCH2(8,3): bpp = 24; break; /* Extended 24 bit style */
  158.         case SWITCH2(1,4): bpp =  4; break; /* EGA RGBI style */
  159.         default: return ( GBM_ERR_PCX_BAD_BITS );
  160.         }
  161.  
  162.     x1 = make_word(hdr [ 4], hdr [ 5]);
  163.     y1 = make_word(hdr [ 6], hdr [ 7]);
  164.     x2 = make_word(hdr [ 8], hdr [ 9]);
  165.     y2 = make_word(hdr [10], hdr [11]);
  166.  
  167.     w = x2 - x1 + 1;
  168.     h = y2 - y1 + 1;
  169.  
  170.     if ( w <= 0 || h <= 0 )
  171.         return ( GBM_ERR_BAD_SIZE );
  172.  
  173.     pcx_priv -> bytes_per_line = make_word(hdr [66], hdr [67]);
  174.  
  175.     gbm -> w   = w;
  176.     gbm -> h   = h;
  177.     gbm -> bpp = bpp;
  178.  
  179.     return ( GBM_ERR_OK );
  180.     }
  181. /*...e*/
  182. /*...spcx_rpal:0:*/
  183. GBM_ERR pcx_rpal(int fd, GBM *gbm, GBMRGB *gbmrgb)
  184.     {
  185.     switch ( gbm -> bpp )
  186.         {
  187. /*...s1 \45\ fixed b\47\w palette:16:*/
  188. case 1:
  189.     gbmrgb [0].r = gbmrgb [0].g = gbmrgb [0].b = 0x00;
  190.     gbmrgb [1].r = gbmrgb [1].g = gbmrgb [1].b = 0xff;
  191.     break;
  192. /*...e*/
  193. /*...s4 \45\ read palette if 1 plane\44\ fix one if 4 plane RGBI:16:*/
  194. case 4:
  195.     /* Use inline palette */
  196.     {
  197.     byte    b [16*3];
  198.     int    i;
  199.  
  200.     lseek(fd, 16L, SEEK_SET);
  201.     read(fd, b, 16 * 3);
  202.     for ( i = 0; i < 16; i++ )
  203.         {
  204.         gbmrgb [i].r = b [i * 3 + 0];
  205.         gbmrgb [i].g = b [i * 3 + 1];
  206.         gbmrgb [i].b = b [i * 3 + 2];
  207.         }
  208.     }
  209.     break;
  210. /*...e*/
  211. /*...s8 \45\ read palette from end of file:16:*/
  212. case 8:
  213.     {
  214.     byte    trailer_id;
  215.     byte    b [0x100*3];
  216.     int    i;
  217.  
  218.     lseek(fd, -0x301L, SEEK_END);
  219.     read(fd, &trailer_id, 1);
  220.     if ( trailer_id != 0x0c )
  221.         return ( GBM_ERR_PCX_BAD_TRAILER );
  222.  
  223.     read(fd, b, 0x100 * 3);
  224.     for ( i = 0; i < 0x100; i++ )
  225.         {
  226.         gbmrgb [i].r = b [i * 3 + 0];
  227.         gbmrgb [i].g = b [i * 3 + 1];
  228.         gbmrgb [i].b = b [i * 3 + 2];
  229.         }
  230.     }
  231.     break;
  232. /*...e*/
  233.         }
  234.     return ( GBM_ERR_OK );
  235.     }
  236. /*...e*/
  237. /*...spcx_rdata:0:*/
  238. /*...sread_pcx_line:0:*/
  239. static void read_pcx_line(
  240.     AHEAD *ahead, byte *line, int bytes_per_line,
  241.     byte *runleft, byte *runval
  242.     )
  243.     {
  244.     /* Handle left overs from previous line */
  245.  
  246.     while ( *runleft > 0 && bytes_per_line > 0 )
  247.         {
  248.         *line++ = *runval;
  249.         (*runleft)--;
  250.         bytes_per_line--;
  251.         }
  252.  
  253.     /* Normal code */
  254.  
  255.     while ( bytes_per_line )
  256.         {
  257.         byte    b1 = next(ahead);
  258.  
  259.         if ( (b1 & 0xc0) == 0xc0 )
  260.             {
  261.             byte    b2 = next(ahead);
  262.  
  263.             b1 &= 0x3f;
  264.             if ( b1 > bytes_per_line )
  265.                 {
  266.                 (*runleft) = (byte) (b1 - bytes_per_line);
  267.                 (*runval) = b2;
  268.                 b1 = bytes_per_line;
  269.                 }
  270.             memset(line, b2, b1);
  271.             line += b1;
  272.             bytes_per_line -= b1;
  273.             }
  274.         else
  275.             {
  276.             *line++ = b1;
  277.             bytes_per_line--;
  278.             }
  279.         }
  280.     }
  281. /*...e*/
  282. /*...sspread:0:*/
  283. static void spread(byte b, byte bit_to_set, byte *dest)
  284.     {
  285.     if ( b & 0x80 ) dest [0] |= (bit_to_set & 0xf0);
  286.     if ( b & 0x40 ) dest [0] |= (bit_to_set & 0x0f);
  287.     if ( b & 0x20 ) dest [1] |= (bit_to_set & 0xf0);
  288.     if ( b & 0x10 ) dest [1] |= (bit_to_set & 0x0f);
  289.     if ( b & 0x08 ) dest [2] |= (bit_to_set & 0xf0);
  290.     if ( b & 0x04 ) dest [2] |= (bit_to_set & 0x0f);
  291.     if ( b & 0x02 ) dest [3] |= (bit_to_set & 0xf0);
  292.     if ( b & 0x01 ) dest [3] |= (bit_to_set & 0x0f);
  293.     }
  294. /*...e*/
  295.  
  296. GBM_ERR pcx_rdata(int fd, GBM *gbm, byte *data)
  297.     {
  298.     PCX_PRIV *pcx_priv = (PCX_PRIV *) gbm -> priv;
  299.     BOOLEAN    trunc = pcx_priv -> trunc;
  300.     int    bytes_per_line = pcx_priv -> bytes_per_line;
  301.     int    stride, y;
  302.     byte    *line;
  303.     AHEAD    *ahead;
  304.     byte    runleft = 0, runval;
  305.  
  306.     if ( (ahead = create_ahead(fd)) == NULL )
  307.         return ( GBM_ERR_MEM );
  308.  
  309.     lseek(fd, 128L, SEEK_SET);
  310.  
  311.     if ( (line = malloc(bytes_per_line)) == NULL )
  312.         {
  313.         destroy_ahead(ahead);
  314.         return ( GBM_ERR_MEM );
  315.         }
  316.  
  317.     switch ( gbm -> bpp )
  318.         {
  319. /*...s1:16:*/
  320. case 1:
  321.     stride = ((gbm -> w + 31) / 32) * 4;
  322.     for ( y = gbm -> h - 1; y >= 0; y-- )
  323.         {
  324.         read_pcx_line(ahead, data + y * stride, bytes_per_line, &runleft, &runval);
  325.         if ( trunc )
  326.             runleft = 0;
  327.         }
  328.     break;
  329. /*...e*/
  330. /*...s4:16:*/
  331. case 4:
  332.     stride = ((gbm -> w * 4 + 31) / 32) * 4;
  333.     if ( pcx_priv -> planes == 1 )
  334.         for ( y = gbm -> h - 1; y >= 0; y-- )
  335.             {
  336.             read_pcx_line(ahead, data + y * stride, bytes_per_line, &runleft, &runval);
  337.             if ( trunc )
  338.                 runleft = 0;
  339.             }
  340.     else
  341.         {
  342.         int    p, x;
  343.         int    bytes = (gbm -> w / 8);
  344.         int    bits  = (gbm -> w & 7);
  345.  
  346.         memset(data, 0, gbm -> h * stride);
  347.         for ( y = gbm -> h - 1; y >= 0; y-- )
  348.             for ( p = 0x11; p <= 0x88 ; p <<= 1 )
  349.                 {
  350.                 byte    *dest = data + y * stride;
  351.  
  352.                 read_pcx_line(ahead, line, bytes_per_line, &runleft, &runval);
  353.                 if ( trunc )
  354.                     runleft = 0;
  355.                 for ( x = 0; x < bytes; x++, dest += 4 )
  356.                     spread(line [x], p, dest);
  357.                 if ( bits )
  358.                     spread((byte) (line [x] & (0xff00 >> bits)), p, dest);
  359.                 }
  360.         }
  361.     break;
  362. /*...e*/
  363. /*...s8:16:*/
  364. case 8:
  365.     stride = ((gbm -> w + 3) & ~3);
  366.     for ( y = gbm -> h - 1; y >= 0; y-- )
  367.         {
  368.         read_pcx_line(ahead, data + y * stride, bytes_per_line, &runleft, &runval);
  369.         if ( trunc )
  370.             runleft = 0;
  371.         }
  372.     break;
  373. /*...e*/
  374. /*...s24:16:*/
  375. case 24:
  376.     {
  377.     int    p, x;
  378.  
  379.     stride = ((gbm -> w * 3 + 3) & ~3);
  380.     for ( y = gbm -> h - 1; y >= 0; y-- )
  381.         for ( p = 2; p >= 0; p-- )
  382.             {
  383.             read_pcx_line(ahead, line, bytes_per_line, &runleft, &runval);
  384.             if ( trunc )
  385.                 runleft = 0;
  386.             for ( x = 0; x < gbm -> w; x++ )
  387.                 data [y * stride + p + x * 3] = line [x];
  388.             }
  389.     }
  390.     break;
  391. /*...e*/
  392.         }
  393.  
  394.     free(line);
  395.  
  396.     destroy_ahead(ahead);
  397.  
  398.     return ( GBM_ERR_OK );
  399.     }
  400. /*...e*/
  401. /*...spcx_w:0:*/
  402. /*...spcx_rle:0:*/
  403. static byte pcx_run(byte *src, int n_src)
  404.     {
  405.     byte    cnt = 1;
  406.     byte    b = *src++;
  407.  
  408.     --n_src;
  409.     while ( cnt < 0x3f && n_src > 0 && *src == b )
  410.         { cnt++; n_src--; src++; }
  411.  
  412.     return ( cnt );
  413.     }
  414.  
  415. static void pcx_rle(byte *src, int n_src, byte *dst, int *n_dst)
  416.     {
  417.     *n_dst = 0;    
  418.     while ( n_src )
  419.         {
  420.         byte    len;
  421.  
  422.         if ( (len = pcx_run(src, n_src)) > 1 || (*src & 0xc0) == 0xc0 )
  423.             {
  424.             *dst++ = (byte) (0xc0 | len);
  425.             *dst++ = *src;
  426.             (*n_dst) += 2;
  427.             }
  428.         else
  429.             {
  430.             *dst++ = *src;
  431.             (*n_dst)++;
  432.             }
  433.         src += len;
  434.         n_src -= len;
  435.         }
  436.     }
  437. /*...e*/
  438.  
  439. GBM_ERR pcx_w(char *fn, int fd, GBM *gbm, GBMRGB *gbmrgb, byte *data, char *opt)
  440.     {
  441.     int i, y, stride = ((gbm -> bpp * gbm -> w + 31) / 32) * 4;
  442.     byte *line;
  443.     byte hdr [128];
  444.     int bytes_per_line, cnt;
  445.  
  446.     fn=fn; opt=opt; /* Suppress 'unref arg' compiler warning */
  447.  
  448.     memset(hdr, 0, 128);
  449.     hdr [ 0] = 0x0a;            /* Magic # */
  450.     hdr [ 1] = 5;                /* Version 5 */
  451.     hdr [ 2] = 1;                /* RLE compression */
  452.     hdr [ 3] = (byte) ( ( gbm -> bpp == 24 ) ? 8 : gbm -> bpp );
  453.                         /* Bits per plane */
  454.     hdr [ 4] = low_byte(0);
  455.     hdr [ 5] = high_byte(0);        /* Top left x */
  456.     hdr [ 6] = low_byte(0);
  457.     hdr [ 7] = high_byte(0);        /* Top left y */
  458.     hdr [ 8] = low_byte(gbm -> w - 1);
  459.     hdr [ 9] = high_byte(gbm -> w - 1);    /* Bottom right x */
  460.     hdr [10] = low_byte(gbm -> h - 1);
  461.     hdr [11] = high_byte(gbm -> h - 1);    /* Bottom right y */
  462.     hdr [12] = low_byte(0);
  463.     hdr [13] = high_byte(0);        /* Horizontal resolution ??? */
  464.     hdr [14] = low_byte(0);
  465.     hdr [15] = high_byte(0);        /* Vertical resolution ??? */
  466.  
  467.     if ( gbm -> bpp == 4 )
  468.         for ( i = 0; i < 16; i++ )
  469.             {
  470.             hdr [16 + i * 3    ] = gbmrgb [i].r;
  471.             hdr [16 + i * 3 + 1] = gbmrgb [i].g;
  472.             hdr [16 + i * 3 + 2] = gbmrgb [i].b;
  473.             }
  474.  
  475.     hdr [65] = (byte) ( ( gbm -> bpp == 24 ) ? 3 : 1 );
  476.                         /* Planes */
  477.     bytes_per_line = (gbm -> w * hdr [3] + 7) / 8;
  478.     if ( bytes_per_line & 1 )
  479.         bytes_per_line++;
  480.     hdr [66] = low_byte(bytes_per_line);
  481.     hdr [67] = high_byte(bytes_per_line);
  482.     hdr [68] = 1;                /* Colour or b/w */
  483.  
  484.     write(fd, hdr, 128);
  485.  
  486.     if ( (line = malloc(bytes_per_line * 2)) == NULL )
  487.         return ( GBM_ERR_MEM );
  488.  
  489.     switch ( gbm -> bpp )
  490.         {
  491. /*...s1\44\4\44\8:16:*/
  492. case 1:
  493. case 4:
  494. case 8:
  495.     for ( y = gbm -> h - 1; y >= 0; y-- )
  496.         {
  497.         pcx_rle(data + y * stride, bytes_per_line, line, &cnt);
  498.         if ( write(fd, line, cnt) != cnt )
  499.             {
  500.             free(line);
  501.             return ( GBM_ERR_WRITE );
  502.             }
  503.         }
  504.     break;
  505. /*...e*/
  506. /*...s24:16:*/
  507. case 24:
  508.     {
  509.     byte    *line2;
  510.     int    p, x;
  511.  
  512.     if ( (line2 = malloc(bytes_per_line)) == NULL )
  513.         {
  514.         free(line);
  515.         return ( GBM_ERR_MEM );
  516.         }
  517.  
  518.     for ( y = gbm -> h - 1; y >= 0; y-- )
  519.         for ( p = 2; p >= 0; p-- )
  520.             {
  521.             byte    *src = data + y * stride;
  522.  
  523.             for ( x = 0; x < gbm -> w; x++ )
  524.                 line2 [x] = src [x * 3 + p];
  525.  
  526.             pcx_rle(line2, bytes_per_line, line, &cnt);
  527.             if ( write(fd, line, cnt) != cnt )
  528.                 {
  529.                 free(line2);
  530.                 free(line);
  531.                 return ( GBM_ERR_WRITE );
  532.                 }
  533.             }
  534.     free(line2);
  535.     }
  536.     break;
  537. /*...e*/
  538.         }
  539.  
  540.     free(line);
  541.  
  542.     if ( gbm -> bpp == 8 )
  543.         {
  544.         byte    pal [1 + 0x100 * 3];
  545.  
  546.         pal [0] = 0x0c;
  547.         for ( i = 0; i < 0x100; i++ )
  548.             {
  549.             pal [i * 3 + 1] = gbmrgb [i].r;
  550.             pal [i * 3 + 2] = gbmrgb [i].g;
  551.             pal [i * 3 + 3] = gbmrgb [i].b;
  552.             }
  553.         write(fd, pal, 1 + 0x100 * 3);
  554.         }
  555.  
  556.     return ( GBM_ERR_OK );
  557.     }
  558. /*...e*/
  559. /*...spcx_err:0:*/
  560. char *pcx_err(GBM_ERR rc)
  561.     {
  562.     switch ( (int) rc )
  563.         {
  564.         case GBM_ERR_PCX_BAD_VERSION:
  565.             return ( "version number not 4 or 5" );
  566.         case GBM_ERR_PCX_BAD_ENCMODE:
  567.             return ( "encoding mode not 1" );
  568.         case GBM_ERR_PCX_BAD_BITS:
  569.             return ( "unsupported bpp/plane / plane combination" );
  570.         case GBM_ERR_PCX_BAD_TRAILER:
  571.             return ( "corrupt file trailer" );
  572.         }
  573.     return ( NULL );
  574.     }
  575. /*...e*/
  576.