home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / msdos / viewers / pcxut10 / pcxutils.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-08  |  18.2 KB  |  500 lines

  1. /* A few simple conversions for monochrome & 16-color PCX files
  2.  
  3.    PCXUTILS is meant to deal with pcx-files produced by DrawPerfect,
  4.    WP Presentations, Harvard Graphics and GhostScript.
  5.    Output should be usable for WordPerfect and TeX.
  6.    Problems which occur with these programs:
  7.    - GhostScript doesn't always produce an even n. of bytes
  8.    - Harvard Graphics does something funny with the palette
  9.    - WordPerfect and some other programs seem to compute bytes/line from
  10.      image width instead of reading it directly from the header
  11.    - Many graphics programs can't produce monochrome bitmaps, causing
  12.      unnecessarily large filesizes
  13.  
  14.    PCXUTILS does the following:
  15.    /i:  invert
  16.    /m:  color to monochrome: every non-white color becomes black;
  17.         use this option only when the bitmap has a standard palette
  18.         apply successive /i /m /i transformations if you want
  19.         to map every non-black color to white
  20.    /r:  round image size up to even n. of bytes per line
  21.    /p+: standardize palette by interpreting existing palette; equivalent to /p
  22.    /p-: standardize palette and ignore existing palette
  23.    Only the first switch is honored.
  24.    Irrespective of options:
  25.    - round bytes/line up to even number (irrespective of image size)
  26.    - reduce bytes/line to smallest possible number
  27.  
  28.    Compiler: Turbo C++ 3.0
  29. */
  30.  
  31. /* standard header files */
  32. #include <stdio.h>
  33. #include <string.h>
  34. #include <stdlib.h>
  35. #include <alloc.h>
  36. #include <dos.h>
  37. #include <dir.h>
  38. #include <errno.h>
  39.  
  40. #define FALSE 0
  41. #define TRUE 1
  42. #define LOBYTE(x) (*(unsigned char *)&(x))
  43. #define HIBYTE(x) (*(((unsigned char *)&(x))+1))
  44.  
  45. void errexit0 (char *message);
  46. void errexit1 (char *message);
  47.  
  48. int prcount, swcount, parinx, swinx;
  49. void cmdline(void); /* find command-line switch and parameter */
  50.  
  51. void helpinfo(void);
  52. void make_palette(void);
  53.  
  54. /* PCX file header */
  55. typedef struct
  56. { char manufacturer;
  57.   char version;
  58.   char encoding;
  59.   char bits_per_pixel;
  60.   int  xmin,ymin;
  61.   int  xmax,ymax;
  62.   int  hres,vres;
  63.   unsigned char palette[48];
  64.   char reserved;
  65.   char color_planes;
  66.   int  bytes_per_line;
  67.   int  palette_type;
  68.   char filler[58];
  69. } PCXHEAD;
  70.  
  71. PCXHEAD header;
  72.  
  73. /* The following typedefs and data make it possible to determine
  74.    pixel values without actual unpacking */
  75. typedef union
  76. { unsigned long l;
  77.   unsigned char c[4];
  78. } MASK; /* for each colorplane one byte */
  79. typedef MASK MASKARRAY[8];
  80. MASKARRAY masks; /* masks to isolate each pixel for each bit position */
  81. MASKARRAY maskpalette[16]; /* (color code, bit position) -> MASK */
  82. MASKARRAY newpalette[16]; /* (new color code, bit position) -> MASK */
  83.  
  84. /* available processing options */
  85. enum options { opt_tomono, opt_round, opt_invert, opt_pal_ignore,
  86.   opt_pal_arrng, opt_none };
  87. int pr_opt; /* selected processing option */
  88.  
  89. FILE *in, *out;
  90.  
  91. /* properties input file: */
  92. int old_bpl; /* old value for bytes_per_line */
  93. int bpl_tot; /* bytes per line times color planes */
  94. int old_width; /* old picture width */
  95. int monoin; /* input file is mono */
  96. int chg_bpl; /* bytes per line requires changing */
  97. int palet_funny; /* palette anomalies; implies !mono && header.version!=3 */
  98. char pcxpath[MAXPATH], oldpath[MAXPATH]; /* full filenames */
  99. char old_pal[48]; /* old palette */
  100. unsigned char *const hpal = (unsigned char *)&header.palette;
  101.   /* for easy reference to header palette */
  102. char const std_pal[48] = /* a more or less standard EGA palette */
  103. { 0x0,0x0,0x0,    0x0,0x0,0x80,  0x0,0x80,0x0,  0x0,0x80,0x80,
  104.   0x80,0x0,0x0,   0x80,0x0,0x80, 0x80,0x80,0x0, 0x80,0x80,0x80,
  105.   0x40,0x40,0x40, 0x0,0x0,0xff,  0x0,0xff,0x0,  0x0,0xff,0xff,
  106.   0xff,0x0,0x0,   0xff,0x0,0xff, 0xff,0xff,0x0, 0xff,0xff,0xff };
  107.  
  108. typedef unsigned char *LINE;
  109. LINE plane[4]; /* up to 4 bitplanes, yet to be allocated */
  110. unsigned char *pl; /* pointer into plane */
  111.  
  112. void main (int argc, char *argv[])
  113.  
  114. { int c,i,j,k,l;
  115.   union { unsigned char ch[2]; unsigned int intg; } endmask;
  116.   MASK eachplane; /* one byte from each plane */
  117.   MASK thispixel;
  118.   cmdline();
  119.   if (prcount>1) puts ("Excess command-line parameters ignored");
  120.   if (swcount>1) puts ("Excess command-line switches ignored");
  121.  
  122.   /* header input file */
  123.   if (prcount<1) helpinfo();
  124.   { char fndrive[MAXDRIVE];
  125.     char fndir[MAXDIR];
  126.     char fnfile[MAXFILE];
  127.     fnsplit
  128.       (argv[parinx],(char *)fndrive,(char *)fndir,(char *)fnfile,NULL);
  129.     fnmerge (pcxpath,(char *)fndrive,(char *)fndir,(char *)fnfile,".PCX");
  130.     fnmerge (oldpath,(char *)fndrive,(char *)fndir,(char *)fnfile,".OLD");
  131.   }
  132.   in = fopen (pcxpath,"rb");
  133.   if (!in) errexit0("Access failure input file");
  134.   if (fread((char *)&header,1,sizeof(PCXHEAD),in)!=sizeof(PCXHEAD))
  135.     errexit0("Failure to read PCX file");
  136.   fclose(in); /* later, we reopen the file as *.old */
  137.   if (header.manufacturer!=0x0a) errexit0("Not a PCX file");
  138.   if (header.bits_per_pixel!=1) errexit0("Format not supported");
  139.     /* this might be changed later on */
  140.   if (header.color_planes==1) monoin = TRUE;
  141.   else if (header.color_planes==4) monoin = FALSE;
  142.   else errexit0("Format not supported");
  143.  
  144.   /* standard palette: 1rst color 0,0,0 last ff,ff,ff; all colors different */
  145.   palet_funny=FALSE;
  146.   memmove(old_pal,header.palette,48);
  147.   if (header.version!=3 && !monoin)
  148.   { for (i=0;i<3;i++) if (header.palette[i]!=0)
  149.       { palet_funny=TRUE; break; }
  150.     if (!palet_funny) for (i=45;i<48;i++) if (header.palette[i]!=255)
  151.       { palet_funny=TRUE; break; }
  152.     if (!palet_funny) for (i=0;i<48;i+=3) /* entries all different? */
  153.       { for (j=0;j<i;j+=3)
  154.           if (old_pal[i]==old_pal[j]
  155.            && old_pal[i+1]==old_pal[j+1]
  156.            && old_pal[i+2]==old_pal[j+2]) { palet_funny=TRUE; break; }
  157.         if (palet_funny) break;
  158.       }
  159.   }
  160.  
  161.   /* image width and bytes_per_line */
  162.   old_width=header.xmax-header.xmin+1;
  163.   if (old_width<=0 || header.ymax<header.ymin)
  164.     errexit0("Error: Picture has zero height or width");
  165.   old_bpl = header.bytes_per_line;
  166.   chg_bpl = (old_bpl%2) || (old_bpl*8-old_width*header.bits_per_pixel>15);
  167.  
  168.   in = NULL; out = NULL;
  169.  
  170.   /* decode switch; start comparing after first character ('/' or '-') */
  171.   pr_opt = opt_none;
  172.   if (swcount>0)
  173.   { if (!stricmp(argv[swinx]+1,"r")) pr_opt = opt_round;
  174.     else if (!stricmp(argv[swinx]+1,"i")) pr_opt = opt_invert;
  175.     else if (!stricmp(argv[swinx]+1,"m")) pr_opt = opt_tomono;
  176.     else if (!stricmp(argv[swinx]+1,"p+")||
  177.              !stricmp(argv[swinx]+1,"p")) pr_opt = opt_pal_arrng;
  178.     else if (!stricmp(argv[swinx]+1,"p-")) pr_opt = opt_pal_ignore;
  179.     else helpinfo();
  180.   }
  181.  
  182.   /* sort out actions; report to user */
  183.  
  184.     /* comments on header */
  185.  
  186.   if (palet_funny && pr_opt!=opt_pal_ignore && pr_opt!=opt_pal_arrng)
  187.     puts("Non-standard palette;\n"
  188.       "if results unsatisfactory try a preliminary PCXUTILS /p run");
  189.   if (chg_bpl) puts ("Correcting bytes/line");
  190.  
  191.     /* options */
  192.  
  193.   if (pr_opt==opt_tomono)
  194.   { if (monoin) { puts("Bitmap already mono"); pr_opt = opt_none; }
  195.     else puts("Converting to monochrome");
  196.   }
  197.   else if (pr_opt==opt_round)
  198.   { if (old_width*header.bits_per_pixel==8*old_bpl && !chg_bpl)
  199.     { puts("Image width is already rounded to match bytes/line");
  200.       pr_opt = opt_none; }
  201.     else puts("Rounding image width");
  202.   }
  203.   else if (pr_opt==opt_invert) puts("Inverting colors");
  204.  
  205.   else if (pr_opt==opt_pal_ignore)
  206.   { if (monoin) { puts("Monochrome bitmap"); pr_opt = opt_none; }
  207.     else if (header.version==3)
  208.       puts("No palette; bitmap gets standard palette");
  209.     else if (!palet_funny) { puts("Palette ok"); pr_opt = opt_none; }
  210.     else puts("Bitmap gets standard palette; original palette ignored");
  211.   }
  212.  
  213.   else if (pr_opt==opt_pal_arrng)
  214.   { if (monoin) { puts("Monochrome bitmap"); pr_opt = opt_none; }
  215.     else if (header.version==3)
  216.     { pr_opt = opt_pal_ignore;
  217.       puts("No palette; bitmap gets standard palette");
  218.     }
  219.     else if (!palet_funny) { puts("Palette ok"); pr_opt = opt_none; }
  220.     else puts("Palette will be standardized by rearranging original palette");
  221.   }
  222.   /* else pr_opt==opt_none */
  223.  
  224.   if (pr_opt==opt_none && !chg_bpl) { puts("Nothing to do"); exit(0); }
  225.   fputs("Transforming ",stdout); puts(pcxpath);
  226.   fputs("Original file will be copied to ",stdout); puts(oldpath);
  227.  
  228.   /* get confirmation */
  229.   { fputs("Continue y/n? [y]",stdout);
  230.     for (;;)
  231.     { c = getc(stdin);
  232.       if (c=='n'||c=='N') exit(0);
  233.       else if (c=='j'||c=='J'||c=='y'||c=='Y'||c=='\n') break;
  234.     }
  235.     putchar('\n');
  236.   }
  237.  
  238.   /* edit header; we already saved essential old info
  239.      in old_bpl, old_pal, old_width and monoin */
  240.   
  241.   header.hres=header.vres=300;
  242.   header.palette_type %= 2; /* 1==color/BW; 2==gray */
  243.   if (pr_opt==opt_pal_ignore) memmove(header.palette,std_pal,48);
  244.   if (pr_opt==opt_pal_arrng) make_palette();
  245.   if (pr_opt==opt_pal_ignore || pr_opt==opt_pal_arrng) header.version = 5;
  246.  
  247.   if (chg_bpl) /* correct header.bytes_per_line */
  248.   { if (old_bpl%2) header.bytes_per_line++; /* even n. of bytes per line */
  249.     while (8*header.bytes_per_line-old_width*header.bits_per_pixel>15)
  250.       header.bytes_per_line-=2;
  251.   }
  252.  
  253.   /* offset window (0,0); round picture width */
  254.   header.xmax=header.xmax-header.xmin; header.xmin=0;
  255.   header.ymax=header.ymax-header.ymin; header.ymin=0;
  256.   if (pr_opt==opt_round)
  257.     header.xmax=8*header.bytes_per_line/header.bits_per_pixel-1;
  258.  
  259.   if (pr_opt==opt_tomono) header.color_planes=1; /* color or mono */
  260.   if (pr_opt==opt_tomono||monoin)
  261.     { hpal[0]=hpal[1]=hpal[2]=0; hpal[3]=hpal[4]=hpal[5]=0xff; }
  262.  
  263.   /* invert: interchange and invert palette entries */
  264.   if (pr_opt==opt_invert)
  265.   { unsigned char tmp;
  266.     for (i=0,j=45;i<48;i+=3,j-=3) for (k=0;k<3;k++)
  267.       { tmp=hpal[i+k]; hpal[i+k]=~hpal[j+k]; hpal[j+k]=~tmp; }
  268.   }
  269.  
  270.   /* NOTE. Some cases only require changing the header.
  271.      However, we unpack and repack the bitmap in all cases.
  272.   */
  273.  
  274.   /* rename and reopen input file; open output file */
  275.   if (unlink(oldpath)) if (errno!=ENOENT)
  276.     errexit0("Failure to rename input file");
  277.   if (rename(pcxpath,oldpath)) errexit0("Failure to rename input file");
  278.   in = fopen (oldpath,"rb");
  279.   if (!in) errexit1("Failure to open renamed input file");
  280.   out = fopen (pcxpath,"wb");
  281.   if (!out) errexit1("Failure to open output file");
  282.  
  283.   /* write edited header to output; skip input header */
  284.   if (fwrite(&header,1,sizeof(PCXHEAD),out)!=sizeof(PCXHEAD))
  285.     errexit1("Write failure");
  286.   if (fseek(in,sizeof(PCXHEAD),SEEK_SET)) errexit1("Read failure");
  287.  
  288.   /* Allocate line buffer.
  289.      When reading, we unpack planes contiguously and only refer to plane[0].
  290.      Therefore, we set plane[1..3] now as required for output
  291.   */
  292.   k = (old_bpl<=header.bytes_per_line)?header.bytes_per_line:old_bpl;
  293.   plane[0]=malloc(k*(monoin?1:4));
  294.   if (!plane[0]) errexit1("Out of memory");
  295.   if (!monoin)
  296.     for (i=1;i<4;i++) plane[i]=&(plane[i-1][header.bytes_per_line]);
  297.  
  298.   /* Make mask to set strip at right to white. Recall that within one byte,
  299.      the most significant bits represent the leftmost pixels */
  300.   k=8*header.bytes_per_line-header.xmax-1;
  301.   endmask.intg=0;
  302.   if (k<8) i=1; /* left byte 0 */
  303.   else {k-=8; endmask.ch[1]=0xff; i=0;} /* set right byte 0xff; 8 bits done */
  304.   for (;k>0;k--) endmask.ch[i]=0x01|(endmask.ch[i]<<1);
  305.  
  306.   /* now reading, converting and writing data */
  307.   for (j=header.ymin;j<=header.ymax;j++)
  308.   { pl = plane[0];
  309.     bpl_tot = old_bpl*(monoin?1:4);
  310.     for (;pl<plane[0]+bpl_tot;) /* decompress RLE-compressed data */
  311.     { c = fgetc(in) & 0xff;
  312.       if ((c&0xc0)==0xc0) /* run length */
  313.       { i=c&0x3f;
  314.         c=fgetc(in); /* run byte */
  315.         memset(pl,LOBYTE(c),i); pl += i;
  316.       }
  317.       else *(pl++)=c;
  318.     }
  319.     /* adjusting bytes per line */
  320.     if (chg_bpl&&!monoin)
  321.     { if (header.bytes_per_line>old_bpl) for (i=3;i>0;i--)
  322.         memmove(plane[0]+i*header.bytes_per_line,plane[0]+i*old_bpl,old_bpl);
  323.       else for (i=1;i<4;i++)
  324.         memmove(plane[0]+i*header.bytes_per_line,plane[0]+i*old_bpl,old_bpl);
  325.     }
  326.     bpl_tot = header.bytes_per_line*(monoin?1:4);
  327.  
  328.     /* now requested transformation */
  329.  
  330.     /* inverting */
  331.     if (pr_opt==opt_invert)
  332.     { pl = plane[0];
  333.       for (i=0;i<bpl_tot;i++,pl++) *pl = ~(*pl);
  334.     }
  335.  
  336.     /* adjusting palette */
  337.     else if (pr_opt==opt_pal_arrng)
  338.     { for (i=0;i<header.bytes_per_line;i++)
  339.       { /* combine bitplanes */
  340.         for (k=0;k<4;k++) eachplane.c[k]=plane[k][i];
  341.         /* process color of each of eight pixels */
  342.         for (k=0;k<8;k++)
  343.         { thispixel.l = eachplane.l&masks[k].l;
  344.           for (l=0;l<16;l++) if (thispixel.l==maskpalette[l][k].l) break;
  345.           if (l==16) errexit1 ("System error; please report");
  346.           eachplane.l=(eachplane.l&~(masks[k].l))|newpalette[l][k].l;
  347.         }
  348.         /* redivide info over bitplanes */
  349.         for (k=0;k<4;k++) plane[k][i]=eachplane.c[k];
  350.       }
  351.     }
  352.  
  353.     /* converting to monochrome */
  354.     else if (pr_opt==opt_tomono) for (i=0;i<header.bytes_per_line;i++)
  355.       plane[0][i]=plane[0][i]&plane[1][i]&plane[2][i]&plane[3][i];
  356.  
  357.     /* Remaining cases opt_round and opt_pal_ignore: no action.
  358.        Make right strip white by or-ing with endmask */
  359.  
  360.     if (header.xmax+1<8*header.bytes_per_line)
  361.       for (k=0;k<header.color_planes;k++)
  362.         { plane[k][header.bytes_per_line-2]|=endmask.ch[0];
  363.           plane[k][header.bytes_per_line-1]|=endmask.ch[1];
  364.         }
  365.  
  366.     /* Compress and write. We compress each color plane separately,
  367.        although this probably isn't necessary */
  368.     for (k=0;k<header.color_planes;k++)
  369.     { pl=plane[k];
  370.       while (pl<(plane[k]+header.bytes_per_line))
  371.       { for (i=1;pl[i-1]==pl[i]&&i<63
  372.                 &&(pl+i)<(plane[k]+header.bytes_per_line);i++);
  373.         /* now pl[0]==pl[i-1], i<=63 and pl[i-1] belongs to plane[k] */
  374.         if (i!=1||pl[0]>=0xc) /* run */
  375.         { if (fputc(0xc0|i,out)==EOF) errexit1("Write failure");
  376.           if (fputc(pl[0],out)==EOF) errexit1("Write failure");
  377.           pl+=i;
  378.         }
  379.         else { if (fputc(pl[0],out)==EOF) errexit1("Write failure"); pl++; }
  380.       }
  381.     }
  382.   } /* for j=ymin..ymax */
  383.   fclose(out); fclose(in);
  384. }
  385.  
  386. void errexit0 (char *message)
  387. { if (in) fclose(in); puts(message); exit(1); }
  388.  
  389. /* after file.pcx is renamed to file.old, call the error exit below */
  390. void errexit1 (char *message)
  391. { if (out) { fclose(out); unlink(pcxpath); }
  392.   if (in) fclose(in); rename(oldpath,pcxpath);
  393.   errexit0(message);
  394. }
  395.  
  396. void helpinfo(void)
  397. { puts("Usage:");
  398.   puts("PCXUTILS [/i|/r|/n|/p|/p+|p-] filename");
  399.   puts("  filename.PCX is copied to filename.OLD"
  400.     " and replaced by a new version.");
  401.   puts("  /i for inverting");
  402.   puts("  /r for rounding image size up");
  403.   puts("  /m for conversion to monochrome");
  404.   puts("  /p, /p+ for standardizing palette"
  405.     " (interpret existing palette info)");
  406.   puts("  /p- for standardizing palette (ignore existing palette info)");
  407.   exit(0);
  408. }
  409.  
  410. void cmdline(void)
  411. /* command-line switches and parameters */
  412. { int i;
  413.   if (_argc<=1) {prcount=swcount=0; parinx=swinx=0;}
  414.   for (prcount=0,swcount=0,i=1;i<_argc;i++)
  415.   { if (_argv[i][0]=='-' || _argv[i][0]=='/')
  416.       { swcount+=1; if (swcount==1) swinx = i; }
  417.     else { prcount+=1; if (prcount==1) parinx = i; }
  418.   }
  419. }
  420.  
  421. void make_palette(void)
  422. /* create a palette which includes 0/0/0 and ff/ff/ff - at positions
  423. 0 and 15 resp., in which each color is unique and which contains, if
  424. possible, all colors of the original palette.
  425. */
  426. { unsigned int scr_pal[16], int_pal[32];
  427.   int pal_map[16]; /* mapping from old palette to new */
  428.   unsigned int i,j,k;
  429.   /* First, we construct a palette int_pal that contains all the original
  430.      colors, also black and white, and enough greys to be sure of at least
  431.      16 DIFFERENT colors. The new palette scr_pal will be picked from int_pal.
  432.      Thus, int_pal contains successively: black; white; old palette (= *hpal);
  433.      greys.
  434.      Colors are coded as single unsigned integers:
  435.      We only retain the most significant 4 bits of each color,
  436.      and consider those as hex digits of an unsigned integer */
  437.   int_pal[0]=0; int_pal[1]=0xfff;
  438.   for (i=0,j=0;i<16;i++) /* 2-17 */
  439.   { int_pal[i+2]=256*(hpal[j++]/16);
  440.     int_pal[i+2]+=16*(hpal[j++]/16);
  441.     int_pal[i+2]+=hpal[j++]/16;
  442.   }
  443.   /* 18-31: 14 greys in the above coding */
  444.   for (i=1;i<15;i++) int_pal[i+17]=0x111*i;
  445.   /* fill scratch palette scr_pal with unique colors from int_pal */
  446.   scr_pal[0]=0; scr_pal[1]=0xfff;
  447.   for (i=2,j=0;i<16;i++)
  448.   { /* find value for scr_pal[i], starting search at int_pal[j] */
  449.     for (;;j++)
  450.     { for (k=0; k<i && int_pal[j]!=scr_pal[k]; k++);
  451.       if (k==i) {scr_pal[i] = int_pal[j]; break;}
  452.     }
  453.   }
  454.   /* move white to place [15] */
  455.   for (i=1;i<15;i++)
  456.     scr_pal[i]=scr_pal[i+1];
  457.   scr_pal[15]=0xfff;
  458.   /* mapping from old palette to new; note that up to 2 colors
  459.      from the old palette may be missing from the new, if the old
  460.      palette didn't contain black and/or white.
  461.      This possibility seems so remote that we are content with
  462.      arbitrary mappings for the missing colors.
  463.   */
  464.   for (i=0;i<16;i++)
  465.   { for (j=0;j<16;j++)
  466.       if (scr_pal[j]==int_pal[i+2])
  467.         {pal_map[i]=j; break;}
  468.     if (j==16)
  469.       pal_map[i]=8; /* arbitrary */
  470.   }
  471.   /* translate scr_pal to header palette */
  472.   for (i=0,j=0;i<16;i++)
  473.   { hpal[j++]=(scr_pal[i]/256)*17;
  474.     hpal[j++]=((scr_pal[i]/16)%16)*17;
  475.     hpal[j++]=(scr_pal[i]%16)*17;
  476.   }
  477.   /* now set up mask arrays for remapping colors */
  478.   for (j=0;j<4;j++) masks[0].c[j]=0x01; /* mask for 1rst pixel */
  479.   for (i=1;i<8;i++) masks[i].l=(masks[i-1].l)<<1; /* next pixel: left shift */
  480.   /* maskpalette[j] contains color j appropriately shifted */
  481.   for (j=0;j<16;j++)
  482.   { maskpalette[j][0].c[0]=j&0x1;
  483.     maskpalette[j][0].c[1]=(j&0x2)>>1;
  484.     maskpalette[j][0].c[2]=(j&0x4)>>2;
  485.     maskpalette[j][0].c[3]=(j&0x8)>>3;
  486.   }
  487.   for (j=0;j<16;j++) for (i=1;i<8;i++)
  488.      maskpalette[j][i].l = maskpalette[j][i-1].l<<1;
  489.   /* newpalette[j] contains color k=pal_map[j] appropriately shifted */
  490.   for (j=0;j<16;j++)
  491.   { k=pal_map[j];
  492.     newpalette[j][0].c[0]=k&0x1;
  493.     newpalette[j][0].c[1]=(k&0x2)>>1;
  494.     newpalette[j][0].c[2]=(k&0x4)>>2;
  495.     newpalette[j][0].c[3]=(k&0x8)>>3;
  496.   }
  497.   for (j=0;j<16;j++) for (i=1;i<8;i++)
  498.     newpalette[j][i].l = newpalette[j][i-1].l<<1;
  499. }
  500.