home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / netpbma.zip / ppm / ilbmtoppm.c < prev    next >
C/C++ Source or Header  |  1993-12-02  |  37KB  |  1,309 lines

  1. /* ilbmtoppm.c - read an IFF ILBM file and produce a portable pixmap
  2. **
  3. ** Copyright (C) 1989 by Jef Poskanzer.
  4. **
  5. ** Permission to use, copy, modify, and distribute this software and its
  6. ** documentation for any purpose and without fee is hereby granted, provided
  7. ** that the above copyright notice appear in all copies and that both that
  8. ** copyright notice and this permission notice appear in supporting
  9. ** documentation.  This software is provided "as is" without express or
  10. ** implied warranty.
  11. **
  12. ** Modified by Mark Thompson on 10/4/90 to accomodate 24 bit IFF files
  13. ** as used by ASDG, NewTek, etc.
  14. **
  15. ** Modified by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
  16. **  20/Jun/93:
  17. **  - row-by-row operation
  18. **  - better de-interleave algorithm
  19. **  - colormap files
  20. **  - direct color
  21. **  04/Oct/93:
  22. **  - multipalette support (PCHG chunk)
  23. **  - options -ignore, -isham, -isehb and -adjustcolors
  24. */
  25.  
  26. #include "ppm.h"
  27. #include "ilbm.h"
  28.  
  29. /*#define DEBUG*/
  30.  
  31. /* prototypes */
  32. static void getfourchars ARGS(( FILE* f, char fourchars[4] ));
  33. static unsigned char get_byte ARGS(( FILE* f ));
  34. static long get_big_long ARGS((FILE *f));
  35. static short get_big_short ARGS((FILE *f));
  36. static void readerr ARGS((FILE *f));
  37.  
  38. static void skip_chunk ARGS((FILE *f, long chunksize));
  39. static void display_chunk ARGS((FILE *ifp, char *iffid, long chunksize));
  40. static pixel * read_colormap ARGS((FILE *f, long colors));
  41. static BitMapHeader * read_bmhd ARGS((FILE *f));
  42. static PCHGInfo *read_pchg ARGS((FILE *ifp, unsigned long chunksize));
  43.  
  44. static void ham_to_ppm ARGS((FILE *ifp, BitMapHeader *bmhd, pixel *colormap, int colors, PCHGInfo *pchginfo));
  45. static void deep_to_ppm ARGS((FILE *ifp, BitMapHeader *bmhd));
  46. static void cmap_to_ppm ARGS((pixel *colormap, int colors));
  47. static void std_to_ppm ARGS((FILE *ifp, BitMapHeader *bmhd, pixel *colormap, int colors, PCHGInfo *pchginfo, long viewportmodes));
  48. static void direct_to_ppm ARGS((FILE *ifp, BitMapHeader *bmhd, DirectColor *dcol));
  49.  
  50. static void init_pchg ARGS((PCHGInfo *pchginfo, pixel *colormap, int colors, pixval newmaxval));
  51. static void adjust_colormap ARGS((PCHGInfo *pchginfo, int row));
  52. static void scale_colormap ARGS((pixel *colormap, int colors, pixval oldmaxval, pixval newmaxval));
  53. static pixel * ehb_to_cmap ARGS((pixel *colormap, int *colors));
  54. static void read_ilbm_plane ARGS((FILE *ifp, int cols, int compression));
  55. static void decode_row ARGS((FILE *ifp, rawtype *chunkyrow, int planes, BitMapHeader *bmhd));
  56.  
  57. static rawtype * alloc_rawrow ARGS((int cols));
  58. static void * xmalloc ARGS((int bytes));
  59. #define MALLOC(n, type)     (type *)xmalloc((n) * sizeof(type))
  60.  
  61.  
  62. static short verbose = 0;
  63. static short adjustcolors = 0;
  64. static unsigned char *ilbmrow;
  65. static pixel *pixelrow;
  66.  
  67.  
  68. int
  69. main(argc, argv)
  70.     int argc;
  71.     char *argv[];
  72. {
  73.     FILE *ifp;
  74.     pixel *colormap = 0;
  75.     int argn, colors;
  76.     char iffid[5];
  77.     short body = 0;
  78.     long formsize, bytesread, chunksize, viewportmodes = 0, fakeviewport = 0;
  79.     char *usage = "[-verbose] [-ignore <chunkID>] [-isham|-isehb] [-adjustcolors] [ilbmfile]";
  80.     BitMapHeader *bmhd = NULL;
  81.     DirectColor *dcol = NULL;
  82.     PCHGInfo *pchginfo = NULL;
  83. #define MAX_IGNORE  16
  84.     char *ignorelist[MAX_IGNORE];
  85.     int ignorecount = 0;
  86.  
  87.  
  88.     ppm_init(&argc, argv);
  89.  
  90.     argn = 1;
  91.     while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
  92.         if( pm_keymatch(argv[argn], "-verbose", 2) )
  93.             verbose = 1;
  94.         else
  95.         if( pm_keymatch(argv[argn], "-noverbose", 4) )
  96.             verbose = 0;
  97.         else
  98.         if( pm_keymatch(argv[argn], "-isham", 4) )
  99.             fakeviewport |= vmHAM;
  100.         else
  101.         if( pm_keymatch(argv[argn], "-isehb", 4) )
  102.             fakeviewport |= vmEXTRA_HALFBRITE;
  103.         else
  104.         if( pm_keymatch(argv[argn], "-adjustcolors", 2) )
  105.             adjustcolors = 1;
  106.         else
  107.         if( pm_keymatch(argv[argn], "-noadjustcolors", 4) )
  108.             adjustcolors = 0;
  109.         else
  110.         if( pm_keymatch(argv[argn], "-ignore", 2) ) {
  111.             if( ++argn >= argc )
  112.                 pm_usage(usage);
  113.             if( strlen(argv[argn]) != 4 )
  114.                 pm_error("\"-ignore\" option needs a 4 byte chunk ID string as argument");
  115.             if( ignorecount >= MAX_IGNORE )
  116.                 pm_error("max %d chunk IDs to ignore", MAX_IGNORE);
  117.             ignorelist[ignorecount++] = argv[argn];
  118.         }
  119.         else
  120.             pm_usage(usage);
  121.         ++argn;
  122.     }
  123.  
  124.     if( argn < argc ) {
  125.         ifp = pm_openr( argv[argn] );
  126.         argn++;
  127.     }
  128.     else
  129.         ifp = stdin;
  130.  
  131.     if( argn != argc )
  132.         pm_usage(usage);
  133.  
  134.     /* Read in the ILBM file. */
  135.     iffid[4] = '\0';
  136.     getfourchars(ifp, iffid);
  137.     if( strcmp(iffid, "FORM") != 0 )
  138.         pm_error("input is not a FORM type IFF file");
  139.     formsize = get_big_long(ifp);
  140.     getfourchars(ifp, iffid);
  141.     if( strcmp(iffid, "ILBM") != 0 )
  142.         pm_error( "input is not an ILBM type FORM IFF file" );
  143.     bytesread = 4;  /* FORM and formsize do not count */
  144.  
  145.     /* Main loop, parsing the IFF FORM. */
  146.     while( bytesread < formsize ) {
  147.         short i, ignore = 0;
  148.  
  149.         getfourchars(ifp, iffid);
  150.         chunksize = get_big_long(ifp);
  151.         bytesread += 8;
  152.  
  153.         for( i = 0; i < ignorecount && !ignore; i++ ) {
  154.             if( strcmp(ignorelist[i], iffid) == 0 )
  155.                 ignore = 1;
  156.         }
  157.  
  158.         if( ignore ) {
  159.             ignore = 0;
  160.             pm_message("ignoring \"%s\" chunk", iffid);
  161.             skip_chunk(ifp, chunksize);
  162.         }
  163.         else
  164.         if( body != 0 ) {
  165.             pm_message("\"%s\" chunk found after BODY chunk - skipping", iffid);
  166.             skip_chunk(ifp, chunksize);
  167.         }
  168.         else
  169.         if( strcmp(iffid, "BMHD") == 0 ) {
  170.             if( chunksize != BitMapHeaderSize )
  171.                 pm_error("BMHD chunk size mismatch");
  172.             bmhd = read_bmhd(ifp);
  173.         }
  174.         else
  175.         if( strcmp(iffid, "CMAP") == 0 ) {
  176.             colors = chunksize / 3;
  177.             if( colors == 0 ) {
  178.                 pm_error("warning - empty colormap");
  179.                 skip_chunk(ifp, chunksize);
  180.             }
  181.             else {
  182.                 long r = 3 * colors;
  183.                 colormap = read_colormap(ifp, colors);
  184.                 while( r++ < chunksize )
  185.                     (void)get_byte(ifp);
  186.             }
  187.         }
  188.         else
  189.         if( strcmp(iffid, "CAMG") == 0 ) {
  190.             if( chunksize != CAMGChunkSize )
  191.                 pm_error("CAMG chunk size mismatch");
  192.             viewportmodes = get_big_long(ifp);
  193.         }
  194.         else
  195.         if( strcmp(iffid, "DCOL") == 0 ) {
  196.             if( chunksize != DirectColorSize )
  197.                 pm_error("DCOL chunk size mismatch");
  198.             dcol = MALLOC(1, DirectColor);
  199.             dcol->r = get_byte(ifp);
  200.             dcol->g = get_byte(ifp);
  201.             dcol->b = get_byte(ifp);
  202.             (void) get_byte(ifp);
  203.         }
  204.         else
  205.         if( strcmp(iffid, "PCHG") == 0 ) {
  206.             pchginfo = read_pchg(ifp, chunksize);
  207.         }
  208.         else
  209.         if( strcmp(iffid, "BODY") == 0 ) {
  210.             if( bmhd == NULL )
  211.                 pm_error("\"BODY\" chunk without \"BMHD\" chunk");
  212.  
  213.             ilbmrow = MALLOC(RowBytes(bmhd->w), unsigned char);
  214.             pixelrow = ppm_allocrow(bmhd->w);
  215.  
  216.             viewportmodes |= fakeviewport;
  217.  
  218.             if( viewportmodes & vmHAM )
  219.                 ham_to_ppm(ifp, bmhd, colormap, colors, pchginfo);
  220.             else
  221.             if( dcol != NULL )
  222.                 direct_to_ppm(ifp, bmhd, dcol);
  223.             else
  224.             if( bmhd->nPlanes == 24 )
  225.                 deep_to_ppm(ifp, bmhd);
  226.             else
  227.                 std_to_ppm(ifp, bmhd, colormap, colors, pchginfo, viewportmodes);
  228.             body = 1;
  229.         }
  230.         else
  231.         if( strcmp(iffid, "GRAB") == 0 || strcmp(iffid, "DEST") == 0 ||
  232.             strcmp(iffid, "SPRT") == 0 || strcmp(iffid, "CRNG") == 0 ||
  233.             strcmp(iffid, "CCRT") == 0 || strcmp(iffid, "CLUT") == 0 ||
  234.             strcmp(iffid, "DPPV") == 0 || strcmp(iffid, "DRNG") == 0 ||
  235.             strcmp(iffid, "EPSF") == 0 ) {
  236.             skip_chunk(ifp, chunksize);
  237.         }
  238.         else
  239.         if( strcmp(iffid, "(c) ") == 0 || strcmp(iffid, "AUTH") == 0 ||
  240.             strcmp(iffid, "NAME") == 0 || strcmp(iffid, "ANNO") == 0 ||
  241.             strcmp(iffid, "TEXT") == 0 ) {
  242.             if( verbose )
  243.                 display_chunk(ifp, iffid, chunksize);
  244.             else
  245.                 skip_chunk(ifp, chunksize);
  246.         }
  247.         else
  248.         if( strcmp(iffid, "DPI ") == 0 ) {
  249.             int x, y;
  250.  
  251.             x = get_big_short(ifp);
  252.             y = get_big_short(ifp);
  253.             if( verbose )
  254.                 pm_message("\"DPI \" chunk:  dpi_x = %d    dpi_y = %d", x, y);
  255.         }
  256.         else {
  257.             pm_message("unknown chunk type \"%s\" - skipping", iffid);
  258.             skip_chunk(ifp, chunksize);
  259.         }
  260.  
  261.         bytesread += chunksize;
  262.         if( odd(chunksize) ) {
  263.                 (void) get_byte(ifp);
  264.                 ++bytesread;
  265.         }
  266.     }
  267.     pm_close(ifp);
  268.  
  269.     if( body == 0 ) {
  270.         if( colormap )
  271.             cmap_to_ppm(colormap, colors);
  272.         else
  273.             pm_error("no \"BODY\" or \"CMAP\" chunk found");
  274.     }
  275.  
  276.     if( bytesread != formsize ) {
  277.         pm_message("warning - file length (%ld bytes) does not match FORM size field (%ld bytes) +8",
  278.                     bytesread, formsize);
  279.     }
  280.  
  281.     exit(0);
  282. }
  283.  
  284.  
  285. static void
  286. readerr(f)
  287.     FILE *f;
  288. {
  289.     if( ferror(f) )
  290.         pm_error("read error");
  291.     else
  292.         pm_error("premature EOF");
  293. }
  294.  
  295.  
  296. static unsigned char
  297. get_byte(ifp)
  298.     FILE* ifp;
  299. {
  300.     int i;
  301.  
  302.     i = getc(ifp);
  303.     if( i == EOF )
  304.         readerr(ifp);
  305.  
  306.     return (unsigned char) i;
  307. }
  308.  
  309. static void
  310. getfourchars(ifp, fourchars)
  311.     FILE* ifp;
  312.     char fourchars[4];
  313. {
  314.     fourchars[0] = get_byte(ifp);
  315.     fourchars[1] = get_byte(ifp);
  316.     fourchars[2] = get_byte(ifp);
  317.     fourchars[3] = get_byte(ifp);
  318. }
  319.  
  320.  
  321. static long
  322. get_big_long(ifp)
  323.     FILE *ifp;
  324. {
  325.     long l;
  326.  
  327.     if( pm_readbiglong(ifp, &l) == -1 )
  328.         readerr(ifp);
  329.  
  330.     return l;
  331. }
  332.  
  333. static short
  334. get_big_short(ifp)
  335.     FILE *ifp;
  336. {
  337.     short s;
  338.  
  339.     if( pm_readbigshort(ifp, &s) == -1 )
  340.         readerr(ifp);
  341.  
  342.     return s;
  343. }
  344.  
  345.  
  346. static void
  347. skip_chunk(ifp, chunksize)
  348.     FILE *ifp;
  349.     long chunksize;
  350. {
  351.     int i;
  352.  
  353.     for( i = 0; i < chunksize; i++ )
  354.         (void) get_byte(ifp);
  355. }
  356.  
  357.  
  358. static pixel *
  359. read_colormap(ifp, colors)
  360.     FILE *ifp;
  361.     long colors;
  362. {
  363.     pixel *colormap;
  364.     int i, r, g, b;
  365.     pixval colmaxval = 0;
  366.  
  367.     colormap = ppm_allocrow(colors);
  368.     for( i = 0; i < colors; i++ ) {
  369.         r = get_byte(ifp); if( r > colmaxval ) colmaxval = r;
  370.         g = get_byte(ifp); if( g > colmaxval ) colmaxval = g;
  371.         b = get_byte(ifp); if( b > colmaxval ) colmaxval = b;
  372.         PPM_ASSIGN(colormap[i], r, g, b);
  373.     }
  374. #ifdef DEBUG
  375.     pm_message("colormap maxval is %d", colmaxval);
  376. #endif
  377.     if( colmaxval == 0 )
  378.         pm_message("warning - black colormap");
  379.     else
  380.     if( colmaxval <= 15 ) {
  381.         if( !adjustcolors ) {
  382.             pm_message("warning - probably 4 bit colormap");
  383.             pm_message("use \"-adjustcolors\" to scale colormap to 8 bits");
  384.         }
  385.         else {
  386.             pm_message("scaling colormap to 8 bits");
  387.             scale_colormap(colormap, colors, 15, MAXCOLVAL);
  388.         }
  389.     }
  390.     return colormap;
  391. }
  392.  
  393.  
  394. static BitMapHeader *
  395. read_bmhd(ifp)
  396.     FILE *ifp;
  397. {
  398.     BitMapHeader *bmhd;
  399.  
  400.     bmhd = MALLOC(1, BitMapHeader);
  401.  
  402.     bmhd->w = get_big_short(ifp);           /* cols */
  403.     bmhd->h = get_big_short(ifp);           /* rows */
  404.     bmhd->x = get_big_short(ifp);
  405.     bmhd->y = get_big_short(ifp);
  406.     bmhd->nPlanes = get_byte(ifp);
  407.     bmhd->masking = get_byte(ifp);
  408.     bmhd->compression = get_byte(ifp);
  409.     bmhd->pad1 = get_byte(ifp);             /* (ignored) */
  410.     bmhd->transparentColor = get_big_short(ifp);
  411.     bmhd->xAspect = get_byte(ifp);
  412.     bmhd->yAspect = get_byte(ifp);
  413.     bmhd->pageWidth = get_big_short(ifp);
  414.     bmhd->pageHeight = get_big_short(ifp);
  415.  
  416.     if( verbose ) {
  417.         pm_message("dimensions: %dx%d", bmhd->w, bmhd->h);
  418.         pm_message("BODY compression: %s", bmhd->compression <= cmpMAXKNOWN ?
  419.                     cmpNAME[bmhd->compression] : "unknown");
  420.     }
  421.  
  422.     /* fix aspect ratio */
  423.     if( bmhd->xAspect == 0 ) {
  424.         if( bmhd->yAspect == 0 ) {
  425.             pm_message("warning - xAspect:yAspect = 0:0, using 1:1");
  426.             bmhd->xAspect = bmhd->yAspect = 1;
  427.         }
  428.         else {
  429.             pm_message("warning - xAspect = 0, setting to yAspect");
  430.             bmhd->xAspect = bmhd->yAspect;
  431.         }
  432.     }
  433.     else {
  434.         if( bmhd->yAspect == 0 ) {
  435.             pm_message("warning - yAspect = 0, setting to xAspect");
  436.             bmhd->yAspect = bmhd->xAspect;
  437.         }
  438.     }
  439.     if( bmhd->xAspect != bmhd->yAspect ) {
  440.         pm_message("warning - non-square pixels; to fix do a 'pnmscale -%cscale %g'",
  441.             bmhd->xAspect > bmhd->yAspect ? 'x' : 'y',
  442.             bmhd->xAspect > bmhd->yAspect ? (float)(bmhd->xAspect)/bmhd->yAspect : (float)(bmhd->yAspect)/bmhd->xAspect);
  443.     }
  444.  
  445.     return bmhd;
  446. }
  447.  
  448.  
  449. static void
  450. ham_to_ppm(ifp, bmhd, colormap, colors, pchginfo)
  451.     FILE *ifp;
  452.     BitMapHeader *bmhd;
  453.     pixel *colormap;
  454.     int colors;
  455.     PCHGInfo *pchginfo;
  456. {
  457.     int cols, rows, hambits, hammask, col, row;
  458.     pixval maxval;
  459.     rawtype *rawrow;
  460.     int pchgflag = (pchginfo && colormap);
  461.  
  462.     cols = bmhd->w;
  463.     rows = bmhd->h;
  464.     hambits = bmhd->nPlanes - 2;
  465.     hammask = (1 << hambits) - 1;
  466.  
  467.     pm_message("input is a %sHAM%d file", pchgflag ? "multipalette " : "", bmhd->nPlanes);
  468.  
  469.     if( hambits > MAXPLANES )
  470.         pm_error("too many planes (max %d)", MAXPLANES);
  471.     if( hambits < 0 ) {
  472.         pm_message("HAM requires 2 or more planes");
  473.         pm_error("try \"-ignore CAMG\" to treat this file as a normal ILBM");
  474.     }
  475.  
  476.     maxval = pm_bitstomaxval(hambits);
  477.     if( maxval > PPM_MAXMAXVAL )
  478.         pm_error("nPlanes is too large - try reconfiguring with PGM_BIGGRAYS\n    or without PPM_PACKCOLORS" );
  479.  
  480.     /* scale colormap to new maxval */
  481.     if( colormap && maxval != MAXCOLVAL )
  482.         scale_colormap(colormap, colors, MAXCOLVAL, maxval);
  483.  
  484.     if( pchgflag )
  485.         init_pchg(pchginfo, colormap, colors, maxval);
  486.  
  487.     rawrow = alloc_rawrow(cols);
  488.  
  489.     ppm_writeppminit(stdout, cols, rows, maxval, 0);
  490.     for( row = 0; row < rows; row++ ) {
  491.         pixval r, g, b;
  492.  
  493.         if( pchgflag )
  494.             adjust_colormap(pchginfo, row);
  495.  
  496.         decode_row(ifp, rawrow, bmhd->nPlanes, bmhd);
  497.  
  498.         r = g = b = 0;
  499.         for( col = 0; col < cols; col++ ) {
  500.             switch((rawrow[col] >> hambits) & 0x03) {
  501.                 case HAMCODE_CMAP:
  502.                     if( colormap && colors >= maxval )
  503.                         pixelrow[col] = colormap[rawrow[col] & hammask];
  504.                     else
  505.                         PPM_ASSIGN(pixelrow[col], rawrow[col] & hammask,
  506.                                    rawrow[col] & hammask, rawrow[col] & hammask);
  507.                     r = PPM_GETR(pixelrow[col]);
  508.                     g = PPM_GETG(pixelrow[col]);
  509.                     b = PPM_GETB(pixelrow[col]);
  510.                     break;
  511.                 case HAMCODE_BLUE:
  512.                     b = rawrow[col] & hammask;
  513.                     PPM_ASSIGN(pixelrow[col], r, g, b);
  514.                     break;
  515.                 case HAMCODE_RED:
  516.                     r = rawrow[col] & hammask;
  517.                     PPM_ASSIGN(pixelrow[col], r, g, b);
  518.                     break;
  519.                 case HAMCODE_GREEN:
  520.                     g = rawrow[col] & hammask;
  521.                     PPM_ASSIGN(pixelrow[col], r, g, b);
  522.                     break;
  523.                 default:
  524.                     pm_error("impossible HAM code");
  525.             }
  526.         }
  527.         ppm_writeppmrow(stdout, pixelrow, cols, (pixval) maxval, 0);
  528.     }
  529. }
  530.  
  531.  
  532. static void
  533. deep_to_ppm(ifp, bmhd)
  534.     FILE *ifp;
  535.     BitMapHeader *bmhd;
  536. {
  537.     int cols, rows, col, row;
  538.     rawtype *Rrow, *Grow, *Brow;
  539.  
  540.     cols = bmhd->w;
  541.     rows = bmhd->h;
  542.  
  543.     pm_message("input is a deep (24bit) ILBM");
  544.  
  545.     Rrow = alloc_rawrow(cols);
  546.     Grow = alloc_rawrow(cols);
  547.     Brow = alloc_rawrow(cols);
  548.  
  549.     ppm_writeppminit(stdout, cols, rows, MAXCOLVAL, 0);
  550.     for( row = 0; row < rows; row++ ) {
  551.         decode_row(ifp, Rrow, 8, bmhd);
  552.         decode_row(ifp, Grow, 8, bmhd);
  553.         decode_row(ifp, Brow, 8, bmhd);
  554.         for( col = 0; col < cols; col++ )
  555.             PPM_ASSIGN(pixelrow[col], Rrow[col], Grow[col], Brow[col]);
  556.         ppm_writeppmrow(stdout, pixelrow, cols, MAXCOLVAL, 0);
  557.     }
  558.     pm_close(stdout);
  559. }
  560.  
  561.  
  562. static void
  563. direct_to_ppm(ifp, bmhd, dcol)
  564.     FILE *ifp;
  565.     BitMapHeader *bmhd;
  566.     DirectColor *dcol;
  567. {
  568.     int cols, rows, col, row, redplanes, greenplanes, blueplanes;
  569.     rawtype *Rrow, *Grow, *Brow;
  570.     pixval maxval, redmaxval, greenmaxval, bluemaxval;
  571.     int scale;
  572.  
  573.     cols = bmhd->w;
  574.     rows = bmhd->h;
  575.  
  576.     redplanes = dcol->r; greenplanes = dcol->g; blueplanes = dcol->b;
  577.  
  578.     pm_message("input is a %d:%d:%d direct color ILBM",
  579.                 redplanes, greenplanes, blueplanes);
  580.  
  581.     if( redplanes > MAXPLANES || blueplanes > MAXPLANES || greenplanes > MAXPLANES )
  582.         pm_error("too many planes (max %d per color)", MAXPLANES);
  583.  
  584.     if( bmhd->nPlanes != (redplanes + greenplanes + blueplanes) )
  585.         pm_error("BMHD/DCOL plane number mismatch");
  586.  
  587.     if( redplanes == blueplanes && redplanes == greenplanes ) {
  588.         scale = 0;
  589.         maxval = pm_bitstomaxval(redplanes);
  590.     }
  591.     else {
  592.         scale = 1;
  593.         redmaxval   = pm_bitstomaxval(redplanes);
  594.         greenmaxval = pm_bitstomaxval(greenplanes);
  595.         bluemaxval  = pm_bitstomaxval(blueplanes);
  596.  
  597.         maxval = max(redmaxval, max(greenmaxval, bluemaxval));
  598.         pm_message("rescaling colors to %d bits", pm_maxvaltobits(maxval));
  599.     }
  600.  
  601.     if( maxval > PPM_MAXMAXVAL )
  602.         pm_error("too many planes - try reconfiguring with PGM_BIGGRAYS\n    or without PPM_PACKCOLORS" );
  603.  
  604.     Rrow = alloc_rawrow(cols);
  605.     Grow = alloc_rawrow(cols);
  606.     Brow = alloc_rawrow(cols);
  607.  
  608.     ppm_writeppminit(stdout, cols, rows, maxval, 0);
  609.     for( row = 0; row < rows; row++ ) {
  610.         decode_row(ifp, Rrow, dcol->r, bmhd);
  611.         decode_row(ifp, Grow, dcol->g, bmhd);
  612.         decode_row(ifp, Brow, dcol->b, bmhd);
  613.  
  614.         if( scale ) {
  615.             for( col = 0; col < cols; col++ ) {
  616.                 PPM_ASSIGN(pixelrow[col],
  617.                             Rrow[col] * maxval / redmaxval,
  618.                             Grow[col] * maxval / greenmaxval,
  619.                             Brow[col] * maxval / bluemaxval);
  620.             }
  621.         }
  622.         else {
  623.             for( col = 0; col < cols; col++ )
  624.                 PPM_ASSIGN(pixelrow[col], Rrow[col], Grow[col], Brow[col]);
  625.         }
  626.         ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0);
  627.     }
  628.     pm_close(stdout);
  629. }
  630.  
  631.  
  632. static void
  633. cmap_to_ppm(colormap, colors)
  634.     pixel *colormap;
  635.     int colors;
  636. {
  637.     pm_message("input is a colormap file");
  638.  
  639.     ppm_writeppminit(stdout, colors, 1, MAXCOLVAL, 0);
  640.     ppm_writeppmrow(stdout, colormap, colors, MAXCOLVAL, 0);
  641.     pm_close(stdout);
  642. }
  643.  
  644.  
  645. static void
  646. std_to_ppm(ifp, bmhd, colormap, colors, pchginfo, viewportmodes)
  647.     FILE *ifp;
  648.     BitMapHeader *bmhd;
  649.     pixel *colormap;
  650.     int colors;
  651.     PCHGInfo *pchginfo;
  652.     long viewportmodes;
  653. {
  654.     rawtype *rawrow;
  655.     pixval maxval;
  656.     int row, rows, col, cols;
  657.     int pchgflag = (pchginfo && colormap);
  658.  
  659.     cols = bmhd->w;
  660.     rows = bmhd->h;
  661.  
  662.     pm_message("input is a %d-plane %s%sILBM", bmhd->nPlanes,
  663.                 pchgflag ? "multipalette " : "",
  664.                 viewportmodes & vmEXTRA_HALFBRITE ? "EHB " : ""
  665.               );
  666.  
  667.     if( bmhd->nPlanes > MAXPLANES )
  668.         pm_error("too many planes (max %d)", MAXPLANES);
  669.  
  670.     if( colormap )
  671.         maxval = MAXCOLVAL;
  672.     else {
  673.         maxval = pm_bitstomaxval(bmhd->nPlanes);
  674.         pm_message("no colormap - interpreting values as grayscale");
  675.     }
  676.     if( maxval > PPM_MAXMAXVAL )
  677.         pm_error("nPlanes is too large - try reconfiguring with PGM_BIGGRAYS\n    or without PPM_PACKCOLORS" );
  678.  
  679.     if( pchgflag )
  680.         init_pchg(pchginfo, colormap, colors, maxval);
  681.  
  682.     rawrow = alloc_rawrow(cols);
  683.  
  684.     if( viewportmodes & vmEXTRA_HALFBRITE )
  685.         colormap = ehb_to_cmap(colormap, &colors);
  686.  
  687.     ppm_writeppminit( stdout, cols, rows, (pixval) maxval, 0 );
  688.     for( row = 0; row < rows; row++ ) {
  689.  
  690.         if( pchgflag )
  691.             adjust_colormap(pchginfo, row);
  692.  
  693.         decode_row(ifp, rawrow, bmhd->nPlanes, bmhd);
  694.         for( col = 0; col < cols; col++ ) {
  695.             if( colormap )
  696.                 pixelrow[col] = colormap[rawrow[col]];
  697.             else
  698.                 PPM_ASSIGN(pixelrow[col], rawrow[col], rawrow[col], rawrow[col]);
  699.         }
  700.         ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0);
  701.     }
  702. }
  703.  
  704.  
  705. static pixel *
  706. ehb_to_cmap(colormap, colors)
  707.     pixel *colormap;
  708.     int *colors;
  709. {
  710.     pixel *tempcolormap = NULL;
  711.     int i, col;
  712.  
  713.     if( colormap ) {
  714.         col = *colors;
  715.         tempcolormap = ppm_allocrow(col * 2);
  716.         for( i = 0; i < col; i++ ) {
  717.             tempcolormap[i] = colormap[i];
  718.             PPM_ASSIGN(tempcolormap[col + i], PPM_GETR(colormap[i]) / 2,
  719.                         PPM_GETG(colormap[i]) / 2, PPM_GETB(colormap[i]) / 2 );
  720.         }
  721.         ppm_freerow(colormap);
  722.         *colors *= 2;
  723.     }
  724.     return tempcolormap;
  725. }
  726.  
  727.  
  728. static void
  729. read_ilbm_plane(ifp, cols, compression)
  730.     FILE *ifp;
  731.     int cols, compression;
  732. {
  733.     unsigned char *ubp;
  734.     int bytes, j, byte;
  735.  
  736.     bytes = RowBytes(cols);
  737.  
  738.     switch(compression) {
  739.         case cmpNone:
  740.             j = fread(ilbmrow, 1, bytes, ifp);
  741.             if( j != bytes )
  742.                 readerr(ifp);
  743.             break;
  744.         case cmpByteRun1:
  745.             ubp = ilbmrow;
  746.             do {
  747.                 byte = (int)get_byte(ifp);
  748.                 if( byte <= 127 ) {
  749.                     j = byte;
  750.                     bytes -= (j+1);
  751.                     if( bytes < 0 )
  752.                         pm_error("error doing ByteRun1 decompression");
  753.                     for( ; j >= 0; j-- )
  754.                         *ubp++ = get_byte(ifp);
  755.                 }
  756.                 else
  757.                 if ( byte != 128 ) {
  758.                     j = 256 - byte;
  759.                     bytes -= (j+1);
  760.                     if( bytes < 0 )
  761.                         pm_error("error doing ByteRun1 decompression");
  762.                     byte = (int)get_byte(ifp);
  763.                     for( ; j >= 0; j-- )
  764.                         *ubp++ = (unsigned char)byte;
  765.                 }
  766.                 /* 128 is a NOP */
  767.             }
  768.             while( bytes > 0 );
  769.             break;
  770.         default:
  771.                 pm_error("unknown compression type");
  772.     }
  773. }
  774.  
  775.  
  776. const unsigned char bit_mask[] = {1, 2, 4, 8, 16, 32, 64, 128};
  777.  
  778. static void
  779. decode_row(ifp, chunkyrow, nPlanes, bmhd)
  780.     FILE *ifp;
  781.     rawtype *chunkyrow;
  782.     int nPlanes;
  783.     BitMapHeader *bmhd;
  784. {
  785.     int plane, col, cols;
  786.     unsigned char *ilp;
  787.     rawtype *chp;
  788.  
  789.     cols = bmhd->w;
  790.     for( plane = 0; plane < nPlanes; plane++ ) {
  791.         int mask, cbit;
  792.  
  793.         mask = 1 << plane;
  794.         read_ilbm_plane(ifp, cols, bmhd->compression);
  795.  
  796.         ilp = ilbmrow;
  797.         chp = chunkyrow;
  798.  
  799.         cbit = 7;
  800.         for( col = 0; col < cols; col++, cbit--, chp++ ) {
  801.             if( cbit < 0 ) {
  802.                 cbit = 7;
  803.                 ilp++;
  804.             }
  805.             if( *ilp & bit_mask[cbit] )
  806.                 *chp |= mask;
  807.             else
  808.                 *chp &= ~mask;
  809.         }
  810.     }
  811.     /* skip mask plane */
  812.     if( bmhd->masking == mskHasMask )
  813.         read_ilbm_plane(ifp, cols, bmhd->compression);
  814. }
  815.  
  816.  
  817. static rawtype *
  818. alloc_rawrow(cols)
  819.     int cols;
  820. {
  821.     rawtype *r;
  822.     int i;
  823.  
  824.     r = MALLOC(cols, rawtype);
  825.  
  826.     for( i = 0; i < cols; i++ )
  827.         r[i] = 0;
  828.  
  829.     return r;
  830. }
  831.  
  832.  
  833. static void *
  834. xmalloc(bytes)
  835.     int bytes;
  836. {
  837.     void *mem;
  838.  
  839.     if( bytes == 0 )
  840.         return NULL;
  841.  
  842.     mem = malloc(bytes);
  843.     if( mem == NULL )
  844.         pm_error("out of memory allocating %d bytes", bytes);
  845.     return mem;
  846. }
  847.  
  848.  
  849. static void
  850. display_chunk(ifp, iffid, chunksize)
  851.     FILE *ifp;
  852.     char *iffid;
  853.     long chunksize;
  854. {
  855.     int byte;
  856.  
  857.     pm_message("contents of \"%s\" chunk:", iffid);
  858.  
  859.     while( chunksize-- ) {
  860.         byte = get_byte(ifp);
  861.         if( fputc(byte, stderr) == EOF )
  862.             pm_error("write error");
  863.     }
  864.     if( fputc('\n', stderr) == EOF )
  865.         pm_error("write error");
  866. }
  867.  
  868. /*
  869.  * PCHG stuff
  870.  */
  871.  
  872. static void PCHG_Decompress ARGS((PCHGHeader *PCHG, PCHGCompHeader *CompHdr, unsigned char *compdata, unsigned long compsize, unsigned char *comptree, unsigned char *data));
  873. static unsigned char * PCHG_MakeMask ARGS((PCHGHeader *PCHG, unsigned char *data, unsigned long datasize, unsigned char **newdata));
  874. static void PCHG_ConvertSmall ARGS((PCHGInfo *Info, unsigned char *data, unsigned long datasize));
  875. static void PCHG_ConvertBig ARGS((PCHGInfo *Info, unsigned char *data, unsigned long datasize));
  876. static void PCHG_DecompHuff ARGS((unsigned char *src, unsigned char *dest, short *tree, unsigned long origsize));
  877. static void pchgerr ARGS((char *when));
  878.  
  879. /* Turn big-endian 4-byte long and 2-byte short stored at x (unsigned char *)
  880.  * into the native format of the CPU
  881.  */
  882. #define BIG_LONG(x) (   ((unsigned long)((x)[0]) << 24) + \
  883.                         ((unsigned long)((x)[1]) << 16) + \
  884.                         ((unsigned long)((x)[2]) <<  8) + \
  885.                         ((unsigned long)((x)[3]) <<  0) )
  886. #define BIG_WORD(x) (   ((unsigned short)((x)[0]) << 8) + \
  887.                         ((unsigned short)((x)[1]) << 0) )
  888.  
  889.  
  890. static PCHGInfo *
  891. read_pchg(ifp, bytesleft)
  892.     FILE *ifp;
  893.     unsigned long bytesleft;
  894. {
  895.     static PCHGInfo Info;
  896.     PCHGCompHeader  CompHdr;
  897.     PCHGHeader      *PCHG;
  898.     unsigned char   *data, *chdata;
  899.     unsigned long   datasize;
  900.  
  901. #ifdef DEBUG
  902.     pm_message("PCHG chunk found");
  903. #endif
  904.  
  905.     if( bytesleft < PCHGHeaderSize )
  906.         pchgerr("while reading PCHGHeader");
  907.  
  908.     Info.PCHG = PCHG = MALLOC(1, PCHGHeader);
  909.     PCHG->Compression = get_big_short(ifp);
  910.     PCHG->Flags       = get_big_short(ifp);
  911.     PCHG->StartLine   = get_big_short(ifp);
  912.     PCHG->LineCount   = get_big_short(ifp);
  913.     PCHG->ChangedLines= get_big_short(ifp);
  914.     PCHG->MinReg      = get_big_short(ifp);
  915.     PCHG->MaxReg      = get_big_short(ifp);
  916.     PCHG->MaxChanges  = get_big_short(ifp);
  917.     PCHG->TotalChanges= get_big_long(ifp);
  918.     bytesleft -= PCHGHeaderSize;
  919.  
  920. #ifdef DEBUG
  921.     pm_message("PCHG StartLine   : %d", PCHG->StartLine);
  922.     pm_message("PCHG LineCount   : %d", PCHG->LineCount);
  923.     pm_message("PCHG ChangedLines: %d", PCHG->ChangedLines);
  924.     pm_message("PCHG TotalChanges: %d", PCHG->TotalChanges);
  925. #endif
  926.  
  927.     if( PCHG->Compression != PCHG_COMP_NONE ) {
  928.         unsigned char *compdata, *comptree;
  929.         unsigned long treesize;
  930.  
  931.         if( bytesleft < PCHGCompHeaderSize )
  932.             pchgerr("while reading PCHGCompHeader");
  933.  
  934.         CompHdr.CompInfoSize     = get_big_long(ifp);
  935.         CompHdr.OriginalDataSize = get_big_long(ifp);
  936.         bytesleft -= PCHGCompHeaderSize;
  937.         treesize = CompHdr.CompInfoSize;
  938.         datasize = CompHdr.OriginalDataSize;
  939.  
  940.         if( bytesleft < treesize )
  941.             pchgerr("while reading compression info data");
  942.  
  943.         comptree = MALLOC(treesize, unsigned char);
  944.         if( fread(comptree, 1, treesize, ifp) != treesize )
  945.             readerr(ifp);
  946.  
  947.         bytesleft -= treesize;
  948.         if( bytesleft == 0 )
  949.             pchgerr("while reading compressed change structure data");
  950.  
  951.         compdata= MALLOC(bytesleft, unsigned char);
  952.         data    = MALLOC(datasize, unsigned char);
  953.  
  954.         if( fread(compdata, 1, bytesleft, ifp) != bytesleft )
  955.             readerr(ifp);
  956.  
  957.         PCHG_Decompress(PCHG, &CompHdr, compdata, bytesleft, comptree, data);
  958.         free(comptree);
  959.         free(compdata);
  960.         bytesleft = 0;
  961.     }
  962.     else {
  963. #ifdef DEBUG
  964.         pm_message("uncompressed PCHG");
  965. #endif
  966.         if( bytesleft == 0 )
  967.             pchgerr("while reading uncompressed change structure data");
  968.  
  969.         datasize = bytesleft;
  970.         data = MALLOC(datasize, unsigned char);
  971.         if( fread(data, 1, datasize, ifp) != datasize )
  972.             readerr(ifp);
  973.         bytesleft = 0;
  974.     }
  975.  
  976.     Info.LineMask = PCHG_MakeMask(PCHG, data, datasize, &chdata);
  977.     datasize -= (chdata - data);
  978.  
  979.     Info.Palette = MALLOC(PCHG->TotalChanges, PaletteChange);
  980.     Info.Change  = MALLOC(PCHG->ChangedLines, LineChanges);
  981.  
  982.     if( PCHG->Flags & PCHGF_USE_ALPHA )
  983.         pm_message("warning - PCHG alpha channel not supported");
  984.  
  985.     if( PCHG->Flags & PCHGF_12BIT ) {
  986. #ifdef DEBUG
  987.         pm_message("SmallLineChanges");
  988. #endif
  989.         PCHG_ConvertSmall(&Info, chdata, datasize);
  990.     }
  991.     else
  992.     if( PCHG->Flags & PCHGF_32BIT ) {
  993. #ifdef DEBUG
  994.         pm_message("BigLineChanges");
  995. #endif
  996.         PCHG_ConvertBig(&Info, chdata, datasize);
  997.     }
  998.     else
  999.         pm_error("unknown palette changes structure format in PCHG chunk");
  1000.  
  1001.     free(data);
  1002.     return &Info;
  1003. }
  1004.  
  1005.  
  1006. static void
  1007. PCHG_Decompress(PCHG, CompHdr, compdata, compsize, comptree, data)
  1008.     PCHGHeader *PCHG;
  1009.     PCHGCompHeader *CompHdr;
  1010.     unsigned char *compdata;
  1011.     unsigned long compsize;
  1012.     unsigned char *comptree;
  1013.     unsigned char *data;
  1014. {
  1015.     short *hufftree;
  1016.     unsigned long huffsize, i;
  1017.     unsigned long treesize = CompHdr->CompInfoSize;
  1018.  
  1019.     switch( PCHG->Compression ) {
  1020.         case PCHG_COMP_HUFFMAN:
  1021.  
  1022. #ifdef DEBUG
  1023.             pm_message("PCHG Huffman compression");
  1024. #endif
  1025.             /* turn big-endian 2-byte shorts into native format */
  1026.             huffsize = treesize/2;
  1027.             hufftree = MALLOC(huffsize, short);
  1028.             for( i = 0; i < huffsize; i++ ) {
  1029.                 hufftree[i] = (short)BIG_WORD(comptree);
  1030.                 comptree += 2;
  1031.             }
  1032.  
  1033.             /* decompress the change structure data */
  1034.             PCHG_DecompHuff(compdata, data, &hufftree[huffsize-1], CompHdr->OriginalDataSize);
  1035.  
  1036.             free(hufftree);
  1037.             break;
  1038.         default:
  1039.             pm_error("unknown PCHG compression type");
  1040.     }
  1041. }
  1042.  
  1043.  
  1044. static unsigned char *
  1045. PCHG_MakeMask(PCHG, data, datasize, newdata)
  1046.     PCHGHeader *PCHG;
  1047.     unsigned char *data;
  1048.     unsigned long datasize;
  1049.     unsigned char **newdata;
  1050. {
  1051.     unsigned long bytes;
  1052.     unsigned char *mask;
  1053.  
  1054.     /* the mask at 'data' is in 4-byte big-endian longword format,
  1055.      * thus we can simply treat it at unsigned char and don't have
  1056.      * to convert it, just copy it to a new mem block so we can
  1057.      * free the original data
  1058.      */
  1059.     bytes = MaskLongWords(PCHG->LineCount) * 4;
  1060.     if( datasize < bytes )
  1061.         pchgerr("for line mask");
  1062.     mask = MALLOC(bytes, unsigned char);
  1063.  
  1064. #ifdef DEBUG
  1065.     pm_message("%ld bytes for line mask", bytes);
  1066. #endif
  1067.     bcopy(data, mask, bytes);
  1068.  
  1069.     *newdata = (data + bytes);
  1070.     return mask;
  1071. }
  1072.  
  1073.  
  1074. static void
  1075. PCHG_ConvertSmall(Info, data, datasize)
  1076.     PCHGInfo *Info;
  1077.     unsigned char *data;
  1078.     unsigned long datasize;
  1079. {
  1080.     PCHGHeader *PCHG        = Info->PCHG;
  1081.     LineChanges *Change     = Info->Change;
  1082.     PaletteChange *Palette  = Info->Palette;
  1083.     unsigned long i, palettecount = 0;
  1084.     unsigned char ChangeCount16, ChangeCount32;
  1085.     unsigned short SmallChange;
  1086.  
  1087.     Info->maxval = 15;  /* 4 bit values */
  1088.  
  1089.     for( i = 0; i < PCHG->ChangedLines; i++ ) {
  1090.         int n;
  1091.  
  1092.         if( datasize < 2 ) goto fail;
  1093.         ChangeCount16 = *data++;
  1094.         ChangeCount32 = *data++;
  1095.         datasize -= 2;
  1096.  
  1097.         Change[i].Count = ChangeCount16 + ChangeCount32;
  1098.         Change[i].Palette = &Palette[palettecount];
  1099.  
  1100.         for(n = 0; n < Change[i].Count; n++ ) {
  1101.             if( palettecount >= PCHG->TotalChanges ) goto fail;
  1102.             if( datasize < 2 ) goto fail;
  1103.             SmallChange = BIG_WORD(data);
  1104.             data += 2; datasize -= 2;
  1105.  
  1106.             Palette[palettecount].Register = (SmallChange >> 12) & 0x0f;
  1107.             if( n >= ChangeCount16 )
  1108.                 Palette[palettecount].Register += 16;
  1109.             Palette[palettecount].Alpha = 0;
  1110.             Palette[palettecount].Red   = (SmallChange >> 8) & 0x0f;
  1111.             Palette[palettecount].Green = (SmallChange >> 4) & 0x0f;
  1112.             Palette[palettecount].Blue  = SmallChange & 0x0f;
  1113.             palettecount++;
  1114.         }
  1115.     }
  1116. #ifdef DEBUG
  1117.     pm_message("%ld palette change structures", palettecount);
  1118. #endif
  1119.     return;
  1120. fail:
  1121.     pchgerr("while building SmallLineChanges array");
  1122. }
  1123.  
  1124.  
  1125. static void
  1126. PCHG_ConvertBig(Info, data, datasize)
  1127.     PCHGInfo *Info;
  1128.     unsigned char *data;
  1129.     unsigned long datasize;
  1130. {
  1131.     PCHGHeader *PCHG        = Info->PCHG;
  1132.     LineChanges *Change     = Info->Change;
  1133.     PaletteChange *Palette  = Info->Palette;
  1134.     unsigned long i, palettecount = 0;
  1135.  
  1136.     Info->maxval = MAXCOLVAL;
  1137.  
  1138.     for( i = 0; i < PCHG->ChangedLines; i++ ) {
  1139.         int n;
  1140.  
  1141.         if( datasize < 2 ) goto fail;
  1142.         Change[i].Count = BIG_WORD(data);
  1143.         data += 2; datasize -= 2;
  1144.  
  1145.         Change[i].Palette = &Palette[palettecount];
  1146.  
  1147.         for( n = 0; n < Change[i].Count; n++ ) {
  1148.             if( palettecount >= PCHG->TotalChanges ) goto fail;
  1149.             if( datasize < 6 ) goto fail;
  1150.             Palette[palettecount].Register = BIG_WORD(data);
  1151.             data += 2;
  1152.             Palette[palettecount].Alpha = *data++;
  1153.             Palette[palettecount].Red   = *data++;
  1154.             Palette[palettecount].Blue  = *data++;  /* yes, RBG */
  1155.             Palette[palettecount].Green = *data++;
  1156.             palettecount++;
  1157.             datasize -= 6;
  1158.         }
  1159.     }
  1160. #ifdef DEBUG
  1161.     pm_message("%ld palette change structures", palettecount);
  1162. #endif
  1163.     return;
  1164. fail:
  1165.     pchgerr("while building BigLineChanges array");
  1166. }
  1167.  
  1168.  
  1169. static void
  1170. pchgerr(when)
  1171.     char *when;
  1172. {
  1173.     pm_message("insufficient data in PCHG chunk %s", when);
  1174.     pm_error("try the \"-ignore\" option to skip this chunk");
  1175. }
  1176.  
  1177.  
  1178. static void
  1179. PCHG_DecompHuff(src, dest, tree, origsize)
  1180.     unsigned char *src, *dest;
  1181.     short *tree;
  1182.     unsigned long origsize;
  1183. {
  1184.     unsigned long i = 0, bits = 0;
  1185.     unsigned char thisbyte;
  1186.     short *p;
  1187.  
  1188.     p = tree;
  1189.     while( i < origsize ) {
  1190.         if( bits == 0 ) {
  1191.             thisbyte = *src++;
  1192.             bits = 8;
  1193.         }
  1194.         if( thisbyte & (1 << 7) ) {
  1195.             if( *p >= 0 ) {
  1196.                 *dest++ = (unsigned char)*p;
  1197.                 i++;
  1198.                 p = tree;
  1199.             }
  1200.             else
  1201.                 p += (*p / 2);
  1202.         }
  1203.         else {
  1204.             p--;
  1205.             if( *p > 0 && (*p & 0x100) ) {
  1206.                 *dest++ = (unsigned char )*p;
  1207.                 i++;
  1208.                 p = tree;
  1209.             }
  1210.         }
  1211.         thisbyte <<= 1;
  1212.         bits--;
  1213.     }
  1214. }
  1215.  
  1216.  
  1217. static void
  1218. init_pchg(pchginfo, colormap, colors, newmaxval)
  1219.     PCHGInfo *pchginfo;
  1220.     pixel *colormap;
  1221.     int colors;
  1222.     pixval newmaxval;
  1223. {
  1224.     PCHGHeader    *PCHG    = pchginfo->PCHG;
  1225.     pixval oldmaxval       = pchginfo->maxval;
  1226.     int row;
  1227.  
  1228.     pchginfo->colormap = colormap;
  1229.     pchginfo->colors   = colors;
  1230.  
  1231.     if( oldmaxval != newmaxval ) {
  1232.         PaletteChange *Palette = pchginfo->Palette;
  1233.         unsigned long i;
  1234.  
  1235. #ifdef DEBUG
  1236.         pm_message("scaling PCHG palette from %d to %d", oldmaxval, newmaxval);
  1237. #endif
  1238.  
  1239.         for( i = 0; i < PCHG->TotalChanges; i++ ) {
  1240.             Palette[i].Red  = Palette[i].Red   * newmaxval / oldmaxval;
  1241.             Palette[i].Green= Palette[i].Green * newmaxval / oldmaxval;
  1242.             Palette[i].Blue = Palette[i].Blue  * newmaxval / oldmaxval;
  1243.         }
  1244.         pchginfo->maxval = newmaxval;
  1245.     }
  1246.  
  1247.     for( row = PCHG->StartLine; row < 0; row++ )
  1248.         adjust_colormap(pchginfo, row);
  1249. }
  1250.  
  1251.  
  1252. static void
  1253. adjust_colormap(pchginfo, row)
  1254.     PCHGInfo *pchginfo;
  1255.     int row;
  1256. {
  1257.     static unsigned long maskcount, changecount;
  1258.     static unsigned char thismask;
  1259.     static int bits;
  1260.  
  1261.     PCHGHeader *PCHG = pchginfo->PCHG;
  1262.  
  1263.     if( row < PCHG->StartLine || changecount >= PCHG->ChangedLines )
  1264.         return;
  1265.  
  1266.     if( bits == 0 ) {
  1267.         thismask = pchginfo->LineMask[maskcount++];
  1268.         bits = 8;
  1269.     }
  1270.  
  1271.     if( thismask & (1 << 7) ) {
  1272.         int i;
  1273.  
  1274.         for( i = 0; i < pchginfo->Change[changecount].Count; i++ ) {
  1275.             PaletteChange *pal = &(pchginfo->Change[changecount].Palette[i]);
  1276.             int reg = pal->Register;
  1277.  
  1278.             if( reg >= pchginfo->colors ) {
  1279.                 pm_message("warning - PCHG palette change register value out of range");
  1280.                 pm_message("    row %d  change structure %ld  palette %d", row, changecount, i);
  1281.                 pm_message("    ignoring it... colors might get messed up from here");
  1282.             }
  1283.         else
  1284.           PPM_ASSIGN(pchginfo->colormap[reg], pal->Red, pal->Green, pal->Blue);
  1285.     }
  1286.         changecount++;
  1287.     }
  1288.     thismask <<= 1;
  1289.     bits--;
  1290. }
  1291.  
  1292.  
  1293. static void
  1294. scale_colormap(colormap, colors, oldmaxval, newmaxval)
  1295.     pixel *colormap;
  1296.     int colors;
  1297.     pixval oldmaxval, newmaxval;
  1298. {
  1299.     int i, r, g, b;
  1300.  
  1301.     for( i = 0; i < colors; i++ ) {
  1302.         r = PPM_GETR(colormap[i]) * newmaxval / oldmaxval;
  1303.         g = PPM_GETG(colormap[i]) * newmaxval / oldmaxval;
  1304.         b = PPM_GETB(colormap[i]) * newmaxval / oldmaxval;
  1305.         PPM_ASSIGN(colormap[i], r, g, b);
  1306.     }
  1307. }
  1308.  
  1309.