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