home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / NETWORK / netpbm_src.lzh / NETPBM / PPM / picttoppm.c < prev    next >
Text File  |  1996-11-26  |  75KB  |  3,345 lines

  1. /*
  2.  * picttoppm.c -- convert a MacIntosh PICT file to PPM format.
  3.  *
  4.  * This program is normally part of the PBM+ utilities, but you
  5.  * can compile a slightly crippled version without PBM+ by
  6.  * defining STANDALONE (e.g., cc -DSTANDALONE picttoppm.c).
  7.  * However, if you want this you probably want PBM+ sooner or
  8.  * later so grab it now.
  9.  *
  10.  * Copyright 1989,1992,1993 George Phillips
  11.  *
  12.  * Permission to use, copy, modify, and distribute this software and its
  13.  * documentation for any purpose and without fee is hereby granted, provided
  14.  * that the above copyright notice appear in all copies and that both that
  15.  * copyright notice and this permission notice appear in supporting
  16.  * documentation.  This software is provided "as is" without express or
  17.  * implied warranty.
  18.  *
  19.  * George Phillips <phillips@cs.ubc.ca>
  20.  * Department of Computer Science
  21.  * University of British Columbia
  22.  *
  23.  * $Id: picttoppm.c,v 1.7 1993/10/26 22:40:31 phillips Exp phillips $
  24.  */
  25.  
  26. #ifdef STANDALONE
  27.  
  28. #include <stdio.h>
  29. #ifdef __STDC__
  30. #define ARGS(x) x
  31. #else
  32. #define ARGS(x) ()
  33. #endif /* __STDC__ */
  34. #define PPM_ASSIGN(p, R, G, B) (p).r = R; (p).g = G; (p).b = B
  35. #define max(x, y) ((x) > (y) ? (x) : (y))
  36. #define min(x, y) ((x) < (y) ? (x) : (y))
  37. typedef unsigned char pixval;
  38. typedef struct { pixval r, g, b; } pixel;
  39. void ppm_init();
  40. FILE* pm_openr();
  41. void pm_usage();
  42. void pm_message();
  43. void pm_error();
  44. int pm_keymatch();
  45. void ppm_writeppminit();
  46. void ppm_writeppmrow();
  47. void pm_close();
  48. pixel* ppm_allocrow();
  49.  
  50. #else
  51.  
  52. #include "ppm.h"
  53.  
  54. #endif /* STANDALONE */
  55.  
  56. #include "pbmfont.h"
  57.  
  58. /*
  59.  * Typical byte, 2 byte and 4 byte integers.
  60.  */
  61. typedef unsigned char byte;
  62. typedef char signed_byte; /* XXX */
  63. typedef unsigned short word;
  64. typedef unsigned long longword;
  65.  
  66. /*
  67.  * Data structures for QuickDraw (and hence PICT) stuff.
  68.  */
  69.  
  70. struct Rect {
  71.     word top;
  72.     word left;
  73.     word bottom;
  74.     word right;
  75. };
  76.  
  77. struct pixMap {
  78.     struct Rect Bounds;
  79.     word version;
  80.     word packType;
  81.     longword packSize;
  82.     longword hRes;
  83.     longword vRes;
  84.     word pixelType;
  85.     word pixelSize;
  86.     word cmpCount;
  87.     word cmpSize;
  88.     longword planeBytes;
  89.     longword pmTable;
  90.     longword pmReserved;
  91. };
  92.  
  93. struct RGBColour {
  94.     word red;
  95.     word green;
  96.     word blue;
  97. };
  98.  
  99. struct Point {
  100.     word x;
  101.     word y;
  102. };
  103.  
  104. struct Pattern {
  105.     byte pix[64];
  106. };
  107.  
  108. typedef void (*transfer_func) ARGS(( struct RGBColour* src, struct RGBColour* dst ));
  109.  
  110. static char* stage;
  111. static struct Rect picFrame;
  112. static word* red;
  113. static word* green;
  114. static word* blue;
  115. static word rowlen;
  116. static word collen;
  117. static longword planelen;
  118. static int verbose;
  119. static int fullres;
  120. static int recognize_comment;
  121.  
  122. static struct RGBColour black = { 0, 0, 0 };
  123. static struct RGBColour white = { 0xffff, 0xffff, 0xffff };
  124.  
  125. /* various bits of drawing state */
  126. static struct RGBColour foreground = { 0, 0, 0 };
  127. static struct RGBColour background = { 0xffff, 0xffff, 0xffff };
  128. static struct RGBColour op_colour;
  129. static struct Pattern bkpat;
  130. static struct Pattern fillpat;
  131. static struct Rect clip_rect;
  132. static struct Rect cur_rect;
  133. static struct Point current;
  134. static struct Pattern pen_pat;
  135. static word pen_width;
  136. static word pen_height;
  137. static word pen_mode;
  138. static transfer_func pen_trf;
  139. static word text_font;
  140. static byte text_face;
  141. static word text_mode;
  142. static transfer_func text_trf;
  143. static word text_size;
  144. static struct font* tfont;
  145.  
  146. /* state for magic printer comments */
  147. static int ps_text;
  148. static byte ps_just;
  149. static byte ps_flip;
  150. static word ps_rotation;
  151. static byte ps_linespace;
  152. static int ps_cent_x;
  153. static int ps_cent_y;
  154. static int ps_cent_set;
  155.  
  156. struct opdef {
  157.     char* name;
  158.     int len;
  159.     void (*impl) ARGS((int));
  160.     char* description;
  161. };
  162.  
  163. struct blit_info {
  164.     struct Rect    srcRect;
  165.     struct Rect    srcBounds;
  166.     int        srcwid;
  167.     byte*        srcplane;
  168.     int        pixSize;
  169.     struct Rect    dstRect;
  170.     struct RGBColour* colour_map;
  171.     int        mode;
  172.     struct blit_info* next;
  173. };
  174.  
  175. static struct blit_info* blit_list = 0;
  176. static struct blit_info** last_bl = &blit_list;
  177.  
  178. #define WORD_LEN (-1)
  179.  
  180. static void interpret_pict ARGS(( void ));
  181. static void alloc_planes ARGS(( void ));
  182. static void compact_plane ARGS(( word* plane, int planelen ));
  183. static void output_ppm ARGS(( int version ));
  184. static void Opcode_9A ARGS(( int version ));
  185. static void BitsRect ARGS(( int version ));
  186. static void BitsRegion ARGS(( int version ));
  187. static void do_bitmap ARGS(( int version, int rowBytes, int is_region ));
  188. static void do_pixmap ARGS(( int version, word rowBytes, int is_region ));
  189. static transfer_func transfer ARGS(( int ));
  190. static void draw_pixel ARGS (( int, int, struct RGBColour*, transfer_func ));
  191. static int blit ARGS((
  192.     struct Rect* srcRect, struct Rect* srcBounds, int srcwid, byte* srcplane,
  193.     int pixSize, struct Rect* dstRect, struct Rect* dstBounds, int dstwid,
  194.     struct RGBColour* colour_map, int mode ));
  195. static struct blit_info* add_blit_list ARGS(( void ));
  196. static void do_blits ARGS(( void ));
  197. static byte* unpackbits ARGS(( struct Rect* bounds, word rowBytes, int pixelSize ));
  198. static byte* expand_buf ARGS(( byte* buf, int* len, int bits_per_pixel ));
  199. static void Clip ARGS(( int version ));
  200. static void read_pixmap ARGS(( struct pixMap* p, word* rowBytes ));
  201. static struct RGBColour* read_colour_table ARGS(( void ));
  202. static void BkPixPat ARGS(( int version ));
  203. static void PnPixPat ARGS(( int version ));
  204. static void FillPixPat ARGS(( int version ));
  205. static void read_pattern ARGS(( void ));
  206. static void read_8x8_pattern ARGS(( struct Pattern* ));
  207. static void BkPat ARGS(( int version ));
  208. static void PnPat ARGS(( int version ));
  209. static void FillPat ARGS(( int version ));
  210. static void PnSize ARGS(( int version ));
  211. static void PnMode ARGS(( int version ));
  212. static void OpColor ARGS(( int version ));
  213. static void RGBFgCol ARGS(( int version ));
  214. static void RGBBkCol ARGS(( int version ));
  215.  
  216. static void Line ARGS(( int version ));
  217. static void LineFrom ARGS(( int version ));
  218. static void ShortLine ARGS(( int version ));
  219. static void ShortLineFrom ARGS(( int version ));
  220.  
  221. static void PnLocHFrac ARGS(( int version ));
  222. static void TxFont ARGS(( int version ));
  223. static void TxFace ARGS(( int version ));
  224. static void TxMode ARGS(( int version ));
  225. static void TxSize ARGS(( int version ));
  226. static void skip_text ARGS(( void ));
  227. static void LongText ARGS(( int version ));
  228. static void DHText ARGS(( int version ));
  229. static void DVText ARGS(( int version ));
  230. static void DHDVText ARGS(( int version ));
  231. static void do_text ARGS(( word x, word y ));
  232. static void do_ps_text ARGS(( word x, word y ));
  233. static void rotate ARGS(( int* x, int* y));
  234. static void skip_poly_or_region ARGS(( int version ));
  235. static void LongComment ARGS(( int version ));
  236. static void ShortComment ARGS(( int version ));
  237.  
  238. static int rectwidth ARGS(( struct Rect* r ));
  239. static int rectheight ARGS(( struct Rect* r ));
  240. static int rectsamesize ARGS(( struct Rect* r1, struct Rect* r2 ));
  241. static void rectinter ARGS(( struct Rect* r1, struct Rect* r2, struct Rect* r3 ));
  242. static void rectscale ARGS(( struct Rect* r, double xscale, double yscale ));
  243.  
  244. static void read_rect ARGS(( struct Rect* r ));
  245. static void dump_rect ARGS(( char* s, struct Rect* r ));
  246.  
  247. static void do_paintRect ARGS(( struct Rect* r ));
  248. static void paintRect ARGS(( int version ));
  249. static void paintSameRect ARGS(( int version ));
  250. static void do_frameRect ARGS(( struct Rect* r ));
  251. static void frameRect ARGS(( int version ));
  252. static void frameSameRect ARGS(( int version ));
  253. static void paintPoly ARGS(( int version ));
  254.  
  255. static word get_op ARGS(( int version ));
  256.  
  257. static longword read_long ARGS(( void ));
  258. static word read_word ARGS(( void ));
  259. static byte read_byte ARGS(( void ));
  260. static signed_byte read_signed_byte ARGS(( void ));
  261.  
  262. static void skip ARGS(( int n ));
  263. static void read_n ARGS(( int n, char* buf ));
  264.  
  265. static struct font* get_font ARGS(( int font, int size, int style ));
  266.  
  267. static int load_fontdir ARGS((char *file));
  268. static void read_rgb ARGS((struct RGBColour *rgb));
  269. static void draw_pen_rect ARGS((struct Rect *r));
  270. static void draw_pen ARGS((int x, int y));
  271. static void read_point ARGS((struct Point *p));
  272. static void read_short_point ARGS((struct Point *p));
  273. static void scan_line ARGS((short x1, short y1, short x2, short y2));
  274. static void scan_poly ARGS((int np, struct Point pts[]));
  275. static void poly_sort ARGS((int sort_index, struct Point points[]));
  276. static void picComment ARGS((word type, int length));
  277. static int abs_value ARGS((int x));
  278. /*
  279.  * a table of the first 194(?) opcodes.  The table is too empty.
  280.  *
  281.  * Probably could use an entry specifying if the opcode is valid in version
  282.  * 1, etc.
  283.  */
  284.  
  285. /* for reserved opcodes of known length */
  286. #define res(length) \
  287. { "reserved", (length), NULL, "reserved for Apple use" }
  288.  
  289. /* for reserved opcodes of length determined by a function */
  290. #define resf(skipfunction) \
  291. { "reserved", NA, (skipfunction), "reserved for Apple use" }
  292.  
  293. /* seems like RGB colours are 6 bytes, but Apple says they're variable */
  294. /* I'll use 6 for now as I don't care that much. */
  295. #define RGB_LEN (6)
  296.  
  297. #define NA (0)
  298.  
  299. static struct opdef optable[] = {
  300. /* 0x00 */    { "NOP", 0, NULL, "nop" },
  301. /* 0x01 */    { "Clip", NA, Clip, "clip" },
  302. /* 0x02 */    { "BkPat", 8, BkPat, "background pattern" },
  303. /* 0x03 */    { "TxFont", 2, TxFont, "text font (word)" },
  304. /* 0x04 */    { "TxFace", 1, TxFace, "text face (byte)" },
  305. /* 0x05 */    { "TxMode", 2, TxMode, "text mode (word)" },
  306. /* 0x06 */    { "SpExtra", 4, NULL, "space extra (fixed point)" },
  307. /* 0x07 */    { "PnSize", 4, PnSize, "pen size (point)" },
  308. /* 0x08 */    { "PnMode", 2, PnMode, "pen mode (word)" },
  309. /* 0x09 */    { "PnPat", 8, PnPat, "pen pattern" },
  310. /* 0x0a */    { "FillPat", 8, FillPat, "fill pattern" },
  311. /* 0x0b */    { "OvSize", 4, NULL, "oval size (point)" },
  312. /* 0x0c */    { "Origin", 4, NULL, "dh, dv (word)" },
  313. /* 0x0d */    { "TxSize", 2, TxSize, "text size (word)" },
  314. /* 0x0e */    { "FgColor", 4, NULL, "foreground color (longword)" },
  315. /* 0x0f */    { "BkColor", 4, NULL, "background color (longword)" },
  316. /* 0x10 */    { "TxRatio", 8, NULL, "numerator (point), denominator (point)" },
  317. /* 0x11 */    { "Version", 1, NULL, "version (byte)" },
  318. /* 0x12 */    { "BkPixPat", NA, BkPixPat, "color background pattern" },
  319. /* 0x13 */    { "PnPixPat", NA, PnPixPat, "color pen pattern" },
  320. /* 0x14 */    { "FillPixPat", NA, FillPixPat, "color fill pattern" },
  321. /* 0x15 */    { "PnLocHFrac", 2, PnLocHFrac, "fractional pen position" },
  322. /* 0x16 */    { "ChExtra", 2, NULL, "extra for each character" },
  323. /* 0x17 */    res(0),
  324. /* 0x18 */    res(0),
  325. /* 0x19 */    res(0),
  326. /* 0x1a */    { "RGBFgCol", RGB_LEN, RGBFgCol, "RGB foreColor" },
  327. /* 0x1b */    { "RGBBkCol", RGB_LEN, RGBBkCol, "RGB backColor" },
  328. /* 0x1c */    { "HiliteMode", 0, NULL, "hilite mode flag" },
  329. /* 0x1d */    { "HiliteColor", RGB_LEN, NULL, "RGB hilite color" },
  330. /* 0x1e */    { "DefHilite", 0, NULL, "Use default hilite color" },
  331. /* 0x1f */    { "OpColor", NA, OpColor, "RGB OpColor for arithmetic modes" },
  332. /* 0x20 */    { "Line", 8, Line, "pnLoc (point), newPt (point)" },
  333. /* 0x21 */    { "LineFrom", 4, LineFrom, "newPt (point)" },
  334. /* 0x22 */    { "ShortLine", 6, ShortLine, "pnLoc (point, dh, dv (-128 .. 127))" },
  335. /* 0x23 */    { "ShortLineFrom", 2, ShortLineFrom, "dh, dv (-128 .. 127)" },
  336. /* 0x24 */    res(WORD_LEN),
  337. /* 0x25 */    res(WORD_LEN),
  338. /* 0x26 */    res(WORD_LEN),
  339. /* 0x27 */    res(WORD_LEN),
  340. /* 0x28 */    { "LongText", NA, LongText, "txLoc (point), count (0..255), text" },
  341. /* 0x29 */    { "DHText", NA, DHText, "dh (0..255), count (0..255), text" },
  342. /* 0x2a */    { "DVText", NA, DVText, "dv (0..255), count (0..255), text" },
  343. /* 0x2b */    { "DHDVText", NA, DHDVText, "dh, dv (0..255), count (0..255), text" },
  344. /* 0x2c */    res(WORD_LEN),
  345. /* 0x2d */    res(WORD_LEN),
  346. /* 0x2e */    res(WORD_LEN),
  347. /* 0x2f */    res(WORD_LEN),
  348. /* 0x30 */    { "frameRect", 8, frameRect, "rect" },
  349. /* 0x31 */    { "paintRect", 8, paintRect, "rect" },
  350. /* 0x32 */    { "eraseRect", 8, NULL, "rect" },
  351. /* 0x33 */    { "invertRect", 8, NULL, "rect" },
  352. /* 0x34 */    { "fillRect", 8, NULL, "rect" },
  353. /* 0x35 */    res(8),
  354. /* 0x36 */    res(8),
  355. /* 0x37 */    res(8),
  356. /* 0x38 */    { "frameSameRect", 0, frameSameRect, "rect" },
  357. /* 0x39 */    { "paintSameRect", 0, paintSameRect, "rect" },
  358. /* 0x3a */    { "eraseSameRect", 0, NULL, "rect" },
  359. /* 0x3b */    { "invertSameRect", 0, NULL, "rect" },
  360. /* 0x3c */    { "fillSameRect", 0, NULL, "rect" },
  361. /* 0x3d */    res(0),
  362. /* 0x3e */    res(0),
  363. /* 0x3f */    res(0),
  364. /* 0x40 */    { "frameRRect", 8, NULL, "rect" },
  365. /* 0x41 */    { "paintRRect", 8, NULL, "rect" },
  366. /* 0x42 */    { "eraseRRect", 8, NULL, "rect" },
  367. /* 0x43 */    { "invertRRect", 8, NULL, "rect" },
  368. /* 0x44 */    { "fillRRrect", 8, NULL, "rect" },
  369. /* 0x45 */    res(8),
  370. /* 0x46 */    res(8),
  371. /* 0x47 */    res(8),
  372. /* 0x48 */    { "frameSameRRect", 0, NULL, "rect" },
  373. /* 0x49 */    { "paintSameRRect", 0, NULL, "rect" },
  374. /* 0x4a */    { "eraseSameRRect", 0, NULL, "rect" },
  375. /* 0x4b */    { "invertSameRRect", 0, NULL, "rect" },
  376. /* 0x4c */    { "fillSameRRect", 0, NULL, "rect" },
  377. /* 0x4d */    res(0),
  378. /* 0x4e */    res(0),
  379. /* 0x4f */    res(0),
  380. /* 0x50 */    { "frameOval", 8, NULL, "rect" },
  381. /* 0x51 */    { "paintOval", 8, NULL, "rect" },
  382. /* 0x52 */    { "eraseOval", 8, NULL, "rect" },
  383. /* 0x53 */    { "invertOval", 8, NULL, "rect" },
  384. /* 0x54 */    { "fillOval", 8, NULL, "rect" },
  385. /* 0x55 */    res(8),
  386. /* 0x56 */    res(8),
  387. /* 0x57 */    res(8),
  388. /* 0x58 */    { "frameSameOval", 0, NULL, "rect" },
  389. /* 0x59 */    { "paintSameOval", 0, NULL, "rect" },
  390. /* 0x5a */    { "eraseSameOval", 0, NULL, "rect" },
  391. /* 0x5b */    { "invertSameOval", 0, NULL, "rect" },
  392. /* 0x5c */    { "fillSameOval", 0, NULL, "rect" },
  393. /* 0x5d */    res(0),
  394. /* 0x5e */    res(0),
  395. /* 0x5f */    res(0),
  396. /* 0x60 */    { "frameArc", 12, NULL, "rect, startAngle, arcAngle" },
  397. /* 0x61 */    { "paintArc", 12, NULL, "rect, startAngle, arcAngle" },
  398. /* 0x62 */    { "eraseArc", 12, NULL, "rect, startAngle, arcAngle" },
  399. /* 0x63 */    { "invertArc", 12, NULL, "rect, startAngle, arcAngle" },
  400. /* 0x64 */    { "fillArc", 12, NULL, "rect, startAngle, arcAngle" },
  401. /* 0x65 */    res(12),
  402. /* 0x66 */    res(12),
  403. /* 0x67 */    res(12),
  404. /* 0x68 */    { "frameSameArc", 4, NULL, "rect, startAngle, arcAngle" },
  405. /* 0x69 */    { "paintSameArc", 4, NULL, "rect, startAngle, arcAngle" },
  406. /* 0x6a */    { "eraseSameArc", 4, NULL, "rect, startAngle, arcAngle" },
  407. /* 0x6b */    { "invertSameArc", 4, NULL, "rect, startAngle, arcAngle" },
  408. /* 0x6c */    { "fillSameArc", 4, NULL, "rect, startAngle, arcAngle" },
  409. /* 0x6d */    res(4),
  410. /* 0x6e */    res(4),
  411. /* 0x6f */    res(4),
  412. /* 0x70 */    { "framePoly", NA, skip_poly_or_region, "poly" },
  413. /* 0x71 */    { "paintPoly", NA, paintPoly, "poly" },
  414. /* 0x72 */    { "erasePoly", NA, skip_poly_or_region, "poly" },
  415. /* 0x73 */    { "invertPoly", NA, skip_poly_or_region, "poly" },
  416. /* 0x74 */    { "fillPoly", NA, skip_poly_or_region, "poly" },
  417. /* 0x75 */    resf(skip_poly_or_region),
  418. /* 0x76 */    resf(skip_poly_or_region),
  419. /* 0x77 */    resf(skip_poly_or_region),
  420. /* 0x78 */    { "frameSamePoly", 0, NULL, "poly (NYI)" },
  421. /* 0x79 */    { "paintSamePoly", 0, NULL, "poly (NYI)" },
  422. /* 0x7a */    { "eraseSamePoly", 0, NULL, "poly (NYI)" },
  423. /* 0x7b */    { "invertSamePoly", 0, NULL, "poly (NYI)" },
  424. /* 0x7c */    { "fillSamePoly", 0, NULL, "poly (NYI)" },
  425. /* 0x7d */    res(0),
  426. /* 0x7e */    res(0),
  427. /* 0x7f */    res(0),
  428. /* 0x80 */    { "frameRgn", NA, skip_poly_or_region, "region" },
  429. /* 0x81 */    { "paintRgn", NA, skip_poly_or_region, "region" },
  430. /* 0x82 */    { "eraseRgn", NA, skip_poly_or_region, "region" },
  431. /* 0x83 */    { "invertRgn", NA, skip_poly_or_region, "region" },
  432. /* 0x84 */    { "fillRgn", NA, skip_poly_or_region, "region" },
  433. /* 0x85 */    resf(skip_poly_or_region),
  434. /* 0x86 */    resf(skip_poly_or_region),
  435. /* 0x87 */    resf(skip_poly_or_region),
  436. /* 0x88 */    { "frameSameRgn", 0, NULL, "region (NYI)" },
  437. /* 0x89 */    { "paintSameRgn", 0, NULL, "region (NYI)" },
  438. /* 0x8a */    { "eraseSameRgn", 0, NULL, "region (NYI)" },
  439. /* 0x8b */    { "invertSameRgn", 0, NULL, "region (NYI)" },
  440. /* 0x8c */    { "fillSameRgn", 0, NULL, "region (NYI)" },
  441. /* 0x8d */    res(0),
  442. /* 0x8e */    res(0),
  443. /* 0x8f */    res(0),
  444. /* 0x90 */    { "BitsRect", NA, BitsRect, "copybits, rect clipped" },
  445. /* 0x91 */    { "BitsRgn", NA, BitsRegion, "copybits, rgn clipped" },
  446. /* 0x92 */    res(WORD_LEN),
  447. /* 0x93 */    res(WORD_LEN),
  448. /* 0x94 */    res(WORD_LEN),
  449. /* 0x95 */    res(WORD_LEN),
  450. /* 0x96 */    res(WORD_LEN),
  451. /* 0x97 */    res(WORD_LEN),
  452. /* 0x98 */    { "PackBitsRect", NA, BitsRect, "packed copybits, rect clipped" },
  453. /* 0x99 */    { "PackBitsRgn", NA, BitsRegion, "packed copybits, rgn clipped" },
  454. /* 0x9a */    { "Opcode_9A", NA, Opcode_9A, "the mysterious opcode 9A" },
  455. /* 0x9b */    res(WORD_LEN),
  456. /* 0x9c */    res(WORD_LEN),
  457. /* 0x9d */    res(WORD_LEN),
  458. /* 0x9e */    res(WORD_LEN),
  459. /* 0x9f */    res(WORD_LEN),
  460. /* 0xa0 */    { "ShortComment", 2, ShortComment, "kind (word)" },
  461. /* 0xa1 */    { "LongComment", NA, LongComment, "kind (word), size (word), data" }
  462. };
  463.  
  464. struct const_name {
  465.     int    value;
  466.     char* name;
  467. };
  468.  
  469. static char* const_name ARGS(( struct const_name* table, int ct));
  470.  
  471. struct const_name transfer_name[] = {
  472.     { 0,    "srcCopy" },
  473.     { 1,    "srcOr" },
  474.     { 2,    "srcXor" },
  475.     { 3,    "srcBic" },
  476.     { 4,    "notSrcCopy" },
  477.     { 5,    "notSrcOr" },
  478.     { 6,    "notSrcXor" },
  479.     { 7,    "notSrcBic" },
  480.     { 32,    "blend" },
  481.     { 33,    "addPin" },
  482.     { 34,    "addOver" },
  483.     { 35,    "subPin" },
  484.     { 36,    "transparent" },
  485.     { 37,    "adMax" },
  486.     { 38,    "subOver" },
  487.     { 39,    "adMin" },
  488.     { -1,    0 }
  489. };
  490.  
  491. struct const_name font_name[] = {
  492.     { 0,    "systemFont" },
  493.     { 1,    "applFont" },
  494.     { 2,    "newYork" },
  495.     { 3,    "geneva" },
  496.     { 4,    "monaco" },
  497.     { 5,    "venice" },
  498.     { 6,    "london" },
  499.     { 7,    "athens" },
  500.     { 8,    "sanFran" },
  501.     { 9,    "toronto" },
  502.     { 11,    "cairo" },
  503.     { 12,    "losAngeles" },
  504.     { 20,    "times" },
  505.     { 21,    "helvetica" },
  506.     { 22,    "courier" },
  507.     { 23,    "symbol" },
  508.     { 24,    "taliesin" },
  509.     { -1,    0 }
  510. };
  511.  
  512. struct const_name ps_just_name[] = {
  513.     { 0,    "no" },
  514.     { 1,    "left" },
  515.     { 2,    "center" },
  516.     { 3,    "right" },
  517.     { 4,    "full" },
  518.     { -1,    0 }
  519. };
  520.  
  521. struct const_name ps_flip_name[] = {
  522.     { 0,    "no" },
  523.     { 1,    "horizontal" },
  524.     { 2,    "vertical" },
  525.     { -1,    0 }
  526. };
  527.  
  528. #define FNT_BOLD    (1)
  529. #define FNT_ITALIC    (2)
  530. #define FNT_ULINE    (4)
  531. #define FNT_OUTLINE    (8)
  532. #define FNT_SHADOW    (16)
  533. #define FNT_CONDENSE    (32)
  534. #define FNT_EXTEND    (64)
  535.  
  536. static int align = 0;
  537. static FILE* ifp;
  538.  
  539. int
  540. main(argc, argv)
  541. int argc;
  542. char* argv[];
  543. {
  544.     int argn;
  545.     int header;
  546.     char* usage =
  547. "[-verbose] [-fullres] [-noheader] [-quickdraw] [-fontdir file] [pictfile]";
  548.  
  549.     ppm_init( &argc, argv );
  550.  
  551.     argn = 1;
  552.     verbose = 0;
  553.     fullres = 0;
  554.     header = 1;
  555.     recognize_comment = 1;
  556.  
  557.     while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
  558.         if (pm_keymatch(argv[argn], "-verbose", 2))
  559.             verbose++;
  560.         else if (pm_keymatch(argv[argn], "-fullres", 3))
  561.             fullres = 1;
  562.         else if (pm_keymatch(argv[argn], "-noheader", 2))
  563.             header = 0;
  564.         else if (pm_keymatch(argv[argn], "-quickdraw", 2))
  565.             recognize_comment = 0;
  566.         else if (pm_keymatch(argv[argn], "-fontdir", 3)) {
  567.             argn++;
  568.             if (!argv[argn])
  569.                 pm_usage(usage);
  570.             else
  571.                 load_fontdir(argv[argn]);
  572.         }
  573.         else
  574.             pm_usage(usage);
  575.         ++argn;
  576.     }
  577.  
  578.     if (load_fontdir("fontdir") < 0)
  579.         pm_message("warning: can't load font directory 'fontdir'\n", 0,0,0,0);
  580.  
  581.     if (argn < argc) {
  582.         ifp = pm_openr(argv[argn]);
  583.         ++argn;
  584.     } else
  585.         ifp = stdin;
  586.  
  587.     if (argn != argc)
  588.         pm_usage(usage);
  589.  
  590.     if (header) {
  591.         stage = "Reading 512 byte header";
  592.         skip(512);
  593.     }
  594.  
  595.     interpret_pict();
  596.     exit(0);
  597. }
  598.  
  599. static void
  600. interpret_pict()
  601. {
  602.     byte ch;
  603.     word picSize;
  604.     word opcode;
  605.     word len;
  606.     int version;
  607.     int i;
  608.  
  609.     for (i = 0; i < 64; i++)
  610.         pen_pat.pix[i] = bkpat.pix[i] = fillpat.pix[i] = 1;
  611.     pen_width = pen_height = 1;
  612.     pen_mode = 0; /* srcCopy */
  613.     pen_trf = transfer(pen_mode);
  614.     text_mode = 0; /* srcCopy */
  615.     text_trf = transfer(text_mode);
  616.  
  617.     stage = "Reading picture size";
  618.     picSize = read_word();
  619.  
  620.     if (verbose)
  621.         pm_message("picture size = %d (0x%x)", picSize, picSize, 0, 0, 0);
  622.  
  623.     stage = "reading picture frame";
  624.     read_rect(&picFrame);
  625.  
  626.     if (verbose) {
  627.         dump_rect("Picture frame:", &picFrame);
  628.         pm_message("Picture size is %d x %d",
  629.             picFrame.right - picFrame.left,
  630.             picFrame.bottom - picFrame.top, 0, 0, 0);
  631.     }
  632.  
  633.     if (!fullres)
  634.         alloc_planes();
  635.  
  636.     while ((ch = read_byte()) == 0)
  637.         ;
  638.     if (ch != 0x11)
  639.         pm_error("No version number");
  640.  
  641.     switch (read_byte()) {
  642.     case 1:
  643.         version = 1;
  644.         break;
  645.     case 2:
  646.         if (read_byte() != 0xff)
  647.             pm_error("can only do version 2, subcode 0xff");
  648.         version = 2;
  649.         break;
  650.     default:
  651.         pm_error("Unknown version");
  652.     }
  653.  
  654.     if (verbose)
  655.         pm_message("PICT version %d", version, 0, 0, 0, 0);
  656.  
  657.     while((opcode = get_op(version)) != 0xff) {
  658.         if (opcode < 0xa2) {
  659.             if (verbose) {
  660.                 stage = optable[opcode].name;
  661.                 if (!strcmp(stage, "reserved"))
  662.                     pm_message("reserved opcode=0x%x", opcode, 0, 0, 0, 0);
  663.                 else
  664.                     pm_message("%s", stage = optable[opcode].name, 0, 0, 0, 0);
  665.             }
  666.  
  667.             if (optable[opcode].impl != NULL)
  668.                 (*optable[opcode].impl)(version);
  669.             else if (optable[opcode].len >= 0)
  670.                 skip(optable[opcode].len);
  671.             else switch (optable[opcode].len) {
  672.             case WORD_LEN:
  673.                 len = read_word();
  674.                 skip(len);
  675.                 break;
  676.             default:
  677.                 pm_error("can't do length of %d",
  678.                     optable[opcode].len);
  679.             }
  680.         }
  681.         else if (opcode == 0xc00) {
  682.             if (verbose)
  683.                 pm_message("HeaderOp", 0, 0, 0, 0, 0);
  684.             stage = "HeaderOp";
  685.             skip(24);
  686.         }
  687.         else if (opcode >= 0xa2 && opcode <= 0xaf) {
  688.             stage = "skipping reserved";
  689.             if (verbose)
  690.                 pm_message("%s 0x%x", stage, opcode, 0, 0, 0);
  691.             skip(read_word());
  692.         }
  693.         else if (opcode >= 0xb0 && opcode <= 0xcf) {
  694.             /* just a reserved opcode, no data */
  695.             if (verbose)
  696.                 pm_message("reserved 0x%x", opcode, 0, 0, 0);
  697.         }
  698.         else if (opcode >= 0xd0 && opcode <= 0xfe) {
  699.             stage = "skipping reserved";
  700.             if (verbose)
  701.                 pm_message("%s 0x%x", stage, opcode, 0, 0, 0);
  702.             skip(read_long());
  703.         }
  704.         else if (opcode >= 0x100 && opcode <= 0x7fff) {
  705.             stage = "skipping reserved";
  706.             if (verbose)
  707.                 pm_message("%s 0x%x", stage, opcode, 0, 0, 0);
  708.             skip((opcode >> 7) & 255);
  709.         }
  710.         else if (opcode >= 0x8000 && opcode <= 0x80ff) {
  711.             /* just a reserved opcode */
  712.             if (verbose)
  713.                 pm_message("reserved 0x%x", opcode, 0, 0, 0, 0);
  714.         }
  715.         else if (opcode >= 8100 && opcode <= 0xffff) {
  716.             stage = "skipping reserved";
  717.             if (verbose)
  718.                 pm_message("%s 0x%x", stage, opcode, 0, 0, 0);
  719.             skip(read_long());
  720.         }
  721.         else
  722.             pm_error("can't handle opcode of %x", opcode);
  723.     }
  724.     output_ppm(version);
  725. }
  726.  
  727. /* allocation is same for version 1 or version 2.  We are super-duper
  728.  * wasteful of memory for version 1 picts.  Someday, we'll separate
  729.  * things and only allocate a byte per pixel for version 1 (or heck,
  730.  * even only a bit, but that would require even more extra work).
  731.  */
  732.  
  733. static void alloc_planes()
  734. {
  735.     rowlen = picFrame.right - picFrame.left;
  736.     collen = picFrame.bottom - picFrame.top;
  737.  
  738.     clip_rect.top = picFrame.top;
  739.     clip_rect.left = picFrame.left;
  740.     clip_rect.bottom = picFrame.bottom;
  741.     clip_rect.top = picFrame.top;
  742.  
  743.     planelen = rowlen * collen;
  744.     if ((red = (word*)malloc(planelen * sizeof(word))) == NULL ||
  745.         (green = (word*)malloc(planelen * sizeof(word))) == NULL ||
  746.         (blue = (word*)malloc(planelen * sizeof(word))) == NULL)
  747.     {
  748.  
  749.         pm_error("not enough memory to hold picture");
  750.     }
  751.     /* initialize background to white */
  752.     memset(red, 255, planelen * sizeof(word));
  753.     memset(green, 255, planelen * sizeof(word));
  754.     memset(blue, 255, planelen * sizeof(word));
  755. }
  756.  
  757. static void
  758. compact_plane(plane, planelen)
  759. register word* plane;
  760. register int planelen;
  761. {
  762.     register byte* p;
  763.  
  764.     for (p = (byte*)plane; planelen-- > 0; )
  765.         *p++ = (*plane++ >> 8) & 255;
  766. }
  767.  
  768. static void
  769. output_ppm(version)
  770. int version;
  771. {
  772.     int width;
  773.     int height;
  774.     register char* r;
  775.     register char* g;
  776.     register char* b;
  777.     pixel* pixelrow;
  778.     register pixel* pP;
  779.     int row;
  780.     register int col;
  781.  
  782.     if (fullres)
  783.         do_blits();
  784.  
  785.     stage = "writing PPM";
  786.  
  787.     width = picFrame.right - picFrame.left;
  788.     height = picFrame.bottom - picFrame.top;
  789.     r = (char*) red;
  790.     compact_plane((word*) r, width * height);
  791.     g = (char*) green;
  792.     compact_plane((word*) g, width * height);
  793.     b = (char*) blue;
  794.     compact_plane((word*) b, width * height);
  795.  
  796.     ppm_writeppminit(stdout, width, height, (pixval) 255, 0 );
  797.     pixelrow = ppm_allocrow(width);
  798.     for (row = 0; row < height; ++row) {
  799.         for (col = 0, pP = pixelrow; col < width;
  800.              ++col, ++pP, ++r, ++g, ++b) {
  801.             PPM_ASSIGN(*pP, *r, *g, *b);
  802.         }
  803.  
  804.         ppm_writeppmrow(stdout, pixelrow, width, (pixval) 255, 0 );
  805.     }
  806.     pm_close(stdout);
  807. }
  808.  
  809. static void
  810. do_blits()
  811. {
  812.     struct blit_info* bi;
  813.     int    srcwidth, dstwidth, srcheight, dstheight;
  814.     double    scale, scalelow, scalehigh;
  815.     double    xscale = 1.0;
  816.     double    yscale = 1.0;
  817.     double    lowxscale, highxscale, lowyscale, highyscale;
  818.     int        xscalecalc = 0, yscalecalc = 0;
  819.  
  820.     if (!blit_list) return;
  821.  
  822.     fullres = 0;
  823.  
  824.     for (bi = blit_list; bi; bi = bi->next) {
  825.         srcwidth = rectwidth(&bi->srcRect);
  826.         dstwidth = rectwidth(&bi->dstRect);
  827.         srcheight = rectheight(&bi->srcRect);
  828.         dstheight = rectheight(&bi->dstRect);
  829.         if (srcwidth > dstwidth) {
  830.             scalelow  = (double)(srcwidth      ) / (double)dstwidth;
  831.             scalehigh = (double)(srcwidth + 1.0) / (double)dstwidth;
  832.             switch (xscalecalc) {
  833.             case 0:
  834.                 lowxscale = scalelow;
  835.                 highxscale = scalehigh;
  836.                 xscalecalc = 1;
  837.                 break;
  838.             case 1:
  839.                 if (scalelow < highxscale && scalehigh > lowxscale) {
  840.                     if (scalelow > lowxscale) lowxscale = scalelow;
  841.                     if (scalehigh < highxscale) highxscale = scalehigh;
  842.                 }
  843.                 else {
  844.                     scale = (lowxscale + highxscale) / 2.0;
  845.                     xscale = (double)srcwidth / (double)dstwidth;
  846.                     if (scale > xscale) xscale = scale;
  847.                     xscalecalc = 2;
  848.                 }
  849.                 break;
  850.             case 2:
  851.                 scale = (double)srcwidth / (double)dstwidth;
  852.                 if (scale > xscale) xscale = scale;
  853.                 break;
  854.             }
  855.         }
  856.  
  857.         if (srcheight > dstheight) {
  858.             scalelow =  (double)(srcheight      ) / (double)dstheight;
  859.             scalehigh = (double)(srcheight + 1.0) / (double)dstheight;
  860.             switch (yscalecalc) {
  861.             case 0:
  862.                 lowyscale = scalelow;
  863.                 highyscale = scalehigh;
  864.                 yscalecalc = 1;
  865.                 break;
  866.             case 1:
  867.                 if (scalelow < highyscale && scalehigh > lowyscale) {
  868.                     if (scalelow > lowyscale) lowyscale = scalelow;
  869.                     if (scalehigh < highyscale) highyscale = scalehigh;
  870.                 }
  871.                 else {
  872.                     scale = (lowyscale + highyscale) / 2.0;
  873.                     yscale = (double)srcheight / (double)dstheight;
  874.                     if (scale > yscale) yscale = scale;
  875.                     yscalecalc = 2;
  876.                 }
  877.                 break;
  878.             case 2:
  879.                 scale = (double)srcheight / (double)dstheight;
  880.                 if (scale > yscale) yscale = scale;
  881.                 break;
  882.             }
  883.         }
  884.     }
  885.  
  886.     if (xscalecalc == 1) {
  887.         if (1.0 >= lowxscale && 1.0 <= highxscale)
  888.             xscale = 1.0;
  889.         else
  890.             xscale = lowxscale;
  891.     }
  892.     if (yscalecalc == 1) {
  893.         if (1.0 >= lowyscale && 1.0 <= lowyscale)
  894.             yscale = 1.0;
  895.         else
  896.             yscale = lowyscale;
  897.     }
  898.  
  899.     if (xscale != 1.0 || yscale != 1.0) {
  900.         for (bi = blit_list; bi; bi = bi->next)
  901.             rectscale(&bi->dstRect, xscale, yscale);
  902.  
  903.         pm_message("Scaling output by %f in X and %f in Y",
  904.             xscale, yscale, 0, 0, 0);
  905.         rectscale(&picFrame, xscale, yscale);
  906.     }
  907.  
  908.     alloc_planes();
  909.  
  910.     for (bi = blit_list; bi; bi = bi->next) {
  911.         blit(&bi->srcRect, &bi->srcBounds, bi->srcwid, bi->srcplane,
  912.              bi->pixSize,
  913.              &bi->dstRect, &picFrame, rowlen,
  914.              bi->colour_map,
  915.              bi->mode);
  916.     }
  917. }
  918.  
  919. /*
  920.  * This could use read_pixmap, but I'm too lazy to hack read_pixmap.
  921.  */
  922.  
  923. static void
  924. Opcode_9A(version)
  925. int version;
  926. {
  927. #ifdef DUMP
  928.     FILE *fp = fopen("data", "w");
  929.     int ch;
  930.     if (fp == NULL) exit(1);
  931.     while ((ch = fgetc(ifp)) != EOF) fputc(ch, fp);
  932.     exit(0);
  933. #else
  934.     struct pixMap    p;
  935.     struct Rect        srcRect;
  936.     struct Rect        dstRect;
  937.     byte*            pm;
  938.     int                pixwidth;
  939.     word            mode;
  940.  
  941.     /* skip fake len, and fake EOF */
  942.     skip(4);
  943.     read_word();    /* version */
  944.     read_rect(&p.Bounds);
  945.     pixwidth = p.Bounds.right - p.Bounds.left;
  946.     p.packType = read_word();
  947.     p.packSize = read_long();
  948.     p.hRes = read_long();
  949.     p.vRes = read_long();
  950.     p.pixelType = read_word();
  951.     p.pixelSize = read_word();
  952.     p.pixelSize = read_word();
  953.     p.cmpCount = read_word();
  954.     p.cmpSize = read_word();
  955.     p.planeBytes = read_long();
  956.     p.pmTable = read_long();
  957.     p.pmReserved = read_long();
  958.  
  959.     if (p.pixelSize == 16)
  960.         pixwidth *= 2;
  961.     else if (p.pixelSize == 32)
  962.         pixwidth *= 3;
  963.  
  964.     read_rect(&srcRect);
  965.     if (verbose)
  966.         dump_rect("source rectangle:", &srcRect);
  967.  
  968.     read_rect(&dstRect);
  969.     if (verbose)
  970.         dump_rect("destination rectangle:", &dstRect);
  971.  
  972.     mode = read_word();
  973.     if (verbose)
  974.         pm_message("transfer mode = %s", const_name(transfer_name, mode),0,0,0,0);
  975.  
  976.     pm = unpackbits(&p.Bounds, 0, p.pixelSize);
  977.  
  978.     if (blit(&srcRect, &(p.Bounds), pixwidth, pm, p.pixelSize,
  979.          &dstRect, &picFrame, rowlen,
  980.          (struct RGBColour*)0,
  981.          mode))
  982.     {
  983.         free(pm);
  984.     }
  985. #endif
  986. }
  987.  
  988. static void
  989. BitsRect(version)
  990. int version;
  991. {
  992.     word rowBytes;
  993.  
  994.     stage = "Reading rowBytes for bitsrect";
  995.     rowBytes = read_word();
  996.  
  997.     if (verbose)
  998.         pm_message("rowbytes = 0x%x (%d)", rowBytes, rowBytes & 0x7fff, 0, 0, 0);
  999.  
  1000.     if (rowBytes & 0x8000)
  1001.         do_pixmap(version, rowBytes, 0);
  1002.     else
  1003.         do_bitmap(version, rowBytes, 0);
  1004. }
  1005.  
  1006. static void
  1007. BitsRegion(version)
  1008. int version;
  1009. {
  1010.     word rowBytes;
  1011.  
  1012.     stage = "Reading rowBytes for bitsregion";
  1013.     rowBytes = read_word();
  1014.  
  1015.     if (rowBytes & 0x8000)
  1016.         do_pixmap(version, rowBytes, 1);
  1017.     else
  1018.         do_bitmap(version, rowBytes, 1);
  1019. }
  1020.  
  1021. static void
  1022. do_bitmap(version, rowBytes, is_region)
  1023. int version;
  1024. int rowBytes;
  1025. int is_region;
  1026. {
  1027.     struct Rect Bounds;
  1028.     struct Rect srcRect;
  1029.     struct Rect dstRect;
  1030.     word mode;
  1031.     byte* pm;
  1032.     static struct RGBColour colour_table[] = { {65535L, 65535L, 65535L}, {0, 0, 0} };
  1033.  
  1034.     read_rect(&Bounds);
  1035.     read_rect(&srcRect);
  1036.     read_rect(&dstRect);
  1037.     mode = read_word();
  1038.     if (verbose)
  1039.         pm_message("transfer mode = %s", const_name(transfer_name, mode),0,0,0,0);
  1040.  
  1041.     if (is_region)
  1042.         skip_poly_or_region(version);
  1043.  
  1044.     stage = "unpacking rectangle";
  1045.  
  1046.     pm = unpackbits(&Bounds, rowBytes, 1);
  1047.  
  1048.     if (blit(&srcRect, &Bounds, Bounds.right - Bounds.left, pm, 8,
  1049.          &dstRect, &picFrame, rowlen,
  1050.          colour_table,
  1051.          mode))
  1052.     {
  1053.         free(pm);
  1054.     }
  1055. }
  1056.  
  1057. #if __STDC__
  1058. static void
  1059. do_pixmap( int version, word rowBytes, int is_region )
  1060. #else /*__STDC__*/
  1061. static void
  1062. do_pixmap(version, rowBytes, is_region)
  1063. int version;
  1064. word rowBytes;
  1065. int is_region;
  1066. #endif /*__STDC__*/
  1067. {
  1068.     word mode;
  1069.     struct pixMap p;
  1070.     word pixwidth;
  1071.     byte* pm;
  1072.     struct RGBColour* colour_table;
  1073.     struct Rect srcRect;
  1074.     struct Rect dstRect;
  1075.  
  1076.     read_pixmap(&p, NULL);
  1077.  
  1078.     pixwidth = p.Bounds.right - p.Bounds.left;
  1079.  
  1080.     if (verbose)
  1081.         pm_message("%d x %d rectangle", pixwidth,
  1082.             p.Bounds.bottom - p.Bounds.top, 0, 0, 0);
  1083.  
  1084.     colour_table = read_colour_table();
  1085.  
  1086.     read_rect(&srcRect);
  1087.  
  1088.     if (verbose)
  1089.         dump_rect("source rectangle:", &srcRect);
  1090.  
  1091.     read_rect(&dstRect);
  1092.  
  1093.     if (verbose)
  1094.         dump_rect("destination rectangle:", &dstRect);
  1095.  
  1096.     mode = read_word();
  1097.  
  1098.     if (verbose)
  1099.         pm_message("transfer mode = %s", const_name(transfer_name, mode),0,0,0,0);
  1100.  
  1101.     if (is_region)
  1102.         skip_poly_or_region(version);
  1103.  
  1104.     stage = "unpacking rectangle";
  1105.  
  1106.     pm = unpackbits(&p.Bounds, rowBytes, p.pixelSize);
  1107.  
  1108.     if (blit(&srcRect, &(p.Bounds), pixwidth, pm, 8,
  1109.          &dstRect, &picFrame, rowlen,
  1110.          colour_table,
  1111.          mode))
  1112.     {
  1113.         free(colour_table);
  1114.         free(pm);
  1115.     }
  1116. }
  1117.  
  1118. static struct blit_info* add_blit_list()
  1119. {
  1120.     struct blit_info* bi;
  1121.  
  1122.     if (!(bi = (struct blit_info*)malloc(sizeof(struct blit_info))))
  1123.         pm_error("out of memory for blit list");
  1124.     
  1125.     bi->next = 0;
  1126.     *last_bl = bi;
  1127.     last_bl = &(bi->next);
  1128.  
  1129.     return bi;
  1130. }
  1131.  
  1132. /* Various transfer functions for blits.
  1133.  *
  1134.  * Note src[Not]{Or,Xor,Copy} only work if the source pixmap was originally
  1135.  * a bitmap.
  1136.  * There's also a small bug that the foreground and background colours
  1137.  * are not used in a srcCopy; this wouldn't be hard to fix.
  1138.  * It IS a problem since the foreground and background colours CAN be changed.
  1139.  */
  1140.  
  1141. #define rgb_all_same(x, y) \
  1142.     ((x)->red == (y) && (x)->green == (y) && (x)->blue == (y))
  1143. #define rgb_is_white(x) rgb_all_same((x), 0xffff)
  1144. #define rgb_is_black(x) rgb_all_same((x), 0)
  1145.  
  1146. static void srcCopy(src, dst)
  1147. struct RGBColour*    src;
  1148. struct RGBColour*    dst;
  1149. {
  1150.     if (rgb_is_black(src))
  1151.         *dst = foreground;
  1152.     else
  1153.         *dst = background;
  1154. }
  1155.  
  1156. static void srcOr(src, dst)
  1157. struct RGBColour*    src;
  1158. struct RGBColour*    dst;
  1159. {
  1160.     if (rgb_is_black(src))
  1161.         *dst = foreground;
  1162. }
  1163.  
  1164. static void srcXor(src, dst)
  1165. struct RGBColour*    src;
  1166. struct RGBColour*    dst;
  1167. {
  1168.     dst->red ^= ~src->red;
  1169.     dst->green ^= ~src->green;
  1170.     dst->blue ^= ~src->blue;
  1171. }
  1172.  
  1173. static void srcBic(src, dst)
  1174. struct RGBColour*    src;
  1175. struct RGBColour*    dst;
  1176. {
  1177.     if (rgb_is_black(src))
  1178.         *dst = background;
  1179. }
  1180.  
  1181. static void notSrcCopy(src, dst)
  1182. struct RGBColour*    src;
  1183. struct RGBColour*    dst;
  1184. {
  1185.     if (rgb_is_white(src))
  1186.         *dst = foreground;
  1187.     else if (rgb_is_black(src))
  1188.         *dst = background;
  1189. }
  1190.  
  1191. static void notSrcOr(src, dst)
  1192. struct RGBColour*    src;
  1193. struct RGBColour*    dst;
  1194. {
  1195.     if (rgb_is_white(src))
  1196.         *dst = foreground;
  1197. }
  1198.  
  1199. static void notSrcBic(src, dst)
  1200. struct RGBColour*    src;
  1201. struct RGBColour*    dst;
  1202. {
  1203.     if (rgb_is_white(src))
  1204.         *dst = background;
  1205. }
  1206.  
  1207. static void notSrcXor(src, dst)
  1208. struct RGBColour*    src;
  1209. struct RGBColour*    dst;
  1210. {
  1211.     dst->red ^= src->red;
  1212.     dst->green ^= src->green;
  1213.     dst->blue ^= src->blue;
  1214. }
  1215.  
  1216. static void addOver(src, dst)
  1217. struct RGBColour*    src;
  1218. struct RGBColour*    dst;
  1219. {
  1220.     dst->red += src->red;
  1221.     dst->green += src->green;
  1222.     dst->blue += src->blue;
  1223. }
  1224.  
  1225. static void addPin(src, dst)
  1226. struct RGBColour*    src;
  1227. struct RGBColour*    dst;
  1228. {
  1229.     if ((long)dst->red + (long)src->red > (long)op_colour.red)
  1230.         dst->red = op_colour.red;
  1231.     else
  1232.         dst->red = dst->red + src->red;
  1233.  
  1234.     if ((long)dst->green + (long)src->green > (long)op_colour.green)
  1235.         dst->green = op_colour.green;
  1236.     else
  1237.         dst->green = dst->green + src->green;
  1238.  
  1239.     if ((long)dst->blue + (long)src->blue > (long)op_colour.blue)
  1240.         dst->blue = op_colour.blue;
  1241.     else
  1242.         dst->blue = dst->blue + src->blue;
  1243. }
  1244.  
  1245. static void subOver(src, dst)
  1246. struct RGBColour*    src;
  1247. struct RGBColour*    dst;
  1248. {
  1249.     dst->red -= src->red;
  1250.     dst->green -= src->green;
  1251.     dst->blue -= src->blue;
  1252. }
  1253.  
  1254. /* or maybe its src - dst; my copy of Inside Mac is unclear */
  1255. static void subPin(src, dst)
  1256. struct RGBColour*    src;
  1257. struct RGBColour*    dst;
  1258. {
  1259.     if ((long)dst->red - (long)src->red < (long)op_colour.red)
  1260.         dst->red = op_colour.red;
  1261.     else
  1262.         dst->red = dst->red - src->red;
  1263.  
  1264.     if ((long)dst->green - (long)src->green < (long)op_colour.green)
  1265.         dst->green = op_colour.green;
  1266.     else
  1267.         dst->green = dst->green - src->green;
  1268.  
  1269.     if ((long)dst->blue - (long)src->blue < (long)op_colour.blue)
  1270.         dst->blue = op_colour.blue;
  1271.     else
  1272.         dst->blue = dst->blue - src->blue;
  1273. }
  1274.  
  1275. static void adMax(src, dst)
  1276. struct RGBColour*    src;
  1277. struct RGBColour*    dst;
  1278. {
  1279.     if (src->red > dst->red) dst->red = src->red;
  1280.     if (src->green > dst->green) dst->green = src->green;
  1281.     if (src->blue > dst->blue) dst->blue = src->blue;
  1282. }
  1283.  
  1284. static void adMin(src, dst)
  1285. struct RGBColour*    src;
  1286. struct RGBColour*    dst;
  1287. {
  1288.     if (src->red < dst->red) dst->red = src->red;
  1289.     if (src->green < dst->green) dst->green = src->green;
  1290.     if (src->blue < dst->blue) dst->blue = src->blue;
  1291. }
  1292.  
  1293. static void blend(src, dst)
  1294. struct RGBColour*    src;
  1295. struct RGBColour*    dst;
  1296. {
  1297. #define blend_component(cmp)    \
  1298.     ((long)src->cmp * (long)op_colour.cmp) / 65536 +    \
  1299.     ((long)dst->cmp * (long)(65536 - op_colour.cmp) / 65536)
  1300.  
  1301.     dst->red = blend_component(red);
  1302.     dst->green = blend_component(green);
  1303.     dst->blue = blend_component(blue);
  1304. }
  1305.  
  1306. static void transparent(src, dst)
  1307. struct RGBColour*    src;
  1308. struct RGBColour*    dst;
  1309. {
  1310.     if (src->red != background.red || src->green != background.green ||
  1311.         src->blue != background.blue)
  1312.     {
  1313.         *dst = *src;
  1314.     }
  1315. }
  1316.  
  1317. static transfer_func transfer(mode)
  1318. int mode;
  1319. {
  1320.     switch (mode) {
  1321.     case  0: return srcCopy;
  1322.     case  1: return srcOr;
  1323.     case  2: return srcXor;
  1324.     case  3: return srcBic;
  1325.     case  4: return notSrcCopy;
  1326.     case  5: return notSrcOr;
  1327.     case  6: return notSrcXor;
  1328.     case  7: return notSrcBic;
  1329.     case 32: return blend;
  1330.     case 33: return addPin;
  1331.     case 34: return addOver;
  1332.     case 35: return subPin;
  1333.     case 36: return transparent;
  1334.     case 37: return adMax;
  1335.     case 38: return subOver;
  1336.     case 39: return adMin;
  1337.     default:
  1338.         if (mode != 0)
  1339.             pm_message("no transfer function for code %s, using srcCopy",
  1340.                 const_name(transfer_name, mode), 0, 0, 0, 0);
  1341.         return srcCopy;
  1342.     }
  1343. }
  1344.  
  1345. static int
  1346. blit(srcRect, srcBounds, srcwid, srcplane, pixSize, dstRect, dstBounds, dstwid, colour_map, mode)
  1347. struct Rect* srcRect;
  1348. struct Rect* srcBounds;
  1349. int srcwid;
  1350. byte* srcplane;
  1351. int pixSize;
  1352. struct Rect* dstRect;
  1353. struct Rect* dstBounds;
  1354. int dstwid;
  1355. struct RGBColour* colour_map;
  1356. int mode;
  1357. {
  1358.     struct Rect clipsrc;
  1359.     struct Rect clipdst;
  1360.     register byte* src;
  1361.     register word* reddst;
  1362.     register word* greendst;
  1363.     register word* bluedst;
  1364.     register int i;
  1365.     register int j;
  1366.     int dstoff;
  1367.     int xsize;
  1368.     int ysize;
  1369.     int srcadd;
  1370.     int dstadd;
  1371.     struct RGBColour* ct;
  1372.     int pkpixsize;
  1373.     struct blit_info* bi;
  1374.     struct RGBColour src_c, dst_c;
  1375.     transfer_func trf;
  1376.  
  1377.     if (ps_text)
  1378.         return;
  1379.  
  1380.     /* almost got it.  clip source rect with source bounds.
  1381.      * clip dest rect with dest bounds.  if source and
  1382.      * destination are not the same size, use pnmscale
  1383.      * to get a nicely sized rectangle.
  1384.      */
  1385.     rectinter(srcBounds, srcRect, &clipsrc);
  1386.     rectinter(dstBounds, dstRect, &clipdst);
  1387.  
  1388.     if (fullres) {
  1389.         bi = add_blit_list();
  1390.         bi->srcRect = clipsrc;
  1391.         bi->srcBounds = *srcBounds;
  1392.         bi->srcwid = srcwid;
  1393.         bi->srcplane = srcplane;
  1394.         bi->pixSize = pixSize;
  1395.         bi->dstRect = clipdst;
  1396.         bi->colour_map = colour_map;
  1397.         bi->mode = mode;
  1398.         return 0;
  1399.     }
  1400.  
  1401.     if (verbose) {
  1402.         dump_rect("copying from:", &clipsrc);
  1403.         dump_rect("to:          ", &clipdst);
  1404.         pm_message("a %d x %d area to a %d x %d area",
  1405.             rectwidth(&clipsrc), rectheight(&clipsrc),
  1406.             rectwidth(&clipdst), rectheight(&clipdst), 0);
  1407.     }
  1408.  
  1409.     pkpixsize = 1;
  1410.     if (pixSize == 16)
  1411.         pkpixsize = 2;
  1412.  
  1413.     src = srcplane + (clipsrc.top - srcBounds->top) * srcwid +
  1414.         (clipsrc.left - srcBounds->left) * pkpixsize;
  1415.     xsize = clipsrc.right - clipsrc.left;
  1416.     ysize = clipsrc.bottom - clipsrc.top;
  1417.     srcadd = srcwid - xsize * pkpixsize;
  1418.  
  1419.     dstoff = (clipdst.top - dstBounds->top) * dstwid +
  1420.         (clipdst.left - dstBounds->left);
  1421.     reddst = red + dstoff;
  1422.     greendst = green + dstoff;
  1423.     bluedst = blue + dstoff;
  1424.     dstadd = dstwid - (clipdst.right - clipdst.left);
  1425.  
  1426.     /* get rid of Text mask mode bit, if (erroneously) set */
  1427.     if ((mode & ~64) == 0)
  1428.         trf = 0;    /* optimized srcCopy */
  1429.     else
  1430.         trf = transfer(mode & ~64);
  1431.  
  1432.     if (!rectsamesize(&clipsrc, &clipdst)) {
  1433. #ifdef STANDALONE
  1434.         fprintf(stderr,
  1435.           "picttoppm: standalone version can't scale rectangles yet, sorry.\n");
  1436.         fprintf(stderr, "picttoppm: skipping this rectangle.\n");
  1437.         return;
  1438. #else
  1439.         FILE*    pnmscale;
  1440. #ifndef _OSK
  1441.         char*    tmpfile = tmpnam((char*)0);
  1442. #else
  1443.         char myname[20] = "/r0/picttopbmXXXXXX";
  1444.         char*    tmpfile = mktemp(myname);
  1445. #endif
  1446.         char    command[1024];
  1447.         register byte* redsrc;
  1448.         register byte* greensrc;
  1449.         register byte* bluesrc;
  1450.         int    greenpix;
  1451.         FILE*    scaled;
  1452.         int    cols, rows, format;
  1453.         pixval maxval;
  1454.         pixel* row;
  1455.         pixel* rowp;
  1456.  
  1457. #if (defined(AMIGA) || defined(VMS))
  1458.                 char ami_tmpfile[L_tmpnam];
  1459.                 int ami_result;
  1460.                 tmpnam(ami_tmpfile);
  1461.                 if (!(pnmscale = fopen(ami_tmpfile, "w")))
  1462.                         pm_error("cannot create temporary file '%s'", ami_tmpfile);
  1463. #else /* AMIGA or VMS */
  1464.         sprintf(command, "pnmscale -xsize %d -ysize %d > %s",
  1465.             rectwidth(&clipdst), rectheight(&clipdst), tmpfile);
  1466.         
  1467.         pm_message("running 'pnmscale -xsize %d -ysize %d' on a %d x %d image",
  1468.             rectwidth(&clipdst), rectheight(&clipdst),
  1469.             rectwidth(&clipsrc), rectheight(&clipsrc), 0);
  1470.  
  1471.         if (!(pnmscale = popen(command, "w"))) {
  1472.             pm_message("cannot execute command '%s'", command, 0, 0, 0, 0);
  1473.             pm_perror("popen");
  1474.         }
  1475. #endif /* AMIGA or VMS */
  1476.  
  1477. /* This should really be PPM_MAXMAXVAL, but that can be big, and then
  1478.  * I'd have to conditionally output raw/not-raw PPM, which is a pain.
  1479.  */
  1480. #define MY_MAXVAL (255)
  1481.  
  1482.         fprintf(pnmscale, "P6\n%d %d\n%d\n",
  1483.             rectwidth(&clipsrc), rectheight(&clipsrc), MY_MAXVAL);
  1484.  
  1485. #define REDEPTH(c, oldmax)  ((c) * ((MY_MAXVAL) + 1) / (oldmax + 1))
  1486.  
  1487.         switch (pixSize) {
  1488.         case 8:
  1489.             for (i = 0; i < ysize; ++i) {
  1490.                 for (j = 0; j < xsize; ++j) {
  1491.                     ct = colour_map + *src++;
  1492.                     fputc(REDEPTH(ct->red, 65535L), pnmscale);
  1493.                     fputc(REDEPTH(ct->green, 65535L), pnmscale);
  1494.                     fputc(REDEPTH(ct->blue, 65535L), pnmscale);
  1495.                 }
  1496.                 src += srcadd;
  1497.             }
  1498.             break;
  1499.         case 16:
  1500.             for (i = 0; i < ysize; ++i) {
  1501.                 for (j = 0; j < xsize; ++j) {
  1502.                     fputc(REDEPTH((*src & 0x7c) >> 2, 32), pnmscale);
  1503.                     greenpix = (*src++ & 3) << 3;
  1504.                     greenpix |= (*src & 0xe0) >> 5;
  1505.                     fputc(REDEPTH(greenpix, 32), pnmscale);
  1506.                     fputc(REDEPTH((*src++ & 0x1f) << 11, 32), pnmscale);
  1507.                 }
  1508.                 src += srcadd;
  1509.             }
  1510.             break;
  1511.         case 32:
  1512.             srcadd = srcwid - xsize;
  1513.             redsrc = src;
  1514.             greensrc = src + (srcwid / 3);
  1515.             bluesrc = greensrc + (srcwid / 3);
  1516.  
  1517.             for (i = 0; i < ysize; ++i) {
  1518.                 for (j = 0; j < xsize; ++j) {
  1519.                     fputc(REDEPTH(*redsrc++, 256), pnmscale);
  1520.                     fputc(REDEPTH(*greensrc++, 256), pnmscale);
  1521.                     fputc(REDEPTH(*bluesrc++, 256), pnmscale);
  1522.                 }
  1523.                 redsrc += srcadd;
  1524.                 greensrc += srcadd;
  1525.                 bluesrc += srcadd;
  1526.             }
  1527.         }
  1528.  
  1529. #if (defined(AMIGA) || defined(VMS))
  1530.                 if( fclose(pnmscale) != 0 ) {
  1531.                     unlink(ami_tmpfile);
  1532.                     pm_perror("write error");
  1533.                 }
  1534.                 sprintf(command, "pnmscale -xsize %d -ysize %d %s > %s",
  1535.                         rectwidth(&clipdst), rectheight(&clipdst), ami_tmpfile, tmpfile);
  1536.                 pm_message("running 'pnmscale -xsize %d -ysize %d' on a %d x %d image",
  1537.                         rectwidth(&clipdst), rectheight(&clipdst),
  1538.                         rectwidth(&clipsrc), rectheight(&clipsrc), 0);
  1539.                 ami_result = system(command);
  1540.                 unlink(ami_tmpfile);
  1541. #ifndef VMS
  1542.                 if( ami_result != 0 ) {
  1543. #else
  1544.                 if( ami_result == 0 ) {
  1545. #endif
  1546.                     unlink(tmpfile);
  1547.                     pm_perror("pnmscale failed");
  1548.                 }
  1549. #else /* AMIGA or VMS */
  1550.         if (pclose(pnmscale)) {
  1551.             pm_message("pnmscale failed", 0, 0, 0, 0, 0);
  1552.             pm_perror("pclose");
  1553.         }
  1554. #endif /* AMIGA or VMS */
  1555.         ppm_readppminit(scaled = pm_openr(tmpfile), &cols, &rows,
  1556.             &maxval, &format);
  1557.         row = ppm_allocrow(cols);
  1558.         /* couldn't hurt to assert cols, rows and maxval... */    
  1559.  
  1560.         if (trf == 0) {
  1561.             while (rows-- > 0) {
  1562.                 ppm_readppmrow(scaled, row, cols, maxval, format);
  1563.                 for (i = 0, rowp = row; i < cols; ++i, ++rowp) {
  1564.                     *reddst++ = PPM_GETR(*rowp) * 65536L / (maxval + 1); 
  1565.                     *greendst++ = PPM_GETG(*rowp) * 65536L / (maxval + 1); 
  1566.                     *bluedst++ = PPM_GETB(*rowp) * 65536L / (maxval + 1); 
  1567.                 }
  1568.                 reddst += dstadd;
  1569.                 greendst += dstadd;
  1570.                 bluedst += dstadd;
  1571.             }
  1572.         }
  1573.         else {
  1574.             while (rows-- > 0) {
  1575.                 ppm_readppmrow(scaled, row, cols, maxval, format);
  1576.                 for (i = 0, rowp = row; i < cols; i++, rowp++) {
  1577.                     dst_c.red = *reddst;
  1578.                     dst_c.green = *greendst;
  1579.                     dst_c.blue = *bluedst;
  1580.                     src_c.red = PPM_GETR(*rowp) * 65536L / (maxval + 1); 
  1581.                     src_c.green = PPM_GETG(*rowp) * 65536L / (maxval + 1); 
  1582.                     src_c.blue = PPM_GETB(*rowp) * 65536L / (maxval + 1); 
  1583.                     (*trf)(&src_c, &dst_c);
  1584.                     *reddst++ = dst_c.red;
  1585.                     *greendst++ = dst_c.green;
  1586.                     *bluedst++ = dst_c.blue;
  1587.                 }
  1588.                 reddst += dstadd;
  1589.                 greendst += dstadd;
  1590.                 bluedst += dstadd;
  1591.             }
  1592.         }
  1593.  
  1594.         pm_close(scaled);
  1595.         ppm_freerow(row);
  1596.         unlink(tmpfile);
  1597.         return;
  1598. #endif /* STANDALONE */
  1599.     }
  1600.  
  1601.     if (trf == 0) {
  1602.         /* optimized srcCopy blit ('cause it was implemented first) */
  1603.         switch (pixSize) {
  1604.         case 8:
  1605.             for (i = 0; i < ysize; ++i) {
  1606.                 for (j = 0; j < xsize; ++j) {
  1607.                     ct = colour_map + *src++;
  1608.                     *reddst++ = ct->red;
  1609.                     *greendst++ = ct->green;
  1610.                     *bluedst++ = ct->blue;
  1611.                 }
  1612.                 src += srcadd;
  1613.                 reddst += dstadd;
  1614.                 greendst += dstadd;
  1615.                 bluedst += dstadd;
  1616.             }
  1617.             break;
  1618.         case 16:
  1619.             for (i = 0; i < ysize; ++i) {
  1620.                 for (j = 0; j < xsize; ++j) {
  1621.                     *reddst++ = (*src & 0x7c) << 9;
  1622.                     *greendst = (*src++ & 3) << 14;
  1623.                     *greendst++ |= (*src & 0xe0) << 6;
  1624.                     *bluedst++ = (*src++ & 0x1f) << 11;
  1625.                 }
  1626.                 src += srcadd;
  1627.                 reddst += dstadd;
  1628.                 greendst += dstadd;
  1629.                 bluedst += dstadd;
  1630.             }
  1631.             break;
  1632.         case 32:
  1633.             srcadd = (srcwid / 3) - xsize;
  1634.             for (i = 0; i < ysize; ++i) {
  1635.                 for (j = 0; j < xsize; ++j)
  1636.                     *reddst++ = *src++ << 8;
  1637.  
  1638.                 reddst += dstadd;
  1639.                 src += srcadd;
  1640.  
  1641.                 for (j = 0; j < xsize; ++j)
  1642.                     *greendst++ = *src++ << 8;
  1643.  
  1644.                 greendst += dstadd;
  1645.                 src += srcadd;
  1646.  
  1647.                 for (j = 0; j < xsize; ++j)
  1648.                     *bluedst++ = *src++ << 8;
  1649.  
  1650.                 bluedst += dstadd;
  1651.                 src += srcadd;
  1652.             }
  1653.         }
  1654.     }
  1655.     else {
  1656. #define grab_destination()        \
  1657.         dst_c.red = *reddst;        \
  1658.         dst_c.green = *greendst;    \
  1659.         dst_c.blue = *bluedst
  1660.  
  1661. #define put_destination()        \
  1662.         *reddst++ = dst_c.red;    \
  1663.         *greendst++ = dst_c.green;    \
  1664.         *bluedst++ = dst_c.blue
  1665.  
  1666.         /* generalized (but slow) blit */
  1667.         switch (pixSize) {
  1668.         case 8:
  1669.             for (i = 0; i < ysize; ++i) {
  1670.                 for (j = 0; j < xsize; ++j) {
  1671.                     grab_destination();
  1672.                     (*trf)(colour_map + *src++, &dst_c);
  1673.                     put_destination();
  1674.                 }
  1675.                 src += srcadd;
  1676.                 reddst += dstadd;
  1677.                 greendst += dstadd;
  1678.                 bluedst += dstadd;
  1679.             }
  1680.             break;
  1681.         case 16:
  1682.             for (i = 0; i < ysize; ++i) {
  1683.                 for (j = 0; j < xsize; ++j) {
  1684.                     grab_destination();
  1685.                     src_c.red = (*src & 0x7c) << 9;
  1686.                     src_c.green = (*src++ & 3) << 14;
  1687.                     src_c.green |= (*src & 0xe0) << 6;
  1688.                     src_c.blue = (*src++ & 0x1f) << 11;
  1689.                     (*trf)(&src_c, &dst_c);
  1690.                     put_destination();
  1691.                 }
  1692.                 src += srcadd;
  1693.                 reddst += dstadd;
  1694.                 greendst += dstadd;
  1695.                 bluedst += dstadd;
  1696.             }
  1697.             break;
  1698.         case 32:
  1699.             srcadd = srcwid / 3;
  1700.             for (i = 0; i < ysize; i++) {
  1701.                 for (j = 0; j < xsize; j++) {
  1702.                     grab_destination();
  1703.                     src_c.red = *src << 8;
  1704.                     src_c.green = src[srcadd] << 8;
  1705.                     src_c.blue = src[srcadd * 2] << 8;
  1706.                     (*trf)(&src_c, &dst_c);
  1707.                     put_destination();
  1708.                     src++;
  1709.                 }
  1710.                 src += srcwid - xsize;
  1711.                 reddst += dstadd;
  1712.                 greendst += dstadd;
  1713.                 bluedst += dstadd;
  1714.             }
  1715.         }
  1716.     }
  1717.     return 1;
  1718. }
  1719.  
  1720. #if __STDC__
  1721. static byte*
  1722. unpackbits( struct Rect* bounds, word rowBytes, int pixelSize )
  1723. #else /*__STDC__*/
  1724. static byte*
  1725. unpackbits(bounds, rowBytes, pixelSize)
  1726. struct Rect* bounds;
  1727. word rowBytes;
  1728. int pixelSize;
  1729. #endif /*__STDC__*/
  1730. {
  1731.     byte* linebuf;
  1732.     byte* pm;
  1733.     byte* pm_ptr;
  1734.     register int i,j,k,l;
  1735.     word pixwidth;
  1736.     int linelen;
  1737.     int len;
  1738.     byte* bytepixels;
  1739.     int buflen;
  1740.     int pkpixsize;
  1741.     int rowsize;
  1742.  
  1743.     if (pixelSize <= 8)
  1744.         rowBytes &= 0x7fff;
  1745.  
  1746.     stage = "unpacking packbits";
  1747.  
  1748.     pixwidth = bounds->right - bounds->left;
  1749.  
  1750.     pkpixsize = 1;
  1751.     if (pixelSize == 16) {
  1752.         pkpixsize = 2;
  1753.         pixwidth *= 2;
  1754.     }
  1755.     else if (pixelSize == 32)
  1756.         pixwidth *= 3;
  1757.     
  1758.     if (rowBytes == 0)
  1759.         rowBytes = pixwidth;
  1760.  
  1761.     rowsize = pixwidth;
  1762.     if (rowBytes < 8)
  1763.         rowsize = 8 * rowBytes;    /* worst case expansion factor */
  1764.  
  1765.     /* we're sloppy and allocate some extra space because we can overshoot
  1766.      * by as many as 8 bytes when we unpack the raster lines.  Really, I
  1767.      * should be checking to see if we go over the scan line (it is
  1768.      * possible) and complain of a corrupt file.  That fix is more complex
  1769.      * (and probably costly in CPU cycles) and will have to come later.
  1770.      */
  1771.     if ((pm = (byte*)malloc((rowsize * (bounds->bottom - bounds->top) + 8) * sizeof(byte))) == NULL)
  1772.         pm_error("no mem for packbits rectangle");
  1773.  
  1774.     /* Sometimes we get rows with length > rowBytes.  I'll allocate some
  1775.      * extra for slop and only die if the size is _way_ out of wack.
  1776.      */
  1777.     if ((linebuf = (byte*)malloc(rowBytes + 100)) == NULL)
  1778.         pm_error("can't allocate memory for line buffer");
  1779.  
  1780.     if (rowBytes < 8) {
  1781.         /* ah-ha!  The bits aren't actually packed.  This will be easy */
  1782.         for (i = 0; i < bounds->bottom - bounds->top; i++) {
  1783.             pm_ptr = pm + i * pixwidth;
  1784.             read_n(buflen = rowBytes, (char*) linebuf);
  1785.             bytepixels = expand_buf(linebuf, &buflen, pixelSize);
  1786.             for (j = 0; j < buflen; j++)
  1787.                 *pm_ptr++ = *bytepixels++;
  1788.         }
  1789.     }
  1790.     else {
  1791.         for (i = 0; i < bounds->bottom - bounds->top; i++) {
  1792.             pm_ptr = pm + i * pixwidth;
  1793.             if (rowBytes > 250 || pixelSize > 8)
  1794.                 linelen = read_word();
  1795.             else
  1796.                 linelen = read_byte();
  1797.  
  1798.             if (verbose > 1)
  1799.                 pm_message("linelen: %d", linelen, 0, 0, 0, 0);
  1800.  
  1801.             if (linelen > rowBytes) {
  1802.                 pm_message("linelen > rowbytes! (%d > %d) at line %d",
  1803.                     linelen, rowBytes, i, 0, 0);
  1804.             }
  1805.  
  1806.             read_n(linelen, (char*) linebuf);
  1807.  
  1808.             for (j = 0; j < linelen; ) {
  1809.                 if (linebuf[j] & 0x80) {
  1810.                     len = ((linebuf[j] ^ 255) & 255) + 2;
  1811.                     buflen = pkpixsize;
  1812.                     bytepixels = expand_buf(linebuf + j+1, &buflen, pixelSize);
  1813.                     for (k = 0; k < len; k++) {
  1814.                         for (l = 0; l < buflen; l++)
  1815.                             *pm_ptr++ = *bytepixels++;
  1816.                         bytepixels -= buflen;
  1817.                     }
  1818.                     j += 1 + pkpixsize;
  1819.                 }
  1820.                 else {
  1821.                     len = (linebuf[j] & 255) + 1;
  1822.                     buflen = len * pkpixsize;
  1823.                     bytepixels = expand_buf(linebuf + j+1, &buflen, pixelSize);
  1824.                     for (k = 0; k < buflen; k++)
  1825.                         *pm_ptr++ = *bytepixels++;
  1826.                     j += len * pkpixsize + 1;
  1827.                 }
  1828.             }
  1829.         }
  1830.     }
  1831.  
  1832.     free(linebuf);
  1833.  
  1834.     return pm;
  1835. }
  1836.  
  1837. static byte*
  1838. expand_buf(buf, len, bits_per_pixel)
  1839. byte* buf;
  1840. int* len;
  1841. int bits_per_pixel;
  1842. {
  1843.     static byte pixbuf[256 * 8];
  1844.     register byte* src;
  1845.     register byte* dst;
  1846.     register int i;
  1847.  
  1848.     src = buf;
  1849.     dst = pixbuf;
  1850.  
  1851.     switch (bits_per_pixel) {
  1852.     case 8:
  1853.     case 16:
  1854.     case 32:
  1855.         return buf;
  1856.     case 4:
  1857.         for (i = 0; i < *len; i++) {
  1858.             *dst++ = (*src >> 4) & 15;
  1859.             *dst++ = *src++ & 15;
  1860.         }
  1861.         *len *= 2;
  1862.         break;
  1863.     case 2:
  1864.         for (i = 0; i < *len; i++) {
  1865.             *dst++ = (*src >> 6) & 3;
  1866.             *dst++ = (*src >> 4) & 3;
  1867.             *dst++ = (*src >> 2) & 3;
  1868.             *dst++ = *src++ & 3;
  1869.         }
  1870.         *len *= 4;
  1871.         break;
  1872.     case 1:
  1873.         for (i = 0; i < *len; i++) {
  1874.             *dst++ = (*src >> 7) & 1;
  1875.             *dst++ = (*src >> 6) & 1;
  1876.             *dst++ = (*src >> 5) & 1;
  1877.             *dst++ = (*src >> 4) & 1;
  1878.             *dst++ = (*src >> 3) & 1;
  1879.             *dst++ = (*src >> 2) & 1;
  1880.             *dst++ = (*src >> 1) & 1;
  1881.             *dst++ = *src++ & 1;
  1882.         }
  1883.         *len *= 8;
  1884.         break;
  1885.     default:
  1886.         pm_error("bad bits per pixel in expand_buf");
  1887.     }
  1888.     return pixbuf;
  1889. }
  1890.  
  1891. static void
  1892. Clip(version)
  1893. int version;
  1894. {
  1895.     word len;
  1896.  
  1897.     len = read_word();
  1898.  
  1899.     if (len == 0x000a) {    /* null rgn */
  1900.         read_rect(&clip_rect);
  1901.         /* XXX should clip this by picFrame */
  1902.         if (verbose)
  1903.             dump_rect("clipping to", &clip_rect);
  1904.     }
  1905.     else
  1906.         skip(len - 2);
  1907. }
  1908.  
  1909. static void
  1910. read_pixmap(p, rowBytes)
  1911. struct pixMap* p;
  1912. word* rowBytes;
  1913. {
  1914.     stage = "getting pixMap header";
  1915.  
  1916.     if (rowBytes != NULL)
  1917.         *rowBytes = read_word();
  1918.  
  1919.     read_rect(&p->Bounds);
  1920.     p->version = read_word();
  1921.     p->packType = read_word();
  1922.     p->packSize = read_long();
  1923.     p->hRes = read_long();
  1924.     p->vRes = read_long();
  1925.     p->pixelType = read_word();
  1926.     p->pixelSize = read_word();
  1927.     p->cmpCount = read_word();
  1928.     p->cmpSize = read_word();
  1929.     p->planeBytes = read_long();
  1930.     p->pmTable = read_long();
  1931.     p->pmReserved = read_long();
  1932.  
  1933.     if (verbose) {
  1934.         pm_message("pixelType: %d", p->pixelType, 0, 0, 0, 0);
  1935.         pm_message("pixelSize: %d", p->pixelSize, 0, 0, 0, 0);
  1936.         pm_message("cmpCount:  %d", p->cmpCount, 0, 0, 0, 0);
  1937.         pm_message("cmpSize:   %d", p->cmpSize, 0, 0, 0, 0);
  1938.     }
  1939.  
  1940.     if (p->pixelType != 0)
  1941.         pm_error("sorry, I only do chunky format");
  1942.     if (p->cmpCount != 1)
  1943.         pm_error("sorry, cmpCount != 1");
  1944.     if (p->pixelSize != p->cmpSize)
  1945.         pm_error("oops, pixelSize != cmpSize");
  1946. }
  1947.  
  1948. static struct RGBColour*
  1949. read_colour_table()
  1950. {
  1951.     longword ctSeed;
  1952.     word ctFlags;
  1953.     word ctSize;
  1954.     word val;
  1955.     int i;
  1956.     struct RGBColour* colour_table;
  1957.  
  1958.     stage = "getting color table info";
  1959.  
  1960.     ctSeed = read_long();
  1961.     ctFlags = read_word();
  1962.     ctSize = read_word();
  1963.  
  1964.     if (verbose) {
  1965.         pm_message("ctSeed:  %d", ctSeed, 0, 0, 0, 0);
  1966.         pm_message("ctFlags: %d", ctFlags, 0, 0, 0, 0);
  1967.         pm_message("ctSize:  %d", ctSize, 0, 0, 0, 0);
  1968.     }
  1969.  
  1970.     stage = "reading colour table";
  1971.  
  1972.     if ((colour_table = (struct RGBColour*) malloc(sizeof(struct RGBColour) * (ctSize + 1))) == NULL)
  1973.         pm_error("no memory for colour table");
  1974.  
  1975.     for (i = 0; i <= ctSize; i++) {
  1976.         val = read_word();
  1977.         /* The indicies in a device colour table are bogus and usually == 0.
  1978.          * so I assume we allocate up the list of colours in order.
  1979.          */
  1980.         if (ctFlags & 0x8000)
  1981.             val = i;
  1982.         if (val > ctSize)
  1983.             pm_error("pixel value greater than colour table size");
  1984.         colour_table[val].red = read_word();
  1985.         colour_table[val].green = read_word();
  1986.         colour_table[val].blue = read_word();
  1987.  
  1988.         if (verbose > 1)
  1989.             pm_message("%d: [%d,%d,%d]", val,
  1990.                 colour_table[val].red,
  1991.                 colour_table[val].green,
  1992.                 colour_table[val].blue, 0);
  1993.     }
  1994.  
  1995.     return colour_table;
  1996. }
  1997.  
  1998. static void
  1999. OpColor(version)
  2000. int version;
  2001. {
  2002.     op_colour.red = read_word();
  2003.     op_colour.green = read_word();
  2004.     op_colour.blue = read_word();
  2005. }
  2006.  
  2007. /* these 3 do nothing but skip over their data! */
  2008. static void
  2009. BkPixPat(version)
  2010. int version;
  2011. {
  2012.     read_pattern();
  2013. }
  2014.  
  2015. static void
  2016. PnPixPat(version)
  2017. int version;
  2018. {
  2019.     read_pattern();
  2020. }
  2021.  
  2022. static void
  2023. FillPixPat(version)
  2024. int version;
  2025. {
  2026.     read_pattern();
  2027. }
  2028.  
  2029. /* this just skips over a version 2 pattern.  Probabaly will return
  2030.  * a pattern in the fabled complete version.
  2031.  */
  2032. static void
  2033. read_pattern()
  2034. {
  2035.     word PatType;
  2036.     word rowBytes;
  2037.     struct pixMap p;
  2038.     byte* pm;
  2039.     struct RGBColour* ct;
  2040.  
  2041.     stage = "Reading a pattern";
  2042.  
  2043.     PatType = read_word();
  2044.  
  2045.     switch (PatType) {
  2046.     case 2:
  2047.         skip(8); /* old pattern data */
  2048.         skip(5); /* RGB for pattern */
  2049.         break;
  2050.     case 1:
  2051.         skip(8); /* old pattern data */
  2052.         read_pixmap(&p, &rowBytes);
  2053.         ct = read_colour_table();
  2054.         pm = unpackbits(&p.Bounds, rowBytes, p.pixelSize);
  2055.         free(pm);
  2056.         free(ct);
  2057.         break;
  2058.     default:
  2059.         pm_error("unknown pattern type in read_pattern");
  2060.     }
  2061. }
  2062.  
  2063. static void BkPat(version)
  2064. int version;
  2065. {
  2066.     read_8x8_pattern(&bkpat);
  2067. }
  2068.  
  2069. static void PnPat(version)
  2070. int version;
  2071. {
  2072.     read_8x8_pattern(&pen_pat);
  2073. }
  2074.  
  2075. static void FillPat(version)
  2076. int version;
  2077. {
  2078.     read_8x8_pattern(&fillpat);
  2079. }
  2080.  
  2081. static void
  2082. read_8x8_pattern(pat)
  2083. struct Pattern* pat;
  2084. {
  2085.     byte buf[8], *exp;
  2086.     int len, i;
  2087.  
  2088.     read_n(len = 8, (char*)buf);
  2089.     if (verbose) {
  2090.         pm_message("pattern: %02x%02x%02x%02x",
  2091.             buf[0], buf[1], buf[2], buf[3], 0);
  2092.         pm_message("pattern: %02x%02x%02x%02x",
  2093.             buf[4], buf[5], buf[6], buf[7], 0);
  2094.     }
  2095.     exp = expand_buf(buf, &len, 1);
  2096.     for (i = 0; i < 64; i++)
  2097.         pat->pix[i] = *exp++;
  2098. }
  2099.  
  2100. static void PnSize(version)
  2101. int version;
  2102. {
  2103.     pen_height = read_word();
  2104.     pen_width = read_word();
  2105.     if (verbose)
  2106.         pm_message("pen size %d x %d", pen_width, pen_height, 0, 0, 0);
  2107. }
  2108.  
  2109. static void PnMode(version)
  2110. int version;
  2111. {
  2112.     pen_mode = read_word();
  2113.  
  2114.     if (pen_mode >= 8 && pen_mode < 15)
  2115.         pen_mode -= 8;
  2116.     if (verbose)
  2117.         pm_message("pen transfer mode = %s",
  2118.             const_name(transfer_name, pen_mode), 0, 0, 0, 0);
  2119.     
  2120.     pen_trf = transfer(pen_mode);
  2121. }
  2122.  
  2123. static void read_rgb(rgb)
  2124. struct RGBColour* rgb;
  2125. {
  2126.     rgb->red = read_word();
  2127.     rgb->green = read_word();
  2128.     rgb->blue = read_word();
  2129. }
  2130.  
  2131. static void RGBFgCol(v)
  2132. int v;
  2133. {
  2134.     read_rgb(&foreground);
  2135.     if (verbose)
  2136.         pm_message("foreground now [%d,%d,%d]", 
  2137.             foreground.red, foreground.green, foreground.blue, 0, 0);
  2138. }
  2139.  
  2140. static void RGBBkCol(v)
  2141. int v;
  2142. {
  2143.     read_rgb(&background);
  2144.     if (verbose)
  2145.         pm_message("background now [%d,%d,%d]", 
  2146.             background.red, background.green, background.blue, 0, 0);
  2147. }
  2148.  
  2149. static void read_point(p)
  2150. struct Point* p;
  2151. {
  2152.     p->y = read_word();
  2153.     p->x = read_word();
  2154. }
  2155.  
  2156. static void read_short_point(p)
  2157. struct Point* p;
  2158. {
  2159.     p->x = read_signed_byte();
  2160.     p->y = read_signed_byte();
  2161. }
  2162.  
  2163. #define PIXEL_INDEX(x,y) ((y) - picFrame.top) * rowlen + (x) - picFrame.left
  2164.  
  2165. static void draw_pixel(x, y, clr, trf)
  2166. int x, y;
  2167. struct RGBColour* clr;
  2168. transfer_func trf;
  2169. {
  2170.     register i;
  2171.     struct RGBColour dst;
  2172.  
  2173.     if (x < clip_rect.left || x >= clip_rect.right ||
  2174.         y < clip_rect.top || y >= clip_rect.bottom)
  2175.     {
  2176.         return;
  2177.     }
  2178.  
  2179.     i = PIXEL_INDEX(x, y);
  2180.     dst.red = red[i];
  2181.     dst.green = green[i];
  2182.     dst.blue = blue[i];
  2183.     (*trf)(clr, &dst);
  2184.     red[i] = dst.red;
  2185.     green[i] = dst.green;
  2186.     blue[i] = dst.blue;
  2187. }
  2188.  
  2189. static void draw_pen_rect(r)
  2190. struct Rect* r;
  2191. {
  2192.     register i = PIXEL_INDEX(r->left, r->top);
  2193.     register int x, y;
  2194.     struct RGBColour dst;
  2195.     int rowadd = rowlen - (r->right - r->left);
  2196.  
  2197.     for (y = r->top; y < r->bottom; y++) {
  2198.         for (x = r->left; x < r->right; x++) {
  2199.             dst.red = red[i];
  2200.             dst.green = green[i];
  2201.             dst.blue = blue[i];
  2202.             if (pen_pat.pix[(x & 7) + (y & 7) * 8])
  2203.                 (*pen_trf)(&black, &dst);
  2204.             else
  2205.                 (*pen_trf)(&white, &dst);
  2206.             red[i] = dst.red;
  2207.             green[i] = dst.green;
  2208.             blue[i] = dst.blue;
  2209.  
  2210.             i++;
  2211.         }
  2212.         i += rowadd;
  2213.     }
  2214. }
  2215.  
  2216. static void draw_pen(x, y)
  2217. int x, y;
  2218. {
  2219.     struct Rect penrect;
  2220.  
  2221.     penrect.left = x;
  2222.     penrect.right = x + pen_width;
  2223.     penrect.top = y;
  2224.     penrect.bottom = y + pen_height;
  2225.  
  2226.     rectinter(&penrect, &clip_rect, &penrect);
  2227.  
  2228.     draw_pen_rect(&penrect);
  2229. }
  2230.  
  2231. /*
  2232.  * Digital Line Drawing
  2233.  * by Paul Heckbert
  2234.  * from "Graphics Gems", Academic Press, 1990
  2235.  */
  2236.  
  2237. /* absolute value of a */
  2238. #define ABS(a)        (((a)<0) ? -(a) : (a))
  2239. /* take binary sign of a, either -1, or 1 if >= 0 */
  2240. #define SGN(a)        (((a)<0) ? -1 : 1)
  2241.  
  2242. /*
  2243.  * digline: draw digital line from (x1,y1) to (x2,y2),
  2244.  * calling a user-supplied procedure at each pixel.
  2245.  * Does no clipping.  Uses Bresenham's algorithm.
  2246.  *
  2247.  * Paul Heckbert    3 Sep 85
  2248.  */
  2249. static void scan_line(x1,y1,x2,y2)
  2250.      short x1,y1,x2,y2;
  2251. {
  2252.     int d, x, y, ax, ay, sx, sy, dx, dy;
  2253.  
  2254.     if (pen_width == 0 && pen_height == 0)
  2255.         return;
  2256.  
  2257.     dx = x2-x1;  ax = ABS(dx)<<1;  sx = SGN(dx);
  2258.     dy = y2-y1;  ay = ABS(dy)<<1;  sy = SGN(dy);
  2259.  
  2260.     x = x1;
  2261.     y = y1;
  2262.     if (ax>ay) {        /* x dominant */
  2263.     d = ay-(ax>>1);
  2264.     for (;;) {
  2265.         draw_pen(x, y);
  2266.         if (x==x2) return;
  2267.         if ((x > rowlen) && (sx > 0)) return;
  2268.         if (d>=0) {
  2269.         y += sy;
  2270.         d -= ax;
  2271.         }
  2272.         x += sx;
  2273.         d += ay;
  2274.     }
  2275.     }
  2276.     else {            /* y dominant */
  2277.     d = ax-(ay>>1);
  2278.     for (;;) {
  2279.         draw_pen(x, y);
  2280.         if (y==y2) return;
  2281.         if ((y > collen) && (sy > 0)) return;
  2282.         if (d>=0) {
  2283.         x += sx;
  2284.         d -= ay;
  2285.         }
  2286.         y += sy;
  2287.         d += ax;
  2288.     }
  2289.     }
  2290. }
  2291.  
  2292. static void Line(v)
  2293.      int v;
  2294. {
  2295.   struct Point p1;
  2296.   read_point(&p1);
  2297.   read_point(¤t);
  2298.   if (verbose)
  2299.     pm_message("(%d,%d) to (%d, %d)",
  2300.            p1.x,p1.y,current.x,current.y, 0);
  2301.   scan_line(p1.x,p1.y,current.x,current.y);
  2302. }
  2303.  
  2304. static void LineFrom(v)
  2305.      int v;
  2306. {
  2307.   struct Point p1;
  2308.   read_point(&p1);
  2309.   if (verbose)
  2310.     pm_message("(%d,%d) to (%d, %d)",
  2311.            current.x,current.y,p1.x,p1.y, 0);
  2312.  
  2313.   if (!fullres)
  2314.       scan_line(current.x,current.y,p1.x,p1.y);
  2315.  
  2316.   current.x = p1.x;
  2317.   current.y = p1.y;
  2318. }
  2319.  
  2320. static void ShortLine(v)
  2321.      int v;
  2322. {
  2323.   struct Point p1;
  2324.   read_point(&p1);
  2325.   read_short_point(¤t);
  2326.   if (verbose)
  2327.     pm_message("(%d,%d) delta (%d, %d)",
  2328.            p1.x,p1.y,current.x,current.y, 0);
  2329.   current.x += p1.x;
  2330.   current.y += p1.y;
  2331.  
  2332.   if (!fullres)
  2333.       scan_line(p1.x,p1.y,current.x,current.y);
  2334. }
  2335.  
  2336. static void ShortLineFrom(v)
  2337.      int v;
  2338. {
  2339.   struct Point p1;
  2340.   read_short_point(&p1);
  2341.   if (verbose)
  2342.     pm_message("(%d,%d) delta (%d, %d)",
  2343.            current.x,current.y,p1.x,p1.y, 0);
  2344.   p1.x += current.x;
  2345.   p1.y += current.y;
  2346.   if (!fullres)
  2347.       scan_line(current.x,current.y,p1.x,p1.y);
  2348.   current.x = p1.x;
  2349.   current.y = p1.y;
  2350. }
  2351.  
  2352. static void paintRect(v)
  2353. int v;
  2354. {
  2355.     read_rect(&cur_rect);
  2356.     do_paintRect(&cur_rect);
  2357. }
  2358.  
  2359. static void paintSameRect(v)
  2360. int v;
  2361. {
  2362.     do_paintRect(&cur_rect);
  2363. }
  2364.  
  2365. static void do_paintRect(prect)
  2366. struct Rect* prect;
  2367. {
  2368.     struct Rect rect;
  2369.   
  2370.     if (fullres)
  2371.         return;
  2372.  
  2373.     if (verbose)
  2374.         dump_rect("painting", prect);
  2375.  
  2376.     rectinter(&clip_rect, prect, &rect);
  2377.  
  2378.     draw_pen_rect(&rect);
  2379. }
  2380.  
  2381. static void frameRect(v)
  2382. int v;
  2383. {
  2384.     read_rect(&cur_rect);
  2385.     do_frameRect(&cur_rect);
  2386. }
  2387.  
  2388. static void frameSameRect(v)
  2389. int v;
  2390. {
  2391.     do_frameRect(&cur_rect);
  2392. }
  2393.  
  2394. static void do_frameRect(rect)
  2395. struct Rect* rect;
  2396. {
  2397.     register int x, y;
  2398.  
  2399.     if (fullres)
  2400.         return;
  2401.   
  2402.     if (verbose)
  2403.         dump_rect("framing", rect);
  2404.  
  2405.     if (pen_width == 0 || pen_height == 0)
  2406.         return;
  2407.  
  2408.     for (x = rect->left; x <= rect->right - pen_width; x += pen_width) {
  2409.         draw_pen(x, rect->top);
  2410.         draw_pen(x, rect->bottom - pen_height);
  2411.     }
  2412.  
  2413.     for (y = rect->top; y <= rect->bottom - pen_height ; y += pen_height) {
  2414.         draw_pen(rect->left, y);
  2415.         draw_pen(rect->right - pen_width, y);
  2416.     }
  2417. }
  2418.  
  2419. /* a stupid shell sort - I'm so embarassed  */
  2420.  
  2421. static void poly_sort(sort_index, points)
  2422.      int sort_index;
  2423.      struct Point points[];
  2424. {
  2425.   int d,i,j,k,temp;
  2426.  
  2427.   /* initialize and set up sort interval */
  2428.   d = 4;
  2429.   while (d<=sort_index) d <<= 1;
  2430.   d -= 1;
  2431.  
  2432.   while (d > 1) {
  2433.     d >>= 1;
  2434.     for (j = 0; j <= (sort_index-d); j++) {
  2435.       for(i = j; i >= 0; i -= d) {
  2436.     if ((points[i+d].y < points[i].y) ||
  2437.         ((points[i+d].y == points[i].y) &&
  2438.          (points[i+d].x <= points[i].x))) {
  2439.       /* swap x1,y1 with x2,y2 */
  2440.       temp = points[i].y;
  2441.       points[i].y = points[i+d].y;
  2442.       points[i+d].y = temp;
  2443.       temp = points[i].x;
  2444.       points[i].x = points[i+d].x;
  2445.       points[i+d].x = temp;
  2446.     }
  2447.       }
  2448.     }
  2449.   }
  2450. }
  2451.  
  2452. /* Watch out for the lack of error checking in the next two functions ... */
  2453.  
  2454. static void scan_poly(np, pts)
  2455.      int np;
  2456.      struct Point pts[];
  2457. {
  2458.   int dx,dy,dxabs,dyabs,i,scan_index,j,k,px,py;
  2459.   int sdx,sdy,x,y,toggle,old_sdy,sy0;
  2460.  
  2461.   /* This array needs to be at least as large as the largest dimension of
  2462.      the bounding box of the poly (but I don't check for overflows ...) */
  2463.   struct Point coord[5000];
  2464.  
  2465.   scan_index = 0;
  2466.  
  2467.   /* close polygon */
  2468.   px = pts[np].x = pts[0].x;
  2469.   py = pts[np].y = pts[0].y;
  2470.  
  2471.   /*  This section draws the polygon and stores all the line points
  2472.    *  in an array. This doesn't work for concave or non-simple polys.
  2473.    */
  2474.   /* are y levels same for first and second points? */
  2475.   if (pts[1].y == pts[0].y) {
  2476.     coord[scan_index].x = px;
  2477.     coord[scan_index].y = py;
  2478.     scan_index++;
  2479.   }
  2480.  
  2481. #define sign(x) ((x) > 0 ? 1 : ((x)==0 ? 0:(-1)) )   
  2482.  
  2483.   old_sdy = sy0 = sign(pts[1].y - pts[0].y);
  2484.   for (j=0; j<np; j++) {
  2485.     /* x,y difference between consecutive points and their signs  */
  2486.     dx = pts[j+1].x - pts[j].x;
  2487.     dy = pts[j+1].y - pts[j].y;
  2488.     sdx = SGN(dx);
  2489.     sdy = SGN(dy);
  2490.     dxabs = abs(dx);
  2491.     dyabs = abs(dy);
  2492.     x = y = 0;
  2493.  
  2494.     if (dxabs >= dyabs)
  2495.       {
  2496.     for (k=0; k < dxabs; k++) {
  2497.       y += dyabs;
  2498.       if (y >= dxabs) {
  2499.         y -= dxabs;
  2500.         py += sdy;
  2501.         if (old_sdy != sdy) {
  2502.           old_sdy = sdy;
  2503.           scan_index--;
  2504.         }
  2505.         coord[scan_index].x = px+sdx;
  2506.         coord[scan_index].y = py;
  2507.         scan_index++;
  2508.       }
  2509.       px += sdx;
  2510.       draw_pen(px, py);
  2511.     }
  2512.       }
  2513.     else
  2514.       {
  2515.     for (k=0; k < dyabs; k++) {
  2516.       x += dxabs;
  2517.       if (x >= dyabs) {
  2518.         x -= dyabs;
  2519.         px += sdx;
  2520.       }
  2521.       py += sdy;
  2522.       if (old_sdy != sdy) {
  2523.         old_sdy = sdy;
  2524.         if (sdy != 0) scan_index--;
  2525.       }
  2526.       draw_pen(px,py);
  2527.       coord[scan_index].x = px;
  2528.       coord[scan_index].y = py;
  2529.       scan_index++;
  2530.     }
  2531.       }
  2532.   }
  2533.  
  2534.   /* after polygon has been drawn now fill it */
  2535.  
  2536.   scan_index--;
  2537.   if (sy0 + sdy == 0) scan_index--;
  2538.  
  2539.   poly_sort(scan_index, coord);
  2540.   
  2541.   toggle = 0;
  2542.   for (i = 0; i < scan_index; i++) {
  2543.     if ((coord[i].y == coord[i+1].y) && (toggle == 0))
  2544.       {
  2545.     for (j = coord[i].x; j <= coord[i+1].x; j++)
  2546.       draw_pen(j, coord[i].y);
  2547.     toggle = 1;
  2548.       }
  2549.     else
  2550.       toggle = 0;
  2551.   }
  2552. }
  2553.   
  2554.   
  2555. static void paintPoly(v)
  2556.      int v;
  2557. {
  2558.   struct Rect bb;
  2559.   struct Point pts[100];
  2560.   int i, np = (read_word() - 10) >> 2;
  2561.  
  2562.   read_rect(&bb);
  2563.   for (i=0; i<np; ++i)
  2564.     read_point(&pts[i]);
  2565.  
  2566.   /* scan convert poly ... */
  2567.   if (!fullres)
  2568.       scan_poly(np, pts);
  2569. }
  2570.  
  2571. static void PnLocHFrac(version)
  2572. int version;
  2573. {
  2574.     word frac = read_word();
  2575.  
  2576.     if (verbose)
  2577.         pm_message("PnLocHFrac = %d", frac, 0, 0, 0, 0);
  2578. }
  2579.  
  2580. static void TxMode(version)
  2581. int version;
  2582. {
  2583.     text_mode = read_word();
  2584.  
  2585.     if (text_mode >= 8 && text_mode < 15)
  2586.         text_mode -= 8;
  2587.     if (verbose)
  2588.         pm_message("text transfer mode = %s",
  2589.             const_name(transfer_name, text_mode), 0, 0, 0, 0);
  2590.     
  2591.     /* ignore the text mask bit 'cause we don't handle it yet */
  2592.     text_trf = transfer(text_mode & ~64);
  2593. }
  2594.  
  2595. static void TxFont(version)
  2596. int version;
  2597. {
  2598.     text_font = read_word();
  2599.     if (verbose)
  2600.         pm_message("text font %s", const_name(font_name, text_font), 0, 0, 0, 0);
  2601. }
  2602.  
  2603. static void TxFace(version)
  2604. int version;
  2605. {
  2606.     text_face = read_byte();
  2607.     if (verbose)
  2608.         pm_message("text face %d", text_face, 0, 0, 0, 0);
  2609. }
  2610.  
  2611. static void TxSize(version)
  2612. int version;
  2613. {
  2614.     text_size = read_word();
  2615.     if (verbose)
  2616.         pm_message("text size %d", text_size, 0, 0, 0, 0);
  2617. }
  2618.  
  2619. static void
  2620. skip_text()
  2621. {
  2622.     skip(read_byte());
  2623. }
  2624.  
  2625. static void
  2626. LongText(version)
  2627. int version;
  2628. {
  2629.     struct Point p;
  2630.  
  2631.     read_point(&p);
  2632.     do_text(p.x, p.y);
  2633. }
  2634.  
  2635. static void
  2636. DHText(version)
  2637. int version;
  2638. {
  2639.     current.x += read_byte();
  2640.     do_text(current.x, current.y);
  2641. }
  2642.  
  2643. static void
  2644. DVText(version)
  2645. int version;
  2646. {
  2647.     current.y += read_byte();
  2648.     do_text(current.x, current.y);
  2649. }
  2650.  
  2651. static void
  2652. DHDVText(version)
  2653. int version;
  2654. {
  2655.     byte dh, dv;
  2656.  
  2657.     dh = read_byte();
  2658.     dv = read_byte();
  2659.  
  2660.     if (verbose)
  2661.         pm_message("dh, dv = %d, %d", dh, dv, 0, 0, 0);
  2662.  
  2663.     current.x += dh;
  2664.     current.y += dv;
  2665.     do_text(current.x, current.y);
  2666. }
  2667.  
  2668. static void
  2669. #ifdef __STDC__
  2670. do_text(word x, word y)
  2671. #else
  2672. do_text(x, y)
  2673. word x;
  2674. word y;
  2675. #endif
  2676. {
  2677.     int len, dy, w, h;
  2678.     struct glyph* glyph;
  2679.  
  2680.     if (fullres) {
  2681.         skip_text();
  2682.         return;
  2683.     }
  2684.  
  2685.     if (!(tfont = get_font(text_font, text_size, text_face)))
  2686.         tfont = pbm_defaultfont("bdf");
  2687.  
  2688.     if (ps_text) {
  2689.         do_ps_text(x, y);
  2690.         return;
  2691.     }
  2692.  
  2693.     for (len = read_byte(); len > 0; len--) {
  2694.         if (!(glyph = tfont->glyph[read_byte()]))
  2695.             continue;
  2696.         
  2697.         dy = y - glyph->height - glyph->y;
  2698.         for (h = 0; h < glyph->height; h++) {
  2699.             for (w = 0; w < glyph->width; w++) {
  2700.                 if (glyph->bmap[h * glyph->width + w])
  2701.                     draw_pixel(x + w + glyph->x, dy, &black, text_trf);
  2702.                 else
  2703.                     draw_pixel(x + w + glyph->x, dy, &white, text_trf);
  2704.             }
  2705.             dy++;
  2706.         }
  2707.         x += glyph->xadd;
  2708.     }
  2709.  
  2710.  
  2711.     current.x = x;
  2712.     current.y = y;
  2713. }
  2714.  
  2715. static void
  2716. #ifdef __STDC__
  2717. do_ps_text(word tx, word ty)
  2718. #else
  2719. do_ps_text(tx, ty)
  2720. word tx;
  2721. word ty;
  2722. #endif
  2723. {
  2724.     int len, width, i, w, h, x, y, rx, ry, o;
  2725.     byte str[256], ch;
  2726.     struct glyph* glyph;
  2727.  
  2728.     current.x = tx;
  2729.     current.y = ty;
  2730.  
  2731.     if (!ps_cent_set) {
  2732.         ps_cent_x += tx;
  2733.         ps_cent_y += ty;
  2734.         ps_cent_set = 1;
  2735.     }
  2736.  
  2737.     len = read_byte();
  2738.  
  2739.     /* XXX this width calculation is not completely correct */
  2740.     width = 0;
  2741.     for (i = 0; i < len; i++) {
  2742.         ch = str[i] = read_byte();
  2743.         if (tfont->glyph[ch])
  2744.             width += tfont->glyph[ch]->xadd;
  2745.     }
  2746.  
  2747.     if (verbose) {
  2748.         str[len] = '\0';
  2749.         pm_message("ps text: %s", str);
  2750.     }
  2751.  
  2752.     /* XXX The width is calculated in order to do different justifications.
  2753.      * However, I need the width of original text to finish the job.
  2754.      * In other words, font metrics for Quickdraw fonts
  2755.      */
  2756.  
  2757.     x = tx;
  2758.  
  2759.     for (i = 0; i < len; i++) {
  2760.         if (!(glyph = tfont->glyph[str[i]]))
  2761.             continue;
  2762.         
  2763.         y = ty - glyph->height - glyph->y;
  2764.         for (h = 0; h < glyph->height; h++) {
  2765.             for (w = 0; w < glyph->width; w++) {
  2766.                 rx = x + glyph->x + w;
  2767.                 ry = y;
  2768.                 rotate(&rx, &ry);
  2769.                 if ((rx >= picFrame.left) && (rx < picFrame.right) &&
  2770.                     (ry >= picFrame.top) && (ry < picFrame.bottom))
  2771.                 {
  2772.                     o = PIXEL_INDEX(rx, ry);
  2773.                     if (glyph->bmap[h * glyph->width + w]) {
  2774.                         red[o] = foreground.red;
  2775.                         green[o] = foreground.green;
  2776.                         blue[o] = foreground.blue;
  2777.                     }
  2778.                 }
  2779.             }
  2780.             y++;
  2781.         }
  2782.         x += glyph->xadd;
  2783.     }
  2784. }
  2785.  
  2786. /* This only does 0, 90, 180 and 270 degree rotations */
  2787.  
  2788. static void rotate(x, y)
  2789. int *x;
  2790. int *y;
  2791. {
  2792.     int tmp;
  2793.  
  2794.     if (ps_rotation >= 315 || ps_rotation <= 45)
  2795.         return;
  2796.  
  2797.     *x -= ps_cent_x;
  2798.     *y -= ps_cent_y;
  2799.  
  2800.     if (ps_rotation > 45 && ps_rotation < 135) {
  2801.         tmp = *x;
  2802.         *x = *y;
  2803.         *y = tmp;
  2804.     }
  2805.     else if (ps_rotation >= 135 && ps_rotation < 225) {
  2806.         *x = -*x;
  2807.     }
  2808.     else if (ps_rotation >= 225 && ps_rotation < 315) {
  2809.         tmp = *x;
  2810.         *x = *y;
  2811.         *y = -tmp;
  2812.     }
  2813.     *x += ps_cent_x;
  2814.     *y += ps_cent_y;
  2815. }
  2816.  
  2817. static void
  2818. skip_poly_or_region(version)
  2819. int version;
  2820. {
  2821.     stage = "skipping polygon or region";
  2822.     skip(read_word() - 2);
  2823. }
  2824.  
  2825. static
  2826. void picComment(type, length)
  2827. word type;
  2828. int length;
  2829. {
  2830.     switch (type) {
  2831.     case 150:
  2832.         if (verbose) pm_message("TextBegin");
  2833.         if (length < 6)
  2834.             break;
  2835.         ps_just = read_byte();
  2836.         ps_flip = read_byte();
  2837.         ps_rotation = read_word();
  2838.         ps_linespace = read_byte();
  2839.         length -= 5;
  2840.         if (recognize_comment)
  2841.             ps_text = 1;
  2842.         ps_cent_set = 0;
  2843.         if (verbose) {
  2844.             pm_message("%s justification, %s flip, %d degree rotation, %d/2 linespacing",
  2845.                 const_name(ps_just_name, ps_just),
  2846.                 const_name(ps_flip_name, ps_flip),
  2847.                 ps_rotation, ps_linespace, 0);
  2848.         }
  2849.         break;
  2850.     case 151:
  2851.         if (verbose) pm_message("TextEnd");
  2852.         ps_text = 0;
  2853.         break;
  2854.     case 152:
  2855.         if (verbose) pm_message("StringBegin");
  2856.         break;
  2857.     case 153:
  2858.         if (verbose) pm_message("StringEnd");
  2859.         break;
  2860.     case 154:
  2861.         if (verbose) pm_message("TextCenter");
  2862.         if (length < 8)
  2863.             break;
  2864.         ps_cent_y = read_word();
  2865.         if (ps_cent_y > 32767)
  2866.             ps_cent_y -= 65536;
  2867.         skip(2); /* ignore fractional part */
  2868.         ps_cent_x = read_word();
  2869.         if (ps_cent_x > 32767)
  2870.             ps_cent_x -= 65536;
  2871.         skip(2); /* ignore fractional part */
  2872.         length -= 8;
  2873.         if (verbose)
  2874.             pm_message("offset %d %d", ps_cent_x, ps_cent_y);
  2875.         break;
  2876.     case 155:
  2877.         if (verbose) pm_message("LineLayoutOff");
  2878.         break;
  2879.     case 156:
  2880.         if (verbose) pm_message("LineLayoutOn");
  2881.         break;
  2882.     case 160:
  2883.         if (verbose) pm_message("PolyBegin");
  2884.         break;
  2885.     case 161:
  2886.         if (verbose) pm_message("PolyEnd");
  2887.         break;
  2888.     case 163:
  2889.         if (verbose) pm_message("PolyIgnore");
  2890.         break;
  2891.     case 164:
  2892.         if (verbose) pm_message("PolySmooth");
  2893.         break;
  2894.     case 165:
  2895.         if (verbose) pm_message("picPlyClo");
  2896.         break;
  2897.     case 180:
  2898.         if (verbose) pm_message("DashedLine");
  2899.         break;
  2900.     case 181:
  2901.         if (verbose) pm_message("DashedStop");
  2902.         break;
  2903.     case 182:
  2904.         if (verbose) pm_message("SetLineWidth");
  2905.         break;
  2906.     case 190:
  2907.         if (verbose) pm_message("PostScriptBegin");
  2908.         break;
  2909.     case 191:
  2910.         if (verbose) pm_message("PostScriptEnd");
  2911.         break;
  2912.     case 192:
  2913.         if (verbose) pm_message("PostScriptHandle");
  2914.         break;
  2915.     case 193:
  2916.         if (verbose) pm_message("PostScriptFile");
  2917.         break;
  2918.     case 194:
  2919.         if (verbose) pm_message("TextIsPostScript");
  2920.         break;
  2921.     case 195:
  2922.         if (verbose) pm_message("ResourcePS");
  2923.         break;
  2924.     case 200:
  2925.         if (verbose) pm_message("RotateBegin");
  2926.         break;
  2927.     case 201:
  2928.         if (verbose) pm_message("RotateEnd");
  2929.         break;
  2930.     case 202:
  2931.         if (verbose) pm_message("RotateCenter");
  2932.         break;
  2933.     case 210:
  2934.         if (verbose) pm_message("FormsPrinting");
  2935.         break;
  2936.     case 211:
  2937.         if (verbose) pm_message("EndFormsPrinting");
  2938.         break;
  2939.     default:
  2940.         if (verbose) pm_message("%d", type);
  2941.         break;
  2942.     }
  2943.     if (length > 0)
  2944.         skip(length);
  2945. }
  2946.  
  2947. static void
  2948. ShortComment(version)
  2949. int version;
  2950. {
  2951.     picComment(read_word(), 0);
  2952. }
  2953.  
  2954. static void
  2955. LongComment(version)
  2956. int version;
  2957. {
  2958.     word type;
  2959.  
  2960.     type = read_word();
  2961.     picComment(type, read_word());
  2962. }
  2963.  
  2964. static int
  2965. rectwidth(r)
  2966. struct Rect* r;
  2967. {
  2968.     return r->right - r->left;
  2969. }
  2970.  
  2971. static int
  2972. rectheight(r)
  2973. struct Rect* r;
  2974. {
  2975.     return r->bottom - r->top;
  2976. }
  2977.  
  2978. static int
  2979. rectequal(r1, r2)
  2980. struct Rect* r1;
  2981. struct Rect* r2;
  2982. {
  2983.     return r1->top == r2->top &&
  2984.            r1->bottom == r2->bottom &&
  2985.            r1->left == r2->left &&
  2986.            r1->right == r2->right;
  2987. }
  2988.  
  2989. static int
  2990. rectsamesize(r1, r2)
  2991. struct Rect* r1;
  2992. struct Rect* r2;
  2993. {
  2994.     return r1->right - r1->left == r2->right - r2->left &&
  2995.            r1->bottom - r1->top == r2->bottom - r2->top ;
  2996. }
  2997.  
  2998. static void
  2999. rectinter(r1, r2, r3)
  3000. struct Rect* r1;
  3001. struct Rect* r2;
  3002. struct Rect* r3;
  3003. {
  3004.     r3->left = max(r1->left, r2->left);
  3005.     r3->top = max(r1->top, r2->top);
  3006.     r3->right = min(r1->right, r2->right);
  3007.     r3->bottom = min(r1->bottom, r2->bottom);
  3008. }
  3009.  
  3010. static void
  3011. rectscale(r, xscale, yscale)
  3012. struct Rect* r;
  3013. double         xscale;
  3014. double         yscale;
  3015. {
  3016.     r->left *= xscale;
  3017.     r->right *= xscale;
  3018.     r->top *= yscale;
  3019.     r->bottom *= yscale;
  3020. }
  3021.  
  3022. static void
  3023. read_rect(r)
  3024. struct Rect* r;
  3025. {
  3026.     r->top = read_word();
  3027.     r->left = read_word();
  3028.     r->bottom = read_word();
  3029.     r->right = read_word();
  3030. }
  3031.  
  3032. static void
  3033. dump_rect(s, r)
  3034. char* s;
  3035. struct Rect* r;
  3036. {
  3037.     pm_message("%s (%d,%d) (%d,%d)",
  3038.         s, r->left, r->top, r->right, r->bottom);
  3039. }
  3040.  
  3041. static char*
  3042. const_name(table, ct)
  3043. struct const_name* table;
  3044. int ct;
  3045. {
  3046.     static char numbuf[32];
  3047.     int i;
  3048.  
  3049.     for (i = 0; table[i].name; i++)
  3050.         if (table[i].value == ct)
  3051.             return table[i].name;
  3052.     
  3053.     sprintf(numbuf, "%d", ct);
  3054.     return numbuf;
  3055. }
  3056.  
  3057. /*
  3058.  * All data in version 2 is 2-byte word aligned.  Odd size data
  3059.  * is padded with a null.
  3060.  */
  3061. static word
  3062. get_op(version)
  3063. int version;
  3064. {
  3065.     if ((align & 1) && version == 2) {
  3066.         stage = "aligning for opcode";
  3067.         read_byte();
  3068.     }
  3069.  
  3070.     stage = "reading opcode";
  3071.  
  3072.     if (version == 1)
  3073.         return read_byte();
  3074.     else
  3075.         return read_word();
  3076. }
  3077.  
  3078. static longword
  3079. read_long()
  3080. {
  3081.     word i;
  3082.  
  3083.     i = read_word();
  3084.     return (i << 16) | read_word();
  3085. }
  3086.  
  3087. static word
  3088. read_word()
  3089. {
  3090.     byte b;
  3091.  
  3092.     b = read_byte();
  3093.  
  3094.     return (b << 8) | read_byte();
  3095. }
  3096.  
  3097. static byte
  3098. read_byte()
  3099. {
  3100.     int c;
  3101.  
  3102.     if ((c = fgetc(ifp)) == EOF)
  3103.         pm_error("EOF / read error while %s", stage);
  3104.  
  3105.     ++align;
  3106.     return c & 255;
  3107. }
  3108.  
  3109. static signed_byte
  3110. read_signed_byte()
  3111. {
  3112.     return (signed_byte)read_byte();
  3113. }
  3114.  
  3115. static void
  3116. skip(n)
  3117. int n;
  3118. {
  3119.     static byte buf[1024];
  3120.  
  3121.     align += n;
  3122.  
  3123.     for (; n > 0; n -= 1024)
  3124.         if (fread(buf, n > 1024 ? 1024 : n, 1, ifp) != 1)
  3125.             pm_error("EOF / read error while %s", stage);
  3126. }
  3127.  
  3128. static void
  3129. read_n(n, buf)
  3130. int n;
  3131. char* buf;
  3132. {
  3133.     align += n;
  3134.  
  3135.     if (fread(buf, n, 1, ifp) != 1)
  3136.         pm_error("EOF / read error while %s", stage);
  3137. }
  3138.  
  3139. #ifdef STANDALONE
  3140.  
  3141. /* glue routines if you don't have PBM+ handy; these are only good enough
  3142.  * for picttoppm's purposes!
  3143.  */
  3144.  
  3145. static char* outfile;
  3146.  
  3147. void pm_message(fmt, p1, p2, p3, p4, p5)
  3148. char* fmt;
  3149. int p1, p2, p3, p4, p5;
  3150. {
  3151.     fprintf(stderr, "picttoppm: ");
  3152.     fprintf(stderr, fmt, p1, p2, p3, p4, p5);
  3153.     fprintf(stderr, "\n");
  3154. }
  3155.  
  3156. void pm_error(fmt, p1, p2, p3, p4, p5)
  3157. char* fmt;
  3158. int p1, p2, p3, p4, p5;
  3159. {
  3160.     pm_message(fmt, p1, p2, p3, p4, p5);
  3161.     exit(1);
  3162. }
  3163.  
  3164. int pm_keymatch(arg, opt, minlen)
  3165. char* arg, *opt;
  3166. int minlen;
  3167. {
  3168.     for (; *arg && *arg == *opt; arg++, opt++)
  3169.         minlen--;
  3170.     return !*arg && minlen <= 0;
  3171. }
  3172.  
  3173. void ppm_init(argc, argv)
  3174. int* argc;
  3175. char** argv;
  3176. {
  3177.     outfile = "standard output";
  3178. }
  3179.  
  3180. FILE* pm_openr(file)
  3181. char* file;
  3182. {
  3183.     FILE* fp;
  3184.  
  3185.     if (!(fp = fopen(file, "rb"))) {
  3186.         fprintf(stderr, "picttoppm: can't read file %s\n", file);
  3187.         exit(1);
  3188.     }
  3189.     outfile = file;
  3190.     return fp;
  3191. }
  3192.  
  3193. void writerr()
  3194. {
  3195.     fprintf(stderr, "picttoppm: write error on %s\n", outfile);
  3196.     exit(1);
  3197. }
  3198.  
  3199. void pm_usage(u)
  3200. char* u;
  3201. {
  3202.     fprintf(stderr, "usage: picttoppm %s\n", u);
  3203.     exit(1);
  3204. }
  3205.  
  3206. void ppm_writeppminit(fp, width, height, maxval, forceplain)
  3207. FILE* fp;
  3208. int width, height, maxval, forceplain;
  3209. {
  3210.     if (fprintf(fp, "P6\n%d %d\n%d\n", width, height, maxval) == EOF)
  3211.         writerr();
  3212. }
  3213.  
  3214. pixel* ppm_allocrow(width)
  3215. int width;
  3216. {
  3217.     pixel* r;
  3218.     
  3219.     if (!(r = (pixel*)malloc(width * sizeof(pixel)))) {
  3220.         fprintf(stderr, "picttoppm: out of memory\n");
  3221.         exit(1);
  3222.     }
  3223.     return r;
  3224. }
  3225.  
  3226. void ppm_writeppmrow(fp, row, width, maxval, forceplain)
  3227. FILE* fp;
  3228. pixel* row;
  3229. int width, maxval, forceplain;
  3230. {
  3231.     while (width--) {
  3232.         if (fputc(row->r, fp) == EOF) writerr();
  3233.         if (fputc(row->g, fp) == EOF) writerr();
  3234.         if (fputc(row->b, fp) == EOF) writerr();
  3235.         row++;
  3236.     }
  3237. }
  3238.  
  3239. void pm_close(fp)
  3240. FILE* fp;
  3241. {
  3242.     if (fclose(fp) == EOF)
  3243.         writerr();
  3244. }
  3245.  
  3246. #endif /* STANDALONE */
  3247.  
  3248. /* Some font searching routines */
  3249.  
  3250. struct fontinfo {
  3251.     int font;
  3252.     int size;
  3253.     int style;
  3254.     char* filename;
  3255.     struct font* loaded;
  3256.     struct fontinfo* next;
  3257. };
  3258.  
  3259. static struct fontinfo* fontlist = 0;
  3260. static struct fontinfo** fontlist_ins = &fontlist;
  3261.  
  3262. int load_fontdir(dirfile)
  3263. char* dirfile;
  3264. {
  3265.     FILE* fp;
  3266.     int n, nfont;
  3267.     char* arg[5], line[1024];
  3268.     struct fontinfo* fontinfo;
  3269.  
  3270.     if (!(fp = fopen(dirfile, "r")))
  3271.         return -1;
  3272.     
  3273.     nfont = 0;
  3274.     while (fgets(line, 1024, fp)) {
  3275.         if ((n = mk_argvn(line, arg, 5)) == 0 || arg[0][0] == '#')
  3276.             continue;
  3277.         if (n != 4)
  3278.             continue;
  3279.         if (!(fontinfo = (struct fontinfo*)malloc(sizeof(struct fontinfo))) ||
  3280.             !(fontinfo->filename = (char*)malloc(strlen(arg[3]) + 1)))
  3281.         {
  3282.             pm_error("out of memory for font information");
  3283.         }
  3284.  
  3285.         fontinfo->font = atoi(arg[0]);
  3286.         fontinfo->size = atoi(arg[1]);
  3287.         fontinfo->style = atoi(arg[2]);
  3288.         strcpy(fontinfo->filename, arg[3]);
  3289.         fontinfo->loaded = 0;
  3290.  
  3291.         fontinfo->next = 0;
  3292.         *fontlist_ins = fontinfo;
  3293.         fontlist_ins = &fontinfo->next;
  3294.         nfont++;
  3295.     }
  3296.  
  3297.     return nfont;
  3298. }
  3299.  
  3300. static int abs_value(x)
  3301. int x;
  3302. {
  3303.     if (x < 0)
  3304.         return -x;
  3305.     else
  3306.         return x;
  3307. }
  3308.  
  3309. static struct font* get_font(font, size, style)
  3310. int font;
  3311. int size;
  3312. int style;
  3313. {
  3314.     int closeness, bestcloseness;
  3315.     struct fontinfo* fi, *best;
  3316.  
  3317.     best = 0;
  3318.     for (fi = fontlist; fi; fi = fi->next) {
  3319.         closeness = abs_value(fi->font - font) * 10000 +
  3320.             abs_value(fi->size - size) * 100 +
  3321.             abs_value(fi->style - style);
  3322.         if (!best || closeness < bestcloseness) {
  3323.             best = fi;
  3324.             bestcloseness = closeness;
  3325.         }
  3326.     }
  3327.  
  3328.     if (best) {
  3329.         if (best->loaded)
  3330.             return best->loaded;
  3331.  
  3332.         if (best->loaded = pbm_loadbdffont(best->filename))
  3333.             return best->loaded;
  3334.     }
  3335.  
  3336.     /* It would be better to go looking for the nth best font, really */
  3337.     return 0;
  3338. }
  3339.  
  3340. #ifdef VMS
  3341. unlink(p)
  3342.      char *p;
  3343. {delete(p);}
  3344. #endif
  3345.