home *** CD-ROM | disk | FTP | other *** search
/ AMIGA PD 1 / AMIGA-PD-1.iso / Programme_zum_Heft / Anwendungen / Kurztests / PBM / ILBMTOPPM.LHA / src / ppmtoilbm.c < prev   
C/C++ Source or Header  |  1994-12-16  |  62KB  |  1,854 lines

  1. /* ppmtoilbm.c - read a portable pixmap and produce an IFF ILBM file
  2. **
  3. ** Copyright (C) 1989 by Jef Poskanzer.
  4. ** Modified by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
  5. **  20/Jun/93:
  6. **  - 24-bit support (new options -24if, -24force)
  7. **  - HAM8 support (well, anything from HAM3 to HAM(MAXPLANES))
  8. **  - now writes up to 8 (16) planes (new options -maxplanes, -fixplanes)
  9. **  - colormap file (new option -map)
  10. **  - write colormap only (new option -cmaponly)
  11. **  - only writes CAMG chunk if it is a HAM-picture
  12. **  29/Aug/93:
  13. **  - operates row-by-row whenever possible
  14. **  - faster colorscaling with lookup-table (~20% faster on HAM pictures)
  15. **  - options -ham8 and -ham6 now imply -hamforce
  16. **  27/Nov/93:
  17. **  - byterun1 compression (this is now default) with new options:
  18. **    -compress, -nocompress, -cmethod, -savemem
  19. **  - floyd-steinberg error diffusion (for std+mapfile and HAM)
  20. **  - new options: -lace and -hires --> write CAMG chunk
  21. **  - LUT for luminance calculation (used by ppm_to_ham)
  22. **  23/Oct/94
  23. **  - rework of mapfile handling
  24. **  - added RGB8 & RGBN image types
  25. **  - added maskplane and transparent color support
  26. **  - 24-bit & direct color modified to n-bit deep ILBM
  27. **
  28. **
  29. **           std   HAM  deep  cmap  RGB8  RGBN
  30. **  -------+-----+-----+-----+-----+-----+-----
  31. **  BMHD     yes   yes   yes   yes   yes   yes
  32. **  CMAP     yes   (1)   no    yes   no    no
  33. **  BODY     yes   yes   yes   no    yes   yes
  34. **  CAMG     (2)   yes   (2)   no    yes   yes
  35. **  nPlanes  1-16  3-16  3-48  0     25    13
  36. **
  37. **  (1): grayscale colormap
  38. **  (2): only if "-lace" or "-hires" option used
  39. **
  40. ** Permission to use, copy, modify, and distribute this software and its
  41. ** documentation for any purpose and without fee is hereby granted, provided
  42. ** that the above copyright notice appear in all copies and that both that
  43. ** copyright notice and this permission notice appear in supporting
  44. ** documentation.  This software is provided "as is" without express or
  45. ** implied warranty.
  46. */
  47.  
  48. #include "ppm.h"
  49. #include "ppmcmap.h"
  50. #include "pbm.h"
  51. #include "ilbm.h"
  52.  
  53. /* as long as the libfloyd & libcmap2 routines are not part of the "official"
  54.  * libppm we cheat by including the C-source here...
  55.  */
  56. #include "libfloyd.c"
  57. #include "libcmap2.c"
  58. /*#include "ppmfloyd.h"*/
  59. /*#include "ppmcmap2.h"*/
  60.  
  61. /*#define DEBUG*/
  62.  
  63. #define MODE_RGB8       5   /* RGB8: 8-bit RGB */
  64. #define MODE_RGBN       4   /* RGBN: 4-bit RGB */
  65. #define MODE_CMAP       3   /* ILBM: colormap only */
  66. #define MODE_DEEP       2   /* ILBM: deep (24-bit) */
  67. #define MODE_HAM        1   /* ILBM: hold-and-modify (HAM) */
  68. #define MODE_NONE       0   /* ILBM: colormapped */
  69.  
  70. #define ECS_MAXPLANES   5
  71. #define ECS_HAMPLANES   6
  72. #define AGA_MAXPLANES   8
  73. #define AGA_HAMPLANES   8
  74.  
  75. #define HAMMAXPLANES    10  /* maximum planes for HAM */
  76.  
  77. #ifdef AMIGA_AGA
  78. #define DEF_MAXPLANES   AGA_MAXPLANES
  79. #define DEF_HAMPLANES   AGA_HAMPLANES
  80. #else
  81. #define DEF_MAXPLANES   ECS_MAXPLANES
  82. #define DEF_HAMPLANES   ECS_HAMPLANES
  83. #endif
  84. #define DEF_COMPRESSION cmpByteRun1
  85. #define DEF_DEEPPLANES  5
  86.  
  87. static int colorstobpp ARGS((int colors));
  88. static void put_big_short ARGS((short s));
  89. static void put_big_long ARGS((long l));
  90. #define put_byte(b)     (void)(putc((unsigned char)(b), stdout))
  91. static void write_bytes ARGS((unsigned char *buffer, int bytes));
  92. static void ppm_to_ham ARGS((FILE *fp, int cols, int rows, int maxval, int hambits, int nocolor));
  93. static void ppm_to_deep ARGS((FILE *fp, int cols, int rows, int maxval, int bitspercolor));
  94. static void ppm_to_rgb8 ARGS((FILE *fp, int cols, int rows, int maxval));
  95. static void ppm_to_rgbn ARGS((FILE *fp, int cols, int rows, int maxval));
  96. static void ppm_to_std ARGS((FILE *fp, int cols, int rows, int maxval, pixel *colormap, int colors, int maxcolors, int nPlanes));
  97. static void ppm_to_cmap ARGS((int maxval, pixel *colormap, int colors));
  98. static void write_bmhd ARGS((int cols, int rows, int nPlanes));
  99. static void write_cmap ARGS((pixel *colormap, int colors, int maxval));
  100. static long encode_row ARGS((FILE *outfile, rawtype *rawrow, int cols, int nPlanes));
  101. static long encode_maskrow ARGS((FILE *outfile, rawtype *rawrow, int cols));
  102. static int compress_row ARGS((int bytes));
  103. static void store_bodyrow ARGS((unsigned char *row, int len));
  104. static int runbyte1 ARGS((int bytes));
  105. static pixel * next_pixrow ARGS((FILE *fp, int row));
  106. static int * make_val_table ARGS((int oldmaxval, int newmaxval));
  107. static void * xmalloc ARGS((int bytes));
  108. #define MALLOC(n, type)     (type *)xmalloc((n) * sizeof(type))
  109. static void init_read ARGS((FILE *fp, int *colsP, int *rowsP, pixval *maxvalP, int *formatP, int readall));
  110. static void write_body_rows ARGS((void));
  111. static void write_camg ARGS((void));
  112. #define PAD(n)      (odd(n) ? 1 : 0)    /* pad to a word */
  113.  
  114.  
  115. /* global data */
  116. static unsigned char *coded_rowbuf; /* buffer for uncompressed scanline */
  117. static unsigned char *compr_rowbuf; /* buffer for compressed scanline */
  118. static pixel **pixels;  /* PPM image (NULL for row-by-row operation) */
  119. static pixel *pixrow;   /* current row in PPM image (pointer into pixels array, or buffer for row-by-row operation) */
  120.  
  121. static long viewportmodes = 0;
  122. static int slicesize = 1;       /* rows per slice for multipalette images - NOT USED */
  123.  
  124. static unsigned char compmethod = cmpByteRun1;      /* default compression */
  125. static unsigned char maskmethod = mskNone;
  126.  
  127. static pixel *transpColor = NULL;   /* transparent color */
  128. static short  transpIndex = -1;     /* index of transparent color */
  129.  
  130. static FILE *maskfile = NULL;
  131. static bit *maskrow = NULL;
  132. static int maskcols, maskformat;
  133. #define TOTALPLANES(nplanes)       ((nplanes) + ((maskmethod == mskHasMask) ? 1 : 0))
  134.  
  135.  
  136. #define ROWS_PER_BLOCK  1024
  137. typedef struct bodyblock {
  138.     int used;
  139.     unsigned char *row[ROWS_PER_BLOCK];
  140.     int            len[ROWS_PER_BLOCK];
  141.     struct bodyblock *next;
  142. } bodyblock;
  143. static bodyblock firstblock = { 0 };
  144. static bodyblock *cur_block = &firstblock;
  145.  
  146.  
  147. /* flags */
  148. static short compr_force = 0;   /* force compressed output, even if the image got larger  - NOT USED */
  149. static short floyd = 0;         /* apply floyd-steinberg error diffusion */
  150.  
  151. #define WORSTCOMPR(bytes)       ((bytes) + (bytes)/128 + 1)
  152. #define DO_COMPRESS             (compmethod != cmpNone)
  153.  
  154.  
  155.  
  156. /* Lookup tables for fast RGB -> luminance calculation. */
  157. /* taken from ppmtopgm.c   -IUW */
  158.  
  159. static int times77[256] = {
  160.             0,    77,   154,   231,   308,   385,   462,   539,
  161.           616,   693,   770,   847,   924,  1001,  1078,  1155,
  162.          1232,  1309,  1386,  1463,  1540,  1617,  1694,  1771,
  163.          1848,  1925,  2002,  2079,  2156,  2233,  2310,  2387,
  164.          2464,  2541,  2618,  2695,  2772,  2849,  2926,  3003,
  165.          3080,  3157,  3234,  3311,  3388,  3465,  3542,  3619,
  166.          3696,  3773,  3850,  3927,  4004,  4081,  4158,  4235,
  167.          4312,  4389,  4466,  4543,  4620,  4697,  4774,  4851,
  168.          4928,  5005,  5082,  5159,  5236,  5313,  5390,  5467,
  169.          5544,  5621,  5698,  5775,  5852,  5929,  6006,  6083,
  170.          6160,  6237,  6314,  6391,  6468,  6545,  6622,  6699,
  171.          6776,  6853,  6930,  7007,  7084,  7161,  7238,  7315,
  172.          7392,  7469,  7546,  7623,  7700,  7777,  7854,  7931,
  173.          8008,  8085,  8162,  8239,  8316,  8393,  8470,  8547,
  174.          8624,  8701,  8778,  8855,  8932,  9009,  9086,  9163,
  175.          9240,  9317,  9394,  9471,  9548,  9625,  9702,  9779,
  176.          9856,  9933, 10010, 10087, 10164, 10241, 10318, 10395,
  177.         10472, 10549, 10626, 10703, 10780, 10857, 10934, 11011,
  178.         11088, 11165, 11242, 11319, 11396, 11473, 11550, 11627,
  179.         11704, 11781, 11858, 11935, 12012, 12089, 12166, 12243,
  180.         12320, 12397, 12474, 12551, 12628, 12705, 12782, 12859,
  181.         12936, 13013, 13090, 13167, 13244, 13321, 13398, 13475,
  182.         13552, 13629, 13706, 13783, 13860, 13937, 14014, 14091,
  183.         14168, 14245, 14322, 14399, 14476, 14553, 14630, 14707,
  184.         14784, 14861, 14938, 15015, 15092, 15169, 15246, 15323,
  185.         15400, 15477, 15554, 15631, 15708, 15785, 15862, 15939,
  186.         16016, 16093, 16170, 16247, 16324, 16401, 16478, 16555,
  187.         16632, 16709, 16786, 16863, 16940, 17017, 17094, 17171,
  188.         17248, 17325, 17402, 17479, 17556, 17633, 17710, 17787,
  189.         17864, 17941, 18018, 18095, 18172, 18249, 18326, 18403,
  190.         18480, 18557, 18634, 18711, 18788, 18865, 18942, 19019,
  191.         19096, 19173, 19250, 19327, 19404, 19481, 19558, 19635 };
  192. static int times150[256] = {
  193.             0,   150,   300,   450,   600,   750,   900,  1050,
  194.          1200,  1350,  1500,  1650,  1800,  1950,  2100,  2250,
  195.          2400,  2550,  2700,  2850,  3000,  3150,  3300,  3450,
  196.          3600,  3750,  3900,  4050,  4200,  4350,  4500,  4650,
  197.          4800,  4950,  5100,  5250,  5400,  5550,  5700,  5850,
  198.          6000,  6150,  6300,  6450,  6600,  6750,  6900,  7050,
  199.          7200,  7350,  7500,  7650,  7800,  7950,  8100,  8250,
  200.          8400,  8550,  8700,  8850,  9000,  9150,  9300,  9450,
  201.          9600,  9750,  9900, 10050, 10200, 10350, 10500, 10650,
  202.         10800, 10950, 11100, 11250, 11400, 11550, 11700, 11850,
  203.         12000, 12150, 12300, 12450, 12600, 12750, 12900, 13050,
  204.         13200, 13350, 13500, 13650, 13800, 13950, 14100, 14250,
  205.         14400, 14550, 14700, 14850, 15000, 15150, 15300, 15450,
  206.         15600, 15750, 15900, 16050, 16200, 16350, 16500, 16650,
  207.         16800, 16950, 17100, 17250, 17400, 17550, 17700, 17850,
  208.         18000, 18150, 18300, 18450, 18600, 18750, 18900, 19050,
  209.         19200, 19350, 19500, 19650, 19800, 19950, 20100, 20250,
  210.         20400, 20550, 20700, 20850, 21000, 21150, 21300, 21450,
  211.         21600, 21750, 21900, 22050, 22200, 22350, 22500, 22650,
  212.         22800, 22950, 23100, 23250, 23400, 23550, 23700, 23850,
  213.         24000, 24150, 24300, 24450, 24600, 24750, 24900, 25050,
  214.         25200, 25350, 25500, 25650, 25800, 25950, 26100, 26250,
  215.         26400, 26550, 26700, 26850, 27000, 27150, 27300, 27450,
  216.         27600, 27750, 27900, 28050, 28200, 28350, 28500, 28650,
  217.         28800, 28950, 29100, 29250, 29400, 29550, 29700, 29850,
  218.         30000, 30150, 30300, 30450, 30600, 30750, 30900, 31050,
  219.         31200, 31350, 31500, 31650, 31800, 31950, 32100, 32250,
  220.         32400, 32550, 32700, 32850, 33000, 33150, 33300, 33450,
  221.         33600, 33750, 33900, 34050, 34200, 34350, 34500, 34650,
  222.         34800, 34950, 35100, 35250, 35400, 35550, 35700, 35850,
  223.         36000, 36150, 36300, 36450, 36600, 36750, 36900, 37050,
  224.         37200, 37350, 37500, 37650, 37800, 37950, 38100, 38250 };
  225. static int times29[256] = {
  226.             0,    29,    58,    87,   116,   145,   174,   203,
  227.           232,   261,   290,   319,   348,   377,   406,   435,
  228.           464,   493,   522,   551,   580,   609,   638,   667,
  229.           696,   725,   754,   783,   812,   841,   870,   899,
  230.           928,   957,   986,  1015,  1044,  1073,  1102,  1131,
  231.          1160,  1189,  1218,  1247,  1276,  1305,  1334,  1363,
  232.          1392,  1421,  1450,  1479,  1508,  1537,  1566,  1595,
  233.          1624,  1653,  1682,  1711,  1740,  1769,  1798,  1827,
  234.          1856,  1885,  1914,  1943,  1972,  2001,  2030,  2059,
  235.          2088,  2117,  2146,  2175,  2204,  2233,  2262,  2291,
  236.          2320,  2349,  2378,  2407,  2436,  2465,  2494,  2523,
  237.          2552,  2581,  2610,  2639,  2668,  2697,  2726,  2755,
  238.          2784,  2813,  2842,  2871,  2900,  2929,  2958,  2987,
  239.          3016,  3045,  3074,  3103,  3132,  3161,  3190,  3219,
  240.          3248,  3277,  3306,  3335,  3364,  3393,  3422,  3451,
  241.          3480,  3509,  3538,  3567,  3596,  3625,  3654,  3683,
  242.          3712,  3741,  3770,  3799,  3828,  3857,  3886,  3915,
  243.          3944,  3973,  4002,  4031,  4060,  4089,  4118,  4147,
  244.          4176,  4205,  4234,  4263,  4292,  4321,  4350,  4379,
  245.          4408,  4437,  4466,  4495,  4524,  4553,  4582,  4611,
  246.          4640,  4669,  4698,  4727,  4756,  4785,  4814,  4843,
  247.          4872,  4901,  4930,  4959,  4988,  5017,  5046,  5075,
  248.          5104,  5133,  5162,  5191,  5220,  5249,  5278,  5307,
  249.          5336,  5365,  5394,  5423,  5452,  5481,  5510,  5539,
  250.          5568,  5597,  5626,  5655,  5684,  5713,  5742,  5771,
  251.          5800,  5829,  5858,  5887,  5916,  5945,  5974,  6003,
  252.          6032,  6061,  6090,  6119,  6148,  6177,  6206,  6235,
  253.          6264,  6293,  6322,  6351,  6380,  6409,  6438,  6467,
  254.          6496,  6525,  6554,  6583,  6612,  6641,  6670,  6699,
  255.          6728,  6757,  6786,  6815,  6844,  6873,  6902,  6931,
  256.          6960,  6989,  7018,  7047,  7076,  7105,  7134,  7163,
  257.          7192,  7221,  7250,  7279,  7308,  7337,  7366,  7395 };
  258.  
  259.  
  260. /************ parse options and figure out what kind of ILBM to write ************/
  261.  
  262.  
  263. static int get_int_val ARGS((char *string, char *option, int bot, int top));
  264. static int get_compr_method ARGS((char *string));
  265. static int get_mask_type ARGS((char *string));
  266. #define NEWDEPTH(pix, table)    PPM_ASSIGN((pix), (table)[PPM_GETR(pix)], (table)[PPM_GETG(pix)], (table)[PPM_GETB(pix)])
  267.  
  268.  
  269. int
  270. main(argc, argv)
  271.     int argc;
  272.     char *argv[];
  273. {
  274.     FILE *ifp;
  275.     int argn, rows, cols, format, colors, nPlanes;
  276.     int ifmode, forcemode, maxplanes, fixplanes, mode;
  277.     int hambits;    /* really hamplanes */
  278.     int deepbits;   /* bits per color component in deep ILBM */
  279. #define MAXCOLORS       (1<<maxplanes)
  280.     pixval maxval;
  281.     pixel *colormap = NULL;
  282.     short sortcmap = 0;      /* sort colormap */
  283.     char *mapfile, *transpname;
  284.     char *usage =
  285. "[-ilbm|-rgb8|-rgbn]\
  286.  [-ecs|-aga] [-ham6|-ham8] [-maxplanes|-mp <n>] [-fixplanes|-fp <n>]\
  287.  [-normal|-hamif|-hamforce|-24if|-24force|-deepif|-deepforce|-cmaponly]\
  288.  [-hamplanes|-hambits <n>] [-deepplanes|-deepbits <n>]\
  289.  [-hires] [-lace] [-camg <hexval>]\
  290.  [-nocompress] [-cmethod none|byterun1]\
  291.  [-mapfile <ppmfile>] [-sortcmap] [-floyd|-fs]\
  292.  [-mmethod none|maskplane|transparentcolor|lasso] [-maskfile <pbmfile>]\
  293.  [-transparent <color>] [ppmfile]";
  294.  
  295.     ppm_init(&argc, argv);
  296.  
  297.     ifmode = MODE_NONE; forcemode = MODE_NONE;
  298.     maxplanes = DEF_MAXPLANES; fixplanes = 0;
  299.     hambits = DEF_HAMPLANES;
  300.     deepbits = DEF_DEEPPLANES;
  301.     mapfile = transpname = NULL;
  302.  
  303.     argn = 1;
  304.     while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
  305.         if( pm_keymatch(argv[argn], "-ilbm", 5) ) {
  306.             if( forcemode == MODE_RGB8 || forcemode == MODE_RGBN )
  307.                 forcemode = MODE_NONE;
  308.         }
  309.         else
  310.         if( pm_keymatch(argv[argn], "-rgb8", 5) )
  311.             forcemode = MODE_RGB8;
  312.         else
  313.         if( pm_keymatch(argv[argn], "-rgbn", 5) )
  314.             forcemode = MODE_RGBN;
  315.         else
  316.         if( pm_keymatch(argv[argn], "-maxplanes", 4) || pm_keymatch(argv[argn], "-mp", 3) ) {
  317.             if( ++argn >= argc )
  318.                 pm_usage(usage);
  319.             maxplanes = get_int_val(argv[argn], argv[argn-1], 1, MAXPLANES);
  320.             fixplanes = 0;
  321.         }
  322.         else
  323.         if( pm_keymatch(argv[argn], "-fixplanes", 4) || pm_keymatch(argv[argn], "-fp", 3) ) {
  324.             if( ++argn >= argc )
  325.                 pm_usage(usage);
  326.             fixplanes = get_int_val(argv[argn], argv[argn-1], 1, MAXPLANES);
  327.             maxplanes = fixplanes;
  328.         }
  329.         else
  330.         if( pm_keymatch(argv[argn], "-mapfile", 4) ) {
  331.             if( ++argn >= argc )
  332.                 pm_usage(usage);
  333.             mapfile = argv[argn];
  334.         }
  335.         else
  336.         if( pm_keymatch(argv[argn], "-mmethod", 3) ) {
  337.             if( ++argn >= argc )
  338.                 pm_usage(usage);
  339.             maskmethod = get_mask_type(argv[argn]);
  340.             switch( maskmethod ) {
  341.                 case mskNone:
  342.                 case mskHasMask:
  343.                 case mskHasTransparentColor:
  344.                     break;
  345.                 default:
  346.                     pm_error("masking method \"%s\" not supported yet", mskNAME[maskmethod]);
  347.             }
  348.         }
  349.         else
  350.         if( pm_keymatch(argv[argn], "-maskfile", 4) ) {
  351.             if( ++argn >= argc )
  352.                 pm_usage(usage);
  353.             maskfile = pm_openr(argv[argn]);
  354.             if( maskmethod == mskNone )
  355.                 maskmethod = mskHasMask;
  356.         }
  357.         else
  358.         if( pm_keymatch(argv[argn], "-transparent", 3) ) {
  359.             if( ++argn >= argc )
  360.                 pm_usage(usage);
  361.             transpname = argv[argn];
  362.             if( maskmethod == mskNone )
  363.                 maskmethod = mskHasTransparentColor;
  364.         }
  365.         else
  366.         if( pm_keymatch(argv[argn], "-sortcmap", 5) )
  367.             sortcmap = 1;
  368.         else
  369.         if( pm_keymatch(argv[argn], "-cmaponly", 3) ) {
  370.             forcemode = MODE_CMAP;
  371.         }
  372.         else
  373.         if( pm_keymatch(argv[argn], "-lace", 2) ) {
  374.             slicesize = 2;
  375.             viewportmodes |= vmLACE;
  376.         }
  377.         else
  378.         if( pm_keymatch(argv[argn], "-nolace", 4) ) {
  379.             slicesize = 1;
  380.             viewportmodes &= ~vmLACE;
  381.         }
  382.         else
  383.         if( pm_keymatch(argv[argn], "-hires", 3) )
  384.             viewportmodes |= vmHIRES;
  385.         else
  386.         if( pm_keymatch(argv[argn], "-nohires", 5) )
  387.             viewportmodes &= ~vmHIRES;
  388.         else
  389.         if( pm_keymatch(argv[argn], "-camg", 5) ) {
  390.             char *tail;
  391.             long value = 0L;
  392.  
  393.             if( ++argn >= argn )
  394.                 pm_usage(usage);
  395.             value = strtol(argv[argn], &tail, 16);
  396.             /* TODO: should do some error checking here */
  397.             viewportmodes |= value;
  398.         }
  399.         else
  400.         if( pm_keymatch(argv[argn], "-ecs", 2) ) {
  401.             maxplanes = ECS_MAXPLANES;
  402.             hambits = ECS_HAMPLANES;
  403.         }
  404.         else
  405.         if( pm_keymatch(argv[argn], "-aga", 2) ) {
  406.             maxplanes = AGA_MAXPLANES;
  407.             hambits = AGA_HAMPLANES;
  408.         }
  409.         else
  410.         if( pm_keymatch(argv[argn], "-hamplanes", 5) ) {
  411.             if( ++argn > argc )
  412.                 pm_usage(usage);
  413.             hambits = get_int_val(argv[argn], argv[argn-1], 3, HAMMAXPLANES);
  414.         }
  415.         else
  416.         if( pm_keymatch(argv[argn], "-hambits", 5) ) {
  417.             if( ++argn > argc )
  418.                 pm_usage(usage);
  419.             hambits = get_int_val(argv[argn], argv[argn-1], 3, HAMMAXPLANES-2) +2;
  420.         }
  421.         else
  422.         if( pm_keymatch(argv[argn], "-ham6", 5) ) {
  423.             hambits = ECS_HAMPLANES;
  424.             forcemode = MODE_HAM;
  425.         }
  426.         else
  427.         if( pm_keymatch(argv[argn], "-ham8", 5) ) {
  428.             hambits = AGA_HAMPLANES;
  429.             forcemode = MODE_HAM;
  430.         }
  431.         else
  432.         if( pm_keymatch(argv[argn], "-hamif", 5) )
  433.             ifmode = MODE_HAM;
  434.         else
  435.         if( pm_keymatch(argv[argn], "-nohamif", 7) ) {
  436.             if( ifmode == MODE_HAM )
  437.                 ifmode = MODE_NONE;
  438.         }
  439.         else
  440.         if( pm_keymatch(argv[argn], "-hamforce", 4) )
  441.             forcemode = MODE_HAM;
  442.         else
  443.         if( pm_keymatch(argv[argn], "-nohamforce", 6) ) {
  444.             if( forcemode == MODE_HAM )
  445.                 forcemode = MODE_NONE;
  446.         }
  447.         else
  448.         if( pm_keymatch(argv[argn], "-24if", 4) ) {
  449.             ifmode = MODE_DEEP;
  450.             deepbits = 8;
  451.         }
  452.         else
  453.         if( pm_keymatch(argv[argn], "-no24if", 6) ) {
  454.             if( ifmode == MODE_DEEP )
  455.                 ifmode = MODE_NONE;
  456.         }
  457.         else
  458.         if( pm_keymatch(argv[argn], "-24force", 3) ) {
  459.             forcemode = MODE_DEEP;
  460.             deepbits = 8;
  461.         }
  462.         else
  463.         if( pm_keymatch(argv[argn], "-no24force", 5) ) {
  464.             if( forcemode == MODE_DEEP )
  465.                 forcemode = MODE_NONE;
  466.         }
  467.         else
  468.         if( pm_keymatch(argv[argn], "-deepplanes", 6) ) {
  469.             if( ++argn > argc )
  470.                 pm_usage(usage);
  471.             deepbits = get_int_val(argv[argn], argv[argn-1], 3, 3*MAXPLANES);
  472.             if( deepbits % 3 != 0 )
  473.                 pm_error("option \"%s\" argument value must be divisible by 3", argv[argn-1]);
  474.             deepbits /= 3;
  475.         }
  476.         else
  477.         if( pm_keymatch(argv[argn], "-deepbits", 6) ) {
  478.             if( ++argn > argc )
  479.                 pm_usage(usage);
  480.             deepbits = get_int_val(argv[argn], argv[argn-1], 1, MAXPLANES);
  481.         }
  482.         else
  483.         if( pm_keymatch(argv[argn], "-deepif", 6) )
  484.             ifmode = MODE_DEEP;
  485.         else
  486.         if( pm_keymatch(argv[argn], "-nodeepif", 8) ) {
  487.             if( ifmode == MODE_DEEP )
  488.                 ifmode = MODE_NONE;
  489.         }
  490.         else
  491.         if( pm_keymatch(argv[argn], "-deepforce", 5) )
  492.             forcemode = MODE_DEEP;
  493.         else
  494.         if( pm_keymatch(argv[argn], "-nodeepforce", 7) ) {
  495.             if( forcemode == MODE_DEEP )
  496.                 forcemode = MODE_NONE;
  497.         }
  498.         else
  499.         if( pm_keymatch(argv[argn], "-normal", 4) ) {
  500.             ifmode = forcemode = MODE_NONE;
  501.             compmethod = DEF_COMPRESSION;
  502.         }
  503.         else
  504.         if( pm_keymatch(argv[argn], "-compress", 3) ) {
  505.             compr_force = 1;
  506.             if( compmethod == cmpNone )
  507.                 if( DEF_COMPRESSION == cmpNone )
  508.                     compmethod = cmpByteRun1;
  509.                 else
  510.                     compmethod = DEF_COMPRESSION;
  511.         }
  512.         else
  513.         if( pm_keymatch(argv[argn], "-nocompress", 4) ) {
  514.             compr_force = 0;
  515.             compmethod = cmpNone;
  516.         }
  517.         else
  518.         if( pm_keymatch(argv[argn], "-cmethod", 4) ) {
  519.             if( ++argn >= argc )
  520.                 pm_usage(usage);
  521.             compmethod = get_compr_method(argv[argn]);
  522.         }
  523.         else
  524.         if( pm_keymatch(argv[argn], "-floyd", 3) || pm_keymatch(argv[argn], "-fs", 3) )
  525.             floyd = 1;
  526.         else
  527.         if( pm_keymatch(argv[argn], "-nofloyd", 5) || pm_keymatch(argv[argn], "-nofs", 5) )
  528.             floyd = 0;
  529.         else
  530.             pm_usage(usage);
  531.         ++argn;
  532.     }
  533.  
  534.     if( argn < argc ) {
  535.         ifp = pm_openr(argv[argn]);
  536.         ++argn;
  537.     }
  538.     else
  539.         ifp = stdin;
  540.  
  541.     if( argn != argc )
  542.         pm_usage( usage );
  543.  
  544.     if( forcemode != MODE_NONE && mapfile != NULL )
  545.         pm_message("warning - mapfile only used for normal ILBMs");
  546.  
  547.     mode = forcemode;
  548.     switch( forcemode ) {
  549.         case MODE_HAM:
  550.             /* grayscale colormap for now - we don't need to read the whole
  551.                file into memory and can use row-by-row operation */
  552.             init_read(ifp, &cols, &rows, &maxval, &format, 0);
  553.             /*pm_message("hamforce option used - proceeding to write a HAM%d file", hambits);*/
  554.             break;
  555.         case MODE_DEEP:
  556.             init_read(ifp, &cols, &rows, &maxval, &format, 0);
  557.             /*pm_message("24force/deepforce option used - proceeding to write a %d-bit \'deep\' ILBM", deepbits*3);*/
  558.             break;
  559.         case MODE_RGB8:
  560.             init_read(ifp, &cols, &rows, &maxval, &format, 0);
  561.             /*pm_message("rgb8 option used - proceeding to write an IFF-RGB8 (24-bit RGB) file");*/
  562.             break;
  563.         case MODE_RGBN:
  564.             init_read(ifp, &cols, &rows, &maxval, &format, 0);
  565.             /*pm_message("rgbn option used - proceeding to write an IFF-RGBN (12-bit RGB) file");*/
  566.             break;
  567.         case MODE_CMAP:
  568.             /* Figure out the colormap. */
  569.             pm_message("computing colormap...");
  570.             colormap = ppm_mapfiletocolorrow(ifp, MAXCOLORS, &colors, &maxval);
  571.             if( colormap == NULL )
  572.                 pm_error("too many colors - try doing a 'ppmquant %d'", MAXCOLORS);
  573.             pm_message("%d colors found", colors);
  574.             break;
  575.         default:
  576.             /* must read the whole file into memory */
  577.             init_read(ifp, &cols, &rows, &maxval, &format, 1);
  578.  
  579.             /* Figure out the colormap. */
  580.             if( mapfile ) {
  581.                 pixval mapmaxval;
  582.                 FILE *mapfp;
  583.  
  584.                 pm_message("reading colormap file...");
  585.                 mapfp = pm_openr(mapfile);
  586.                 colormap = ppm_mapfiletocolorrow(mapfp, MAXCOLORS, &colors, &mapmaxval);
  587.                 pm_close(mapfp);
  588.                 if( colormap == NULL )
  589.                     pm_error("too many colors in mapfile for %d planes", maxplanes);
  590.                 if( colors == 0 )
  591.                     pm_error("empty colormap??");
  592.  
  593.                 /* if the maxvals of the ppmfile and the mapfile are the same,
  594.                  * then the scaling to MAXCOLVAL (if necessary) will be done by
  595.                  * the write_cmap() function.
  596.                  * Otherwise scale them both to MAXCOLVAL.
  597.                  */
  598.                 if( maxval != mapmaxval ) {
  599.                     if( mapmaxval != MAXCOLVAL ) {
  600.                         int *table;
  601.                         int col;
  602.                         pm_message("colormap maxval is not %d - rescaling colormap...", MAXCOLVAL);
  603.                         table = make_val_table(mapmaxval, MAXCOLVAL);
  604.                         for( col = 0; col < colors; ++col )
  605.                                 NEWDEPTH(colormap[col], table);
  606.                         mapmaxval = MAXCOLVAL;
  607.                         free(table);
  608.                     }
  609.  
  610.                     if( maxval != mapmaxval ) {
  611.                         int col, row;
  612.                         int *table;
  613.                         pixel *pP;
  614.  
  615.                         pm_message("rescaling colors of picture...");
  616.                         table = make_val_table(maxval, mapmaxval);
  617.                         for( row = 0; row < rows; ++row )
  618.                             for( col = 0, pP = pixels[row]; col < cols; ++col, ++pP )
  619.                                 NEWDEPTH(*pP, table);   /* was PPM_DEPTH( *pP, *pP, maxval, mapmaxval ); */
  620.                         maxval = mapmaxval;
  621.                         free(table);
  622.                     }
  623.                 }
  624.  
  625.                 pm_message("%d colors found in colormap", colors);
  626.             }
  627.             else {  /* no mapfile */
  628.                 pm_message("computing colormap...");
  629.                 colormap = ppm_computecolorrow(pixels, cols, rows, MAXCOLORS, &colors);
  630.                 if( colormap )
  631.                     pm_message("%d colors found", colors);
  632.                 else {  /* too many colors */
  633.                     mode = ifmode;
  634.                     switch( ifmode ) {
  635.                         case MODE_HAM:
  636.                             pm_message("too many colors - proceeding to write a HAM%d file", hambits);
  637.                             pm_message("if you want a non-HAM file, try doing a 'ppmquant %d'", MAXCOLORS);
  638.                             break;
  639.                         case MODE_DEEP:
  640.                             pm_message("too many colors - proceeding to write a %d-bit \'deep\' ILBM", deepbits*3);
  641.                             pm_message("if you want a non-deep file, try doing a 'ppmquant %d'", MAXCOLORS);
  642.                             break;
  643.                         default:
  644.                             pm_error("too many colors for %d planes - try doing a 'ppmquant %d'", maxplanes, MAXCOLORS);
  645.                             break;
  646.                     }
  647.                 }
  648.             }
  649.             nPlanes = colorstobpp(colors);
  650.             if( fixplanes > nPlanes )
  651.                 nPlanes = fixplanes;
  652.             break;
  653.     }
  654.  
  655.     if( maskmethod != mskNone ) {
  656.         if( transpname ) {
  657.             transpColor = MALLOC(1, pixel);
  658.             *transpColor = ppm_parsecolor(transpname, maxval);
  659.         }
  660.         if( maskfile ) {
  661.             int maskrows;
  662.             pbm_readpbminit(maskfile, &maskcols, &maskrows, &maskformat);
  663.             if( maskcols < cols || maskrows < rows )
  664.                 pm_error("maskfile too small - try scaling it");
  665.             if( maskcols > cols || maskrows > rows )
  666.                 pm_message("warning - maskfile larger than image");
  667.         }
  668.         else
  669.             maskcols = rows;
  670.         maskrow = pbm_allocrow(maskcols);
  671.     }
  672.  
  673.     if( mode != MODE_CMAP ) {
  674.         register int i;
  675.         coded_rowbuf = MALLOC(RowBytes(cols), unsigned char);
  676.         for( i = 0; i < RowBytes(cols); i++ )
  677.             coded_rowbuf[i] = 0;
  678.         if( DO_COMPRESS )
  679.             compr_rowbuf = MALLOC(WORSTCOMPR(RowBytes(cols)), unsigned char);
  680.     }
  681.  
  682.     if( sortcmap && colormap != NULL && colors != 0 )
  683.         ppm_sortcolorrow(colormap, colors, PPM_STDSORT);
  684.  
  685.     switch( mode ) {
  686.         case MODE_HAM: {
  687.             int nocolor;
  688.  
  689.             nocolor = !(PPM_FORMAT_TYPE(format) == PPM_TYPE);
  690.             if( nocolor )
  691.                 floyd = 0;
  692.  
  693.             viewportmodes |= vmHAM;
  694.             ppm_to_ham(ifp, cols, rows, maxval, hambits, nocolor);
  695.             }
  696.             break;
  697.         case MODE_DEEP:
  698.             ppm_to_deep(ifp, cols, rows, maxval, deepbits);
  699.             break;
  700.         case MODE_RGB8:
  701.             ppm_to_rgb8(ifp, cols, rows, maxval);
  702.             break;
  703.         case MODE_RGBN:
  704.             ppm_to_rgbn(ifp, cols, rows, maxval);
  705.             break;
  706.         case MODE_CMAP:
  707.             ppm_to_cmap(maxval, colormap, colors);
  708.             break;
  709.         default:
  710.             if( mapfile == NULL )
  711.                 floyd = 0;          /* would only slow down conversion */
  712.             ppm_to_std(ifp, cols, rows, maxval, colormap, colors, MAXCOLORS, nPlanes);
  713.             break;
  714.     }
  715.     pm_close(ifp);
  716.     exit(0);
  717.     /*NOTREACHED*/
  718. }
  719.  
  720.  
  721. static int
  722. get_int_val(string, option, bot, top)
  723.     char *string, *option;
  724.     int bot, top;
  725. {
  726.     int val;
  727.  
  728.     if( sscanf(string, "%d", &val) != 1 )
  729.         pm_error("option \"%s\" needs integer argument", option);
  730.  
  731.     if( val < bot || val > top )
  732.         pm_error("option \"%s\" argument value out of range (%d..%d)", option, bot, top);
  733.  
  734.     return val;
  735. }
  736.  
  737.  
  738. static int
  739. get_compr_method(string)
  740.     char *string;
  741. {
  742.     if( pm_keymatch(string, "none", 1) )
  743.         return cmpNone;
  744.     else
  745.     if( pm_keymatch(string, "byterun1", 1) )
  746.         return cmpByteRun1;
  747.  
  748.     pm_error("unknown compression method: %s", string);
  749. }
  750.  
  751.  
  752. static int
  753. get_mask_type(string)
  754.     char *string;
  755. {
  756.     if( pm_keymatch(string, "none", 1) )
  757.         return mskNone;
  758.     else
  759.     if( pm_keymatch(string, "plane", 1) || pm_keymatch(string, "maskplane", 1) )
  760.         return mskHasMask;
  761.     else
  762.     if( pm_keymatch(string, "transparentcolor", 1) )
  763.         return mskHasTransparentColor;
  764.     else
  765.     if( pm_keymatch(string, "lasso", 1) == 0 )
  766.         return mskLasso;
  767.  
  768.     pm_error("unknown masking method: %s", string);
  769. }
  770.  
  771.  
  772. /************ colormap file ************/
  773.  
  774. static void
  775. ppm_to_cmap(maxval, colorrow, colors)
  776.     int maxval;
  777.     pixel *colorrow;
  778.     int colors;
  779. {
  780.     int formsize, cmapsize;
  781.  
  782.     cmapsize = colors * 3;
  783.  
  784.     formsize =
  785.         4 +                                 /* ILBM */
  786.         4 + 4 + BitMapHeaderSize +          /* BMHD size header */
  787.         4 + 4 + cmapsize + PAD(cmapsize);   /* CMAP size colormap */
  788.  
  789.     put_big_long(ID_FORM);
  790.     put_big_long(formsize);
  791.     put_big_long(ID_ILBM);
  792.  
  793.     write_bmhd(0, 0, 0);
  794.     write_cmap(colorrow, colors, maxval);
  795. }
  796.  
  797. /************ HAM ************/
  798.  
  799. static long do_ham_body     ARGS((FILE *ifp, FILE *ofp, int cols, int rows, pixval maxval, pixval hammaxval, int nPlanes, int colbits, int no));
  800.  
  801. static void
  802. ppm_to_ham(fp, cols, rows, maxval, hambits, nocolor)
  803.     FILE *fp;
  804.     int cols, rows, maxval, hambits, nocolor;
  805. {
  806.     int colors, colbits, nPlanes, i, hammaxval;
  807.     long oldsize, bodysize, formsize, cmapsize;
  808.     int *table = NULL;
  809.  
  810.     if( maskmethod == mskHasTransparentColor ) {
  811.         pm_message("masking method \"%s\" not usable with HAM - using \"%s\" instead",
  812.                     mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]);
  813.         maskmethod = mskHasMask;
  814.     }
  815.  
  816.     colbits = hambits-2;
  817.     colors = 1 << colbits;
  818.     hammaxval = pm_bitstomaxval(colbits);
  819.     nPlanes = hambits;
  820.     cmapsize = colors * 3;
  821.  
  822.     bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols);
  823.     if( DO_COMPRESS ) {
  824.         bodysize = do_ham_body(fp, NULL, cols, rows, maxval, hammaxval, nPlanes, colbits, nocolor);
  825.         if( bodysize > oldsize )
  826.             pm_message("warning - %s compression increases BODY size by %d%%", cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
  827.         else
  828.             pm_message("BODY compression (%s): %d%%", cmpNAME[compmethod], 100*(oldsize-bodysize)/oldsize);
  829. #if 0
  830.         if( bodysize > oldsize && !compr_force ) {
  831.             pm_message("%s compression would increase body size by %d%%", cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
  832.             pm_message("writing uncompressed image");
  833.             compmethod = cmpNone;
  834.             bodysize = oldsize;
  835.         }
  836. #endif
  837.     }
  838.  
  839.  
  840.     formsize =
  841.         4 +                                 /* ILBM */
  842.         4 + 4 + BitMapHeaderSize +          /* BMHD size header */
  843.         4 + 4 + cmapsize + PAD(cmapsize) +  /* CMAP size colormap */
  844.         4 + 4 + bodysize + PAD(bodysize);   /* BODY size data */
  845.     if( viewportmodes )
  846.         formsize += 4 + 4 + CAMGChunkSize;  /* CAMG size viewportmodes */
  847.  
  848.     put_big_long(ID_FORM);
  849.     put_big_long(formsize);
  850.     put_big_long(ID_ILBM);
  851.  
  852.     write_bmhd(cols, rows, nPlanes);
  853.     if( viewportmodes )
  854.         write_camg();
  855.  
  856.     /* write grayscale colormap */
  857.     put_big_long(ID_CMAP);
  858.     put_big_long(cmapsize);
  859.     table = make_val_table(hammaxval, MAXCOLVAL);
  860.     for( i = 0; i < colors; i++ ) {
  861.         put_byte( table[i] );   /* red */
  862.         put_byte( table[i] );   /* green */
  863.         put_byte( table[i] );   /* blue */
  864.     }
  865.     free(table);
  866.     if( odd(cmapsize) )
  867.         put_byte(0);
  868.  
  869.     /* write body */
  870.     put_big_long(ID_BODY);
  871.     put_big_long(bodysize);
  872.     if( DO_COMPRESS )
  873.         write_body_rows();
  874.     else
  875.         do_ham_body(fp, stdout, cols, rows, maxval, hammaxval, nPlanes, colbits, nocolor);
  876. }
  877.  
  878.  
  879. static long
  880. #ifdef __STDC__
  881. do_ham_body(FILE *ifp, FILE *ofp, int cols, int rows,
  882.             pixval maxval, pixval hammaxval, int nPlanes,
  883.             int colbits, int nocolor)
  884. #else
  885. do_ham_body(ifp, ofp, cols, rows, maxval, hammaxval, nPlanes, colbits, nocolor)
  886.     FILE *ifp, *ofp;
  887.     int cols, rows;
  888.     pixval maxval, hammaxval;
  889.     int nPlanes, colbits, nocolor;
  890. #endif
  891. {
  892.     register int col, row;
  893.     pixel *pP;
  894.     int *table = NULL;
  895.     rawtype *raw_rowbuf;
  896.     ppm_fs_info *fi = NULL;
  897.     long bodysize = 0;
  898.  
  899.     raw_rowbuf = MALLOC(cols, rawtype);
  900.  
  901.     if( hammaxval != maxval )
  902.         table = make_val_table(maxval, hammaxval);
  903.  
  904.     if( floyd )
  905.         fi = ppm_fs_init(cols, maxval, 0);
  906.  
  907.  
  908.     for( row = 0; row < rows; row++ ) {
  909.         register int noprev, pr, pg, pb, r, g, b, l;
  910.         int fpr, fpg, fpb;      /* unscaled previous color values, for floyd */
  911.         pixel *prow;
  912.  
  913.         noprev = 1;
  914.         prow = next_pixrow(ifp, row);
  915.         for( col = ppm_fs_startrow(fi, prow); col < cols; col = ppm_fs_next(fi, col) ) {
  916.             int fr, fg, fb, fl;     /* unscaled color values, for floyd */
  917.  
  918.             pP = &prow[col];
  919.  
  920.             r = fr = PPM_GETR( *pP );
  921.             g = fg = PPM_GETG( *pP );
  922.             b = fb = PPM_GETB( *pP );
  923.             if( maxval <= 255 ) /* Use fast approximation to 0.299 r + 0.587 g + 0.114 b. */
  924.                 l = fl = (int)((times77[r] + times150[g] + times29[b] + 128) >> 8);
  925.             else /* Can't use fast approximation, so fall back on floats. */
  926.                 l = fl = (int)(PPM_LUMIN(*pP) + 0.5); /* -IUW added '+ 0.5' */
  927.  
  928.             if( table ) {
  929.                 r = table[r];
  930.                 g = table[g];
  931.                 b = table[b];
  932.                 l = table[l];
  933.             }
  934.  
  935.             if( noprev || nocolor ) {
  936.                 /* No previous pixels, gotta use the gray option. */
  937.                 raw_rowbuf[col] = l /* + (HAMCODE_CMAP << colbits) */;
  938.                 pr = pg = pb = l;
  939.                 fpr = fpg = fpb = fl;
  940.                 noprev = 0;
  941.             }
  942.             else {
  943.                 register int dred, dgreen, dblue, dgray;
  944.                 /* Compute distances for the four options. */
  945.                 dred = abs( g - pg ) + abs( b - pb );
  946.                 dgreen = abs( r - pr ) + abs( b - pb );
  947.                 dblue = abs( r - pr ) + abs( g - pg );
  948.                 dgray = abs( r - l ) + abs( g - l ) + abs( b - l );
  949.  
  950.                 if( dgray <= dred && dgray <= dgreen && dgray <= dblue ) {      /* -IUW  '<=' was '<'  */
  951.                     raw_rowbuf[col] = l /* + (HAMCODE_CMAP << colbits) */;
  952.                     pr = pg = pb = l;
  953.                     fpr = fpg = fpb = fl;
  954.                 }
  955.                 else
  956.                 if( dblue <= dred && dblue <= dgreen ) {
  957.                     raw_rowbuf[col] = b + (HAMCODE_BLUE << colbits);
  958.                     pb = b;
  959.                     fpb = fb;
  960.                 }
  961.                 else
  962.                 if( dred <= dgreen ) {
  963.                     raw_rowbuf[col] = r + (HAMCODE_RED << colbits);
  964.                     pr = r;
  965.                     fpr = fr;
  966.                 }
  967.                 else {
  968.                     raw_rowbuf[col] = g + (HAMCODE_GREEN << colbits);
  969.                     pg = g;
  970.                     fpg = fg;
  971.                 }
  972.             }
  973.             ppm_fs_update3(fi, col, fpr, fpg, fpb);
  974.         }
  975.         bodysize += encode_row(ofp, raw_rowbuf, cols, nPlanes);
  976.         if( maskmethod == mskHasMask )
  977.             bodysize += encode_maskrow(ofp, raw_rowbuf, cols);
  978.         ppm_fs_endrow(fi);
  979.     }
  980.     if( ofp && odd(bodysize) )
  981.         put_byte(0);
  982.  
  983.     /* clean up */
  984.     if( table )
  985.         free(table);
  986.     free(raw_rowbuf);
  987.     ppm_fs_free(fi);
  988.  
  989.     return bodysize;
  990. }
  991.  
  992. /************ deep (24-bit) ************/
  993.  
  994. static long do_deep_body      ARGS((FILE *ifp, FILE *ofp, int cols, int rows, pixval maxval, int bitspercolor));
  995.  
  996. static void
  997. ppm_to_deep(fp, cols, rows, maxval, bitspercolor)
  998.     FILE *fp;
  999.     int cols, rows, maxval, bitspercolor;
  1000. {
  1001.     int nPlanes;
  1002.     long bodysize, oldsize, formsize;
  1003.  
  1004.     if( maskmethod == mskHasTransparentColor ) {
  1005.         pm_message("masking method \"%s\" not usable with deep ILBM - using \"%s\" instead",
  1006.                     mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]);
  1007.         maskmethod = mskHasMask;
  1008.     }
  1009.  
  1010.     nPlanes = 3*bitspercolor;
  1011.  
  1012.     bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols);
  1013.     if( DO_COMPRESS ) {
  1014.         bodysize = do_deep_body(fp, NULL, cols, rows, maxval, bitspercolor);
  1015.         if( bodysize > oldsize )
  1016.             pm_message("warning - %s compression increases BODY size by %d%%", cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
  1017.         else
  1018.             pm_message("BODY compression (%s): %d%%", cmpNAME[compmethod], 100*(oldsize-bodysize)/oldsize);
  1019. #if 0
  1020.         if( bodysize > oldsize && !compr_force ) {
  1021.             pm_message("%s compression would increase body size by %d%%", cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
  1022.             pm_message("writing uncompressed image");
  1023.             compmethod = cmpNone;
  1024.             bodysize = oldsize;
  1025.         }
  1026. #endif
  1027.     }
  1028.  
  1029.  
  1030.     formsize =
  1031.         4 +                                 /* ILBM */
  1032.         4 + 4 + BitMapHeaderSize +          /* BMHD size header */
  1033.         4 + 4 + bodysize + PAD(bodysize);   /* BODY size data */
  1034.     if( viewportmodes )
  1035.         formsize += 4 + 4 + CAMGChunkSize;  /* CAMG size viewportmodes */
  1036.  
  1037.     put_big_long(ID_FORM);
  1038.     put_big_long(formsize);
  1039.     put_big_long(ID_ILBM);
  1040.  
  1041.     write_bmhd(cols, rows, nPlanes);
  1042.     if( viewportmodes )
  1043.         write_camg();
  1044.  
  1045.     /* write body */
  1046.     put_big_long(ID_BODY);
  1047.     put_big_long(bodysize);
  1048.     if( DO_COMPRESS )
  1049.         write_body_rows();
  1050.     else
  1051.         do_deep_body(fp, stdout, cols, rows, maxval, bitspercolor);
  1052. }
  1053.  
  1054.  
  1055. static long
  1056. #if __STDC__
  1057. do_deep_body(FILE *ifp, FILE *ofp, int cols, int rows, pixval maxval, int bitspercolor)
  1058. #else
  1059. do_deep_body(ifp, ofp, cols, rows, maxval, bitspercolor)
  1060.     FILE *ifp, *ofp;
  1061.     int cols, rows;
  1062.     pixval maxval;
  1063.     int bitspercolor;
  1064. #endif
  1065. {
  1066.     register int row, col;
  1067.     pixel *pP;
  1068.     int *table = NULL;
  1069.     long bodysize = 0;
  1070.     rawtype *redbuf, *greenbuf, *bluebuf;
  1071.     int newmaxval;
  1072.  
  1073.     redbuf   = MALLOC(cols, rawtype);
  1074.     greenbuf = MALLOC(cols, rawtype);
  1075.     bluebuf  = MALLOC(cols, rawtype);
  1076.  
  1077.     newmaxval = pm_bitstomaxval(bitspercolor);
  1078.     if( maxval != newmaxval ) {
  1079.         pm_message("maxval is not %d - automatically rescaling colors", newmaxval);
  1080.         table = make_val_table(maxval, newmaxval);
  1081.     }
  1082.  
  1083.     for( row = 0; row < rows; row++ ) {
  1084.         pP = next_pixrow(ifp, row);
  1085.         if( table ) {
  1086.             for( col = 0; col < cols; col++, pP++ ) {
  1087.                 redbuf[col]     = table[PPM_GETR(*pP)];
  1088.                 greenbuf[col]   = table[PPM_GETG(*pP)];
  1089.                 bluebuf[col]    = table[PPM_GETB(*pP)];
  1090.             }
  1091.         }
  1092.         else {
  1093.             for( col = 0; col < cols; col++, pP++ ) {
  1094.                 redbuf[col]     = PPM_GETR(*pP);
  1095.                 greenbuf[col]   = PPM_GETG(*pP);
  1096.                 bluebuf[col]    = PPM_GETB(*pP);
  1097.             }
  1098.         }
  1099.         bodysize += encode_row(ofp, redbuf,   cols, bitspercolor);
  1100.         bodysize += encode_row(ofp, greenbuf, cols, bitspercolor);
  1101.         bodysize += encode_row(ofp, bluebuf,  cols, bitspercolor);
  1102.         if( maskmethod == mskHasMask )
  1103.             bodysize += encode_maskrow(ofp, redbuf, cols);
  1104.     }
  1105.     if( ofp && odd(bodysize) )
  1106.         put_byte(0);
  1107.  
  1108.     /* clean up */
  1109.     if( table )
  1110.         free(table);
  1111.     free(redbuf);
  1112.     free(greenbuf);
  1113.     free(bluebuf);
  1114.  
  1115.     return bodysize;
  1116. }
  1117.  
  1118.  
  1119. /************ normal colormapped ************/
  1120.  
  1121. static long do_std_body     ARGS((FILE *ifp, FILE *ofp, int cols, int rows, pixval maxval, pixel *colormap, int colors, int nPlanes));
  1122.  
  1123. static void
  1124. ppm_to_std(fp, cols, rows, maxval, colormap, colors, maxcolors, nPlanes)
  1125.     FILE *fp;
  1126.     int cols, rows, maxval;
  1127.     pixel *colormap;
  1128.     int colors, maxcolors, nPlanes;
  1129. {
  1130.     long formsize, cmapsize, bodysize, oldsize;
  1131.  
  1132.     if( maskmethod == mskHasTransparentColor ) {
  1133.         if( transpColor ) {
  1134.             int oldcolors = colors;
  1135.             transpIndex = ppm_addtocolorrow(colormap, &colors, maxcolors, transpColor);
  1136.         }
  1137.         else
  1138.         if( colors < maxcolors )
  1139.             transpIndex = colors;
  1140.  
  1141.         if( transpIndex < 0 ) {
  1142.             pm_message("too many colors for masking method \"%s\" - using \"%s\" instead",
  1143.                         mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]);
  1144.             maskmethod = mskHasMask;
  1145.         }
  1146.     }
  1147.  
  1148.     bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols);
  1149.     if( DO_COMPRESS ) {
  1150.         bodysize = do_std_body(fp, NULL, cols, rows, maxval, colormap, colors, nPlanes);
  1151.         if( bodysize > oldsize )
  1152.             pm_message("warning - %s compression increases BODY size by %d%%", cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
  1153.         else
  1154.             pm_message("BODY compression (%s): %d%%", cmpNAME[compmethod], 100*(oldsize-bodysize)/oldsize);
  1155. #if 0
  1156.         if( bodysize > oldsize && !compr_force ) {
  1157.             pm_message("%s compression would increase body size by %d%%", cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize);
  1158.             pm_message("writing uncompressed image");
  1159.             compmethod = cmpNone;
  1160.             bodysize = oldsize;
  1161.         }
  1162. #endif
  1163.     }
  1164.  
  1165.     cmapsize = colors * 3;
  1166.  
  1167.     formsize =
  1168.         4 +                                 /* ILBM */
  1169.         4 + 4 + BitMapHeaderSize +          /* BMHD size header */
  1170.         4 + 4 + cmapsize + PAD(cmapsize) +  /* CMAP size colormap */
  1171.         4 + 4 + bodysize + PAD(bodysize);   /* BODY size data */
  1172.     if( viewportmodes )
  1173.         formsize += 4 + 4 + CAMGChunkSize;  /* CAMG size viewportmodes */
  1174.  
  1175.     put_big_long(ID_FORM);
  1176.     put_big_long(formsize);
  1177.     put_big_long(ID_ILBM);
  1178.  
  1179.     write_bmhd(cols, rows, nPlanes);
  1180.     if( viewportmodes )
  1181.         write_camg();
  1182.     write_cmap(colormap, colors, maxval);
  1183.  
  1184.     /* write body */
  1185.     put_big_long(ID_BODY);
  1186.     put_big_long(bodysize);
  1187.     if( DO_COMPRESS )
  1188.         write_body_rows();
  1189.     else
  1190.         do_std_body(fp, stdout, cols, rows, maxval, colormap, colors, nPlanes);
  1191. }
  1192.  
  1193.  
  1194. static long
  1195. #if __STDC__
  1196. do_std_body(FILE *ifp, FILE *ofp, int cols, int rows,
  1197.             pixval maxval, pixel *colormap, int colors, int nPlanes)
  1198. #else
  1199. do_std_body(ifp, ofp, cols, rows, maxval, colormap, colors, nPlanes)
  1200.     FILE *ifp, *ofp;
  1201.     int cols, rows;
  1202.     pixval maxval;
  1203.     pixel *colormap;
  1204.     int colors, nPlanes;
  1205. #endif
  1206. {
  1207.     register int row, col;
  1208.     pixel *pP;
  1209.     rawtype *raw_rowbuf;
  1210.     ppm_fs_info *fi = NULL;
  1211.     long bodysize = 0;
  1212.     int usehash = 1;
  1213.     colorhash_table cht;
  1214.  
  1215.     raw_rowbuf = MALLOC(cols, rawtype);
  1216.     cht = ppm_colorrowtocolorhash(colormap, colors);
  1217.     if( floyd )
  1218.         fi = ppm_fs_init(cols, maxval, FS_ALTERNATE);
  1219.  
  1220.     for( row = 0; row < rows; row++ ) {
  1221.         pixel *prow;
  1222.         prow = next_pixrow(ifp, row);
  1223.  
  1224.         for( col = ppm_fs_startrow(fi, prow); col < cols; col = ppm_fs_next(fi, col) ) {
  1225.             int ind;
  1226.  
  1227.             pP = &prow[col];
  1228.  
  1229.             if( maskmethod == mskHasTransparentColor && maskrow[col] == PBM_WHITE )
  1230.                 ind = transpIndex;
  1231.             else {
  1232.                 /* Check hash table to see if we have already matched this color. */
  1233.                 ind = ppm_lookupcolor(cht, pP);
  1234.                 if( ind == -1 ) {
  1235.                     ind = ppm_findclosestcolor(colormap, colors, pP);    /* No; search colormap for closest match. */
  1236.                     if( usehash ) {
  1237.                         if( ppm_addtocolorhash(cht, pP, ind) < 0 ) {
  1238.                             pm_message("out of memory adding to hash table, proceeding without it");
  1239.                             usehash = 0;
  1240.                         }
  1241.                     }
  1242.                 }
  1243.             }
  1244.             raw_rowbuf[col] = ind;
  1245.             ppm_fs_update(fi, col, &colormap[ind]);
  1246.         }
  1247.         bodysize += encode_row(ofp, raw_rowbuf, cols, nPlanes);
  1248.         if( maskmethod == mskHasMask )
  1249.             bodysize += encode_maskrow(ofp, raw_rowbuf, cols);
  1250.         ppm_fs_endrow(fi);
  1251.     }
  1252.     if( ofp && odd(bodysize) )
  1253.         put_byte(0);
  1254.  
  1255.     /* clean up */
  1256.     ppm_freecolorhash(cht);
  1257.     free(raw_rowbuf);
  1258.     ppm_fs_free(fi);
  1259.  
  1260.     return bodysize;
  1261. }
  1262.  
  1263. /************ RGB8 ************/
  1264.  
  1265. static void
  1266. ppm_to_rgb8(ifp, cols, rows, maxval)
  1267.     FILE *ifp;
  1268.     int cols, rows;
  1269.     int maxval;
  1270. {
  1271.     long bodysize, oldsize, formsize;
  1272.     pixel *pP;
  1273.     int *table = NULL;
  1274.     int row, col1, col2, compr_len, len;
  1275.     unsigned char *compr_row;
  1276.  
  1277.     maskmethod = 0;     /* no masking - RGB8 uses genlock bits */
  1278.     compmethod = 4;     /* RGB8 files are always compressed */
  1279.     compr_row = MALLOC(cols * 4, unsigned char);
  1280.  
  1281.     if( maxval != 255 ) {
  1282.         pm_message("maxval is not 255 - automatically rescaling colors");
  1283.         table = make_val_table(maxval, 255);
  1284.     }
  1285.  
  1286.     oldsize = cols * rows * 4;
  1287.     bodysize = 0;
  1288.     for( row = 0; row < rows; row++ ) {
  1289.         pP = next_pixrow(ifp, row);
  1290.         compr_len = 0;
  1291.         for( col1 = 0; col1 < cols; col1 = col2 ) {
  1292.             col2 = col1 + 1;
  1293.             if( maskrow ) {
  1294.                 while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) && maskrow[col1] == maskrow[col2] )
  1295.                     col2++;
  1296.             }
  1297.             else {
  1298.                 while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) )
  1299.                     col2++;
  1300.             }
  1301.             len = col2 - col1;
  1302.             while( len ) {
  1303.                 int count;
  1304.                 count = (len > 127 ? 127 : len);
  1305.                 len -= count;
  1306.                 if( table ) {
  1307.                     compr_row[compr_len++] = table[PPM_GETR(pP[col1])];
  1308.                     compr_row[compr_len++] = table[PPM_GETG(pP[col1])];
  1309.                     compr_row[compr_len++] = table[PPM_GETB(pP[col1])];
  1310.                 }
  1311.                 else {
  1312.                     compr_row[compr_len++] = PPM_GETR(pP[col1]);
  1313.                     compr_row[compr_len++] = PPM_GETG(pP[col1]);
  1314.                     compr_row[compr_len++] = PPM_GETB(pP[col1]);
  1315.                 }
  1316.                 compr_row[compr_len] = count;
  1317.                 if( maskrow && maskrow[col1] == PBM_WHITE )
  1318.                     compr_row[compr_len] |= 1<<7;     /* genlock bit */
  1319.                 ++compr_len;
  1320.             }
  1321.         }
  1322.         store_bodyrow(compr_row, compr_len);
  1323.         bodysize += compr_len;
  1324.     }
  1325.  
  1326.     pm_message("BODY compression: %d%%", 100*(oldsize-bodysize)/oldsize);
  1327.  
  1328.     formsize =
  1329.         4 +                                 /* RGB8 */
  1330.         4 + 4 + BitMapHeaderSize +          /* BMHD size header */
  1331.         4 + 4 + CAMGChunkSize +             /* CAMG size viewportmode */
  1332.         4 + 4 + bodysize + PAD(bodysize);   /* BODY size data */
  1333.  
  1334.     /* write header */
  1335.     put_big_long(ID_FORM);
  1336.     put_big_long(formsize);
  1337.     put_big_long(ID_RGB8);
  1338.  
  1339.     write_bmhd(cols, rows, 25);
  1340.     write_camg();               /* RGB8 requires CAMG chunk */
  1341.  
  1342.     put_big_long(ID_BODY);
  1343.     put_big_long(bodysize);
  1344.     write_body_rows();
  1345. }
  1346.  
  1347.  
  1348. /************ RGBN ************/
  1349.  
  1350. static void
  1351. ppm_to_rgbn(ifp, cols, rows, maxval)
  1352.     FILE *ifp;
  1353.     int cols, rows;
  1354.     int maxval;
  1355. {
  1356.     long bodysize, oldsize, formsize;
  1357.     pixel *pP;
  1358.     int *table = NULL;
  1359.     int row, col1, col2, compr_len, len;
  1360.     unsigned char *compr_row;
  1361.  
  1362.     maskmethod = 0;     /* no masking - RGBN uses genlock bits */
  1363.     compmethod = 4;     /* RGBN files are always compressed */
  1364.     compr_row = MALLOC(cols * 2, unsigned char);
  1365.  
  1366.     if( maxval != 15 ) {
  1367.         pm_message("maxval is not 15 - automatically rescaling colors");
  1368.         table = make_val_table(maxval, 15);
  1369.     }
  1370.  
  1371.     oldsize = cols * rows * 2;
  1372.     bodysize = 0;
  1373.     for( row = 0; row < rows; row++ ) {
  1374.         pP = next_pixrow(ifp, row);
  1375.         compr_len = 0;
  1376.         for( col1 = 0; col1 < cols; col1 = col2 ) {
  1377.             col2 = col1 + 1;
  1378.             if( maskrow ) {
  1379.                 while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) && maskrow[col1] == maskrow[col2] )
  1380.                     col2++;
  1381.             }
  1382.             else {
  1383.                 while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) )
  1384.                     col2++;
  1385.             }
  1386.             len = col2 - col1;
  1387.             while( len ) {
  1388.                 int count;
  1389.                 count = (len > 65535 ? 65535 : len);
  1390.                 len -= count;
  1391.                 if( table ) {
  1392.                     compr_row[compr_len]  = table[PPM_GETR(pP[col1])] << 4;
  1393.                     compr_row[compr_len] |= table[PPM_GETG(pP[col1])];
  1394.                     ++compr_len;
  1395.                     compr_row[compr_len]  = table[PPM_GETB(pP[col1])] << 4;
  1396.                 }
  1397.                 else {
  1398.                     compr_row[compr_len]  = PPM_GETR(pP[col1]) << 4;
  1399.                     compr_row[compr_len] |= PPM_GETG(pP[col1]);
  1400.                     ++compr_len;
  1401.                     compr_row[compr_len]  = PPM_GETB(pP[col1]) << 4;
  1402.                 }
  1403.                 if( maskrow && maskrow[col1] == PBM_WHITE )
  1404.                     compr_row[compr_len] |= 1<<3;   /* genlock bit */
  1405.                 if( count <= 7 )
  1406.                     compr_row[compr_len++] |= count;                    /* 3 bit repeat count */
  1407.                 else {
  1408.                     ++compr_len;                                        /* 3 bit repeat count = 0 */
  1409.                     if( count <= 255 )
  1410.                         compr_row[compr_len++] = (unsigned char)count;  /* byte repeat count */
  1411.                     else {
  1412.                         compr_row[compr_len++] = (unsigned char)0;      /* byte repeat count = 0 */
  1413.                         compr_row[compr_len++] = (count >> 8) & 0xff;   /* word repeat count MSB */
  1414.                         compr_row[compr_len++] = count & 0xff;          /* word repeat count LSB */
  1415.                     }
  1416.                 }
  1417.             }
  1418.         }
  1419.         store_bodyrow(compr_row, compr_len);
  1420.         bodysize += compr_len;
  1421.     }
  1422.  
  1423.     pm_message("BODY compression: %d%%", 100*(oldsize-bodysize)/oldsize);
  1424.  
  1425.     formsize =
  1426.         4 +                                 /* RGBN */
  1427.         4 + 4 + BitMapHeaderSize +          /* BMHD size header */
  1428.         4 + 4 + CAMGChunkSize +             /* CAMG size viewportmode */
  1429.         4 + 4 + bodysize + PAD(bodysize);   /* BODY size data */
  1430.  
  1431.     /* write header */
  1432.     put_big_long(ID_FORM);
  1433.     put_big_long(formsize);
  1434.     put_big_long(ID_RGBN);
  1435.  
  1436.     write_bmhd(cols, rows, 13);
  1437.     write_camg();               /* RGBN requires CAMG chunk */
  1438.  
  1439.     put_big_long(ID_BODY);
  1440.     put_big_long(bodysize);
  1441.     write_body_rows();
  1442. }
  1443.  
  1444.  
  1445. /************ multipalette ************/
  1446.  
  1447. #ifdef ILBM_PCHG
  1448. static pixel *ppmslice[2];  /* need 2 for laced ILBMs, else 1 */
  1449.  
  1450. void ppm_to_pchg()
  1451. {
  1452. /*
  1453.     read first slice
  1454.     build a colormap from this slice
  1455.     select upto <maxcolors> colors
  1456.     build colormap from selected colors
  1457.     map slice to colormap
  1458.     write slice
  1459.     while( !finished ) {
  1460.         read next slice
  1461.         compute distances for each pixel and select upto
  1462.             <maxchangesperslice> unused colors in this slice
  1463.         modify selected colors to the ones with maximum(?) distance
  1464.         map slice to colormap
  1465.         write slice
  1466.     }
  1467.  
  1468.  
  1469.     for HAM use a different mapping:
  1470.         compute distance to closest color in colormap
  1471.         if( there is no matching color in colormap ) {
  1472.             compute distances for the three "modify" cases
  1473.             use the shortest distance from the four cases
  1474.         }
  1475. */
  1476. }
  1477. #endif
  1478.  
  1479.  
  1480. /************ ILBM functions ************/
  1481.  
  1482. static void
  1483. write_cmap(colormap, colors, maxval)
  1484.     pixel *colormap;
  1485.     int colors, maxval;
  1486. {
  1487.     int cmapsize, i;
  1488.  
  1489.     cmapsize = 3 * colors;
  1490.  
  1491.     /* write colormap */
  1492.     put_big_long(ID_CMAP);
  1493.     put_big_long(cmapsize);
  1494.     if( maxval != MAXCOLVAL ) {
  1495.         int *table;
  1496.         pm_message("maxval is not %d - automatically rescaling colors", MAXCOLVAL);
  1497.         table = make_val_table(maxval, MAXCOLVAL);
  1498.         for( i = 0; i < colors; i++ ) {
  1499.             put_byte(table[PPM_GETR(colormap[i])]);
  1500.             put_byte(table[PPM_GETG(colormap[i])]);
  1501.             put_byte(table[PPM_GETB(colormap[i])]);
  1502.         }
  1503.         free(table);
  1504.     }
  1505.     else {
  1506.         for( i = 0; i < colors; i++ ) {
  1507.             put_byte(PPM_GETR(colormap[i]));
  1508.             put_byte(PPM_GETG(colormap[i]));
  1509.             put_byte(PPM_GETB(colormap[i]));
  1510.         }
  1511.     }
  1512.     if( odd(cmapsize) )
  1513.         put_byte(0);
  1514. }
  1515.  
  1516.  
  1517. static void
  1518. write_bmhd(cols, rows, nPlanes)
  1519.     int cols, rows, nPlanes;
  1520. {
  1521.     unsigned char xasp = 10, yasp = 10;
  1522.  
  1523.     if( viewportmodes & vmLACE )
  1524.         xasp *= 2;
  1525.     if( viewportmodes & vmHIRES )
  1526.         yasp *= 2;
  1527.  
  1528.     put_big_long(ID_BMHD);
  1529.     put_big_long(BitMapHeaderSize);
  1530.  
  1531.     put_big_short(cols);
  1532.     put_big_short(rows);
  1533.     put_big_short(0);                       /* x-offset */
  1534.     put_big_short(0);                       /* y-offset */
  1535.     put_byte(nPlanes);                      /* no of planes */
  1536.     put_byte(maskmethod);                   /* masking */
  1537.     put_byte(compmethod);                   /* compression */
  1538.     put_byte(BMHD_FLAGS_CMAPOK);            /* flags */
  1539.     if( maskmethod == mskHasTransparentColor )
  1540.         put_big_short(transpIndex);
  1541.     else
  1542.         put_big_short(0);
  1543.     put_byte(xasp);                         /* x-aspect */
  1544.     put_byte(yasp);                         /* y-aspect */
  1545.     put_big_short(cols);                    /* pageWidth */
  1546.     put_big_short(rows);                    /* pageHeight */
  1547. }
  1548.  
  1549.  
  1550. /* encode algorithm by Johan Widen (jw@jwdata.se) */
  1551. static const unsigned char bitmask[] = {1, 2, 4, 8, 16, 32, 64, 128};
  1552.  
  1553. static long
  1554. encode_row(outfile, rawrow, cols, nPlanes)
  1555.     FILE *outfile;  /* if non-NULL, write uncompressed row to this file */
  1556.     rawtype *rawrow;
  1557.     int cols, nPlanes;
  1558. {
  1559.     int plane, bytes;
  1560.     long retbytes = 0;
  1561.  
  1562.     bytes = RowBytes(cols);
  1563.  
  1564.     /* Encode and write raw bytes in plane-interleaved form. */
  1565.     for( plane = 0; plane < nPlanes; plane++ ) {
  1566.         register int col, cbit;
  1567.         register rawtype *rp;
  1568.         register unsigned char *cp;
  1569.         int mask;
  1570.  
  1571.         mask = 1 << plane;
  1572.         cbit = -1;
  1573.         cp = coded_rowbuf-1;
  1574.         rp = rawrow;
  1575.         for( col = 0; col < cols; col++, cbit--, rp++ ) {
  1576.             if( cbit < 0 ) {
  1577.                 cbit = 7;
  1578.                 *++cp = 0;
  1579.             }
  1580.             if( *rp & mask )
  1581.                 *cp |= bitmask[cbit];
  1582.         }
  1583.         if( outfile ) {
  1584.             write_bytes(coded_rowbuf, bytes);
  1585.             retbytes += bytes;
  1586.         }
  1587.         else
  1588.             retbytes += compress_row(bytes);
  1589.     }
  1590.     return retbytes;
  1591. }
  1592.  
  1593.  
  1594. static long
  1595. encode_maskrow(ofp, rawrow, cols)
  1596.     FILE *ofp;
  1597.     rawtype *rawrow;
  1598.     int cols;
  1599. {
  1600.     int col;
  1601.  
  1602.     for( col = 0; col < cols; col++ ) {
  1603.         if( maskrow[col] == PBM_BLACK )
  1604.             rawrow[col] = 1;
  1605.         else
  1606.             rawrow[col] = 0;
  1607.     }
  1608.     return encode_row(ofp, rawrow, cols, 1);
  1609. }
  1610.  
  1611.  
  1612. static int
  1613. compress_row(bytes)
  1614.     int bytes;
  1615. {
  1616.     int newbytes;
  1617.  
  1618.     switch( compmethod ) {
  1619.         case cmpByteRun1:
  1620.             newbytes = runbyte1(bytes);
  1621.             break;
  1622.         default:
  1623.             pm_error("compress_row(): unknown compression method %d\n", compmethod);
  1624.     }
  1625.     store_bodyrow(compr_rowbuf, newbytes);
  1626.  
  1627.     return newbytes;
  1628. }
  1629.  
  1630.  
  1631. static void
  1632. store_bodyrow(row, len)
  1633.     unsigned char *row;
  1634.     int len;
  1635. {
  1636.     int idx = cur_block->used;
  1637.     if( idx >= ROWS_PER_BLOCK ) {
  1638.         cur_block->next = MALLOC(1, bodyblock);
  1639.         cur_block = cur_block->next;
  1640.         cur_block->used = idx = 0;
  1641.         cur_block->next = NULL;
  1642.     }
  1643.     cur_block->row[idx] = MALLOC(len, unsigned char);
  1644.     cur_block->len[idx] = len;
  1645.     bcopy(row, cur_block->row[idx], len);
  1646.     cur_block->used++;
  1647. }
  1648.  
  1649.  
  1650. static void
  1651. write_body_rows ARGS((void))
  1652. {
  1653.     bodyblock *b;
  1654.     int i;
  1655.     long total = 0;
  1656.  
  1657.     for( b = &firstblock; b != NULL; b = b->next ) {
  1658.         for( i = 0; i < b->used; i++ ) {
  1659.             write_bytes(b->row[i], b->len[i]);
  1660.             total += b->len[i];
  1661.         }
  1662.     }
  1663.     if( odd(total) )
  1664.         put_byte(0);
  1665. }
  1666.  
  1667.  
  1668. static void
  1669. write_camg ARGS((void))
  1670. {
  1671.     put_big_long(ID_CAMG);
  1672.     put_big_long(CAMGChunkSize);
  1673.     put_big_long(viewportmodes);
  1674. }
  1675.  
  1676.  
  1677. /************ compression ************/
  1678.  
  1679.  
  1680. /* runbyte1 algorithm by Robert A. Knop (rknop@mop.caltech.edu) */
  1681. static int
  1682. runbyte1(size)
  1683.    int size;
  1684. {
  1685.     int in,out,count,hold;
  1686.     register unsigned char *inbuf = coded_rowbuf;
  1687.     register unsigned char *outbuf = compr_rowbuf;
  1688.  
  1689.  
  1690.     in=out=0;
  1691.     while( in<size ) {
  1692.         if( (in<size-1) && (inbuf[in]==inbuf[in+1]) ) {     /*Begin replicate run*/
  1693.             for( count=0,hold=in; in<size && inbuf[in]==inbuf[hold] && count<128; in++,count++)
  1694.                 ;
  1695.             outbuf[out++]=(unsigned char)(char)(-count+1);
  1696.             outbuf[out++]=inbuf[hold];
  1697.         }
  1698.         else {  /*Do a literal run*/
  1699.             hold=out; out++; count=0;
  1700.             while( ((in>=size-2)&&(in<size)) || ((in<size-2) && ((inbuf[in]!=inbuf[in+1])||(inbuf[in]!=inbuf[in+2]))) ) {
  1701.                 outbuf[out++]=inbuf[in++];
  1702.                 if( ++count>=128 )
  1703.                     break;
  1704.             }
  1705.             outbuf[hold]=count-1;
  1706.         }
  1707.     }
  1708.     return(out);
  1709. }
  1710.  
  1711.  
  1712.  
  1713. /************ other utility functions ************/
  1714.  
  1715. static int
  1716. colorstobpp(colors)
  1717.     int colors;
  1718. {
  1719.     int i;
  1720.  
  1721.     for( i = 1; i <= MAXPLANES; i++ ) {
  1722.         if( colors <= (1 << i) )
  1723.             return i;
  1724.     }
  1725.     pm_error("too many planes (max %d)", MAXPLANES);
  1726. }
  1727.  
  1728.  
  1729. static void
  1730. #if __STDC__
  1731. put_big_short(short s)
  1732. #else
  1733. put_big_short(s)
  1734.     short s;
  1735. #endif
  1736. {
  1737.     if ( pm_writebigshort( stdout, s ) == -1 )
  1738.         pm_error( "write error" );
  1739. }
  1740.  
  1741.  
  1742. static void
  1743. put_big_long(l)
  1744.     long l;
  1745. {
  1746.     if ( pm_writebiglong( stdout, l ) == -1 )
  1747.         pm_error( "write error" );
  1748. }
  1749.  
  1750.  
  1751. static void
  1752. write_bytes(buffer, bytes)
  1753.     unsigned char *buffer;
  1754.     int bytes;
  1755. {
  1756.     if( fwrite(buffer, 1, bytes, stdout) != bytes )
  1757.         pm_error("write error");
  1758. }
  1759.  
  1760.  
  1761. static int *
  1762. make_val_table(oldmaxval, newmaxval)
  1763.     int oldmaxval, newmaxval;
  1764. {
  1765.     int i;
  1766.     int *table;
  1767.  
  1768.     table = MALLOC(oldmaxval + 1, int);
  1769.     for(i = 0; i <= oldmaxval; i++ )
  1770.         table[i] = (i * newmaxval + oldmaxval/2) / oldmaxval;
  1771.  
  1772.     return table;
  1773. }
  1774.  
  1775.  
  1776. static void *
  1777. xmalloc(bytes)
  1778.     int bytes;
  1779. {
  1780.     void *mem;
  1781.  
  1782.     mem = malloc(bytes);
  1783.     if( mem == NULL )
  1784.         pm_error("out of memory allocating %d bytes", bytes);
  1785.     return mem;
  1786. }
  1787.  
  1788.  
  1789. static int  gFormat;
  1790. static int  gCols;
  1791. static int  gMaxval;
  1792.  
  1793. static void
  1794. init_read(fp, colsP, rowsP, maxvalP, formatP, readall)
  1795.     FILE *fp;
  1796.     int *colsP, *rowsP;
  1797.     pixval *maxvalP;
  1798.     int *formatP;
  1799.     int readall;
  1800. {
  1801.     ppm_readppminit(fp, colsP, rowsP, maxvalP, formatP);
  1802.     if( readall ) {
  1803.         int row;
  1804.  
  1805.         pixels = ppm_allocarray(*colsP, *rowsP);
  1806.         for( row = 0; row < *rowsP; row++ )
  1807.             ppm_readppmrow(fp, pixels[row], *colsP, *maxvalP, *formatP);
  1808.         /* pixels = ppm_readppm(fp, colsP, rowsP, maxvalP); */
  1809.     }
  1810.     else {
  1811.         pixrow = ppm_allocrow(*colsP);
  1812.     }
  1813.     gCols = *colsP;
  1814.     gMaxval = *maxvalP;
  1815.     gFormat = *formatP;
  1816. }
  1817.  
  1818.  
  1819. static pixel *
  1820. next_pixrow(fp, row)
  1821.     FILE *fp;
  1822.     int row;
  1823. {
  1824.     if( pixels )
  1825.         pixrow = pixels[row];
  1826.     else {
  1827. #ifdef DEBUG
  1828.         static int rowcnt;
  1829.         if( row != rowcnt )
  1830.             pm_error("big mistake");
  1831.         rowcnt++;
  1832. #endif
  1833.         ppm_readppmrow(fp, pixrow, gCols, gMaxval, gFormat);
  1834.     }
  1835.     if( maskrow ) {
  1836.         int col;
  1837.  
  1838.         if( maskfile )
  1839.             pbm_readpbmrow(maskfile, maskrow, maskcols, maskformat);
  1840.         else {
  1841.             for( col = 0; col < gCols; col++ )
  1842.                 maskrow[col] = PBM_BLACK;
  1843.         }
  1844.         if( transpColor ) {
  1845.             for( col = 0; col < gCols; col++ )
  1846.                 if( PPM_EQUAL(pixrow[col], *transpColor) )
  1847.                     maskrow[col] = PBM_WHITE;
  1848.         }
  1849.     }
  1850.     return pixrow;
  1851. }
  1852.  
  1853.  
  1854.