home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / netpbma.zip / ppm / picttoppm.c < prev    next >
C/C++ Source or Header  |  1996-11-10  |  103KB  |  3,344 lines

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