home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-12-07 | 73.4 KB | 3,337 lines |
- /*
- * picttoppm.c -- convert a MacIntosh PICT file to PPM format.
- *
- * This program is normally part of the PBM+ utilities, but you
- * can compile a slightly crippled version without PBM+ by
- * defining STANDALONE (e.g., cc -DSTANDALONE picttoppm.c).
- * However, if you want this you probably want PBM+ sooner or
- * later so grab it now.
- *
- * Copyright 1989,1992,1993 George Phillips
- *
- * Permission is granted to freely distribute this program in whole or in
- * part provided you don't make money off it, you don't pretend that you
- * wrote it and that this notice accompanies the code.
- *
- * George Phillips <phillips@cs.ubc.ca>
- * Department of Computer Science
- * University of British Columbia
- *
- * $Id: picttoppm.c,v 1.7 1993/10/26 22:40:31 phillips Exp phillips $
- */
-
- #ifdef STANDALONE
-
- #include <stdio.h>
- #ifdef __STDC__
- #define ARGS(x) x
- #else
- #define ARGS(x) ()
- #endif /* __STDC__ */
- #define PPM_ASSIGN(p, R, G, B) (p).r = R; (p).g = G; (p).b = B
- #define max(x, y) ((x) > (y) ? (x) : (y))
- #define min(x, y) ((x) < (y) ? (x) : (y))
- typedef unsigned char pixval;
- typedef struct { pixval r, g, b; } pixel;
- void ppm_init();
- FILE* pm_openr();
- void pm_usage();
- void pm_message();
- void pm_error();
- int pm_keymatch();
- void ppm_writeppminit();
- void ppm_writeppmrow();
- void pm_close();
- pixel* ppm_allocrow();
-
- #else
-
- #include "ppm.h"
-
- #endif /* STANDALONE */
-
- #include "pbmfont.h"
-
- /*
- * Typical byte, 2 byte and 4 byte integers.
- */
- typedef unsigned char byte;
- typedef char signed_byte; /* XXX */
- typedef unsigned short word;
- typedef unsigned long longword;
-
- /*
- * Data structures for QuickDraw (and hence PICT) stuff.
- */
-
- struct Rect {
- word top;
- word left;
- word bottom;
- word right;
- };
-
- struct pixMap {
- struct Rect Bounds;
- word version;
- word packType;
- longword packSize;
- longword hRes;
- longword vRes;
- word pixelType;
- word pixelSize;
- word cmpCount;
- word cmpSize;
- longword planeBytes;
- longword pmTable;
- longword pmReserved;
- };
-
- struct RGBColour {
- word red;
- word green;
- word blue;
- };
-
- struct Point {
- word x;
- word y;
- };
-
- struct Pattern {
- byte pix[64];
- };
-
- typedef void (*transfer_func) ARGS(( struct RGBColour* src, struct RGBColour* dst ));
-
- static char* stage;
- static struct Rect picFrame;
- static word* red;
- static word* green;
- static word* blue;
- static word rowlen;
- static word collen;
- static longword planelen;
- static int verbose;
- static int fullres;
- static int recognize_comment;
-
- static struct RGBColour black = { 0, 0, 0 };
- static struct RGBColour white = { 0xffff, 0xffff, 0xffff };
-
- /* various bits of drawing state */
- static struct RGBColour foreground = { 0, 0, 0 };
- static struct RGBColour background = { 0xffff, 0xffff, 0xffff };
- static struct RGBColour op_colour;
- static struct Pattern bkpat;
- static struct Pattern fillpat;
- static struct Rect clip_rect;
- static struct Rect cur_rect;
- static struct Point current;
- static struct Pattern pen_pat;
- static word pen_width;
- static word pen_height;
- static word pen_mode;
- static transfer_func pen_trf;
- static word text_font;
- static byte text_face;
- static word text_mode;
- static transfer_func text_trf;
- static word text_size;
- static struct font* tfont;
-
- /* state for magic printer comments */
- static int ps_text;
- static byte ps_just;
- static byte ps_flip;
- static word ps_rotation;
- static byte ps_linespace;
- static int ps_cent_x;
- static int ps_cent_y;
- static int ps_cent_set;
-
- struct opdef {
- char* name;
- int len;
- void (*impl) ARGS((int));
- char* description;
- };
-
- struct blit_info {
- struct Rect srcRect;
- struct Rect srcBounds;
- int srcwid;
- byte* srcplane;
- int pixSize;
- struct Rect dstRect;
- struct RGBColour* colour_map;
- int mode;
- struct blit_info* next;
- };
-
- static struct blit_info* blit_list = 0;
- static struct blit_info** last_bl = &blit_list;
-
- #define WORD_LEN (-1)
-
- static void interpret_pict ARGS(( void ));
- static void alloc_planes ARGS(( void ));
- static void compact_plane ARGS(( word* plane, int planelen ));
- static void output_ppm ARGS(( int version ));
- static void Opcode_9A ARGS(( int version ));
- static void BitsRect ARGS(( int version ));
- static void BitsRegion ARGS(( int version ));
- static void do_bitmap ARGS(( int version, int rowBytes, int is_region ));
- static void do_pixmap ARGS(( int version, word rowBytes, int is_region ));
- static transfer_func transfer ARGS(( int ));
- static void draw_pixel ARGS (( int, int, struct RGBColour*, transfer_func ));
- static int blit ARGS((
- struct Rect* srcRect, struct Rect* srcBounds, int srcwid, byte* srcplane,
- int pixSize, struct Rect* dstRect, struct Rect* dstBounds, int dstwid,
- struct RGBColour* colour_map, int mode ));
- static struct blit_info* add_blit_list ARGS(( void ));
- static void do_blits ARGS(( void ));
- static byte* unpackbits ARGS(( struct Rect* bounds, word rowBytes, int pixelSize ));
- static byte* expand_buf ARGS(( byte* buf, int* len, int bits_per_pixel ));
- static void Clip ARGS(( int version ));
- static void read_pixmap ARGS(( struct pixMap* p, word* rowBytes ));
- static struct RGBColour* read_colour_table ARGS(( void ));
- static void BkPixPat ARGS(( int version ));
- static void PnPixPat ARGS(( int version ));
- static void FillPixPat ARGS(( int version ));
- static void read_pattern ARGS(( void ));
- static void read_8x8_pattern ARGS(( struct Pattern* ));
- static void BkPat ARGS(( int version ));
- static void PnPat ARGS(( int version ));
- static void FillPat ARGS(( int version ));
- static void PnSize ARGS(( int version ));
- static void PnMode ARGS(( int version ));
- static void OpColor ARGS(( int version ));
- static void RGBFgCol ARGS(( int version ));
- static void RGBBkCol ARGS(( int version ));
-
- static void Line ARGS(( int version ));
- static void LineFrom ARGS(( int version ));
- static void ShortLine ARGS(( int version ));
- static void ShortLineFrom ARGS(( int version ));
-
- static void PnLocHFrac ARGS(( int version ));
- static void TxFont ARGS(( int version ));
- static void TxFace ARGS(( int version ));
- static void TxMode ARGS(( int version ));
- static void TxSize ARGS(( int version ));
- static void skip_text ARGS(( void ));
- static void LongText ARGS(( int version ));
- static void DHText ARGS(( int version ));
- static void DVText ARGS(( int version ));
- static void DHDVText ARGS(( int version ));
- static void do_text ARGS(( word x, word y ));
- static void do_ps_text ARGS(( word x, word y ));
- static void rotate ARGS(( int* x, int* y));
- static void skip_poly_or_region ARGS(( int version ));
- static void LongComment ARGS(( int version ));
- static void ShortComment ARGS(( int version ));
-
- static int rectwidth ARGS(( struct Rect* r ));
- static int rectheight ARGS(( struct Rect* r ));
- static int rectsamesize ARGS(( struct Rect* r1, struct Rect* r2 ));
- static void rectinter ARGS(( struct Rect* r1, struct Rect* r2, struct Rect* r3 ));
- static void rectscale ARGS(( struct Rect* r, double xscale, double yscale ));
-
- static void read_rect ARGS(( struct Rect* r ));
- static void dump_rect ARGS(( char* s, struct Rect* r ));
-
- static void do_paintRect ARGS(( struct Rect* r ));
- static void paintRect ARGS(( int version ));
- static void paintSameRect ARGS(( int version ));
- static void do_frameRect ARGS(( struct Rect* r ));
- static void frameRect ARGS(( int version ));
- static void frameSameRect ARGS(( int version ));
- static void paintPoly ARGS(( int version ));
-
- static word get_op ARGS(( int version ));
-
- static longword read_long ARGS(( void ));
- static word read_word ARGS(( void ));
- static byte read_byte ARGS(( void ));
- static signed_byte read_signed_byte ARGS(( void ));
-
- static void skip ARGS(( int n ));
- static void read_n ARGS(( int n, char* buf ));
-
- static struct font* get_font ARGS(( int font, int size, int style ));
-
- static int load_fontdir ARGS((char *file));
- static void read_rgb ARGS((struct RGBColour *rgb));
- static void draw_pen_rect ARGS((struct Rect *r));
- static void draw_pen ARGS((int x, int y));
- static void read_point ARGS((struct Point *p));
- static void read_short_point ARGS((struct Point *p));
- static void scan_line ARGS((short x1, short y1, short x2, short y2));
- static void scan_poly ARGS((int np, struct Point pts[]));
- static void poly_sort ARGS((int sort_index, struct Point points[]));
- static void picComment ARGS((word type, int length));
- static int abs_value ARGS((int x));
- /*
- * a table of the first 194(?) opcodes. The table is too empty.
- *
- * Probably could use an entry specifying if the opcode is valid in version
- * 1, etc.
- */
-
- /* for reserved opcodes of known length */
- #define res(length) \
- { "reserved", (length), NULL, "reserved for Apple use" }
-
- /* for reserved opcodes of length determined by a function */
- #define resf(skipfunction) \
- { "reserved", NA, (skipfunction), "reserved for Apple use" }
-
- /* seems like RGB colours are 6 bytes, but Apple says they're variable */
- /* I'll use 6 for now as I don't care that much. */
- #define RGB_LEN (6)
-
- #define NA (0)
-
- static struct opdef optable[] = {
- /* 0x00 */ { "NOP", 0, NULL, "nop" },
- /* 0x01 */ { "Clip", NA, Clip, "clip" },
- /* 0x02 */ { "BkPat", 8, BkPat, "background pattern" },
- /* 0x03 */ { "TxFont", 2, TxFont, "text font (word)" },
- /* 0x04 */ { "TxFace", 1, TxFace, "text face (byte)" },
- /* 0x05 */ { "TxMode", 2, TxMode, "text mode (word)" },
- /* 0x06 */ { "SpExtra", 4, NULL, "space extra (fixed point)" },
- /* 0x07 */ { "PnSize", 4, PnSize, "pen size (point)" },
- /* 0x08 */ { "PnMode", 2, PnMode, "pen mode (word)" },
- /* 0x09 */ { "PnPat", 8, PnPat, "pen pattern" },
- /* 0x0a */ { "FillPat", 8, FillPat, "fill pattern" },
- /* 0x0b */ { "OvSize", 4, NULL, "oval size (point)" },
- /* 0x0c */ { "Origin", 4, NULL, "dh, dv (word)" },
- /* 0x0d */ { "TxSize", 2, TxSize, "text size (word)" },
- /* 0x0e */ { "FgColor", 4, NULL, "foreground color (longword)" },
- /* 0x0f */ { "BkColor", 4, NULL, "background color (longword)" },
- /* 0x10 */ { "TxRatio", 8, NULL, "numerator (point), denominator (point)" },
- /* 0x11 */ { "Version", 1, NULL, "version (byte)" },
- /* 0x12 */ { "BkPixPat", NA, BkPixPat, "color background pattern" },
- /* 0x13 */ { "PnPixPat", NA, PnPixPat, "color pen pattern" },
- /* 0x14 */ { "FillPixPat", NA, FillPixPat, "color fill pattern" },
- /* 0x15 */ { "PnLocHFrac", 2, PnLocHFrac, "fractional pen position" },
- /* 0x16 */ { "ChExtra", 2, NULL, "extra for each character" },
- /* 0x17 */ res(0),
- /* 0x18 */ res(0),
- /* 0x19 */ res(0),
- /* 0x1a */ { "RGBFgCol", RGB_LEN, RGBFgCol, "RGB foreColor" },
- /* 0x1b */ { "RGBBkCol", RGB_LEN, RGBBkCol, "RGB backColor" },
- /* 0x1c */ { "HiliteMode", 0, NULL, "hilite mode flag" },
- /* 0x1d */ { "HiliteColor", RGB_LEN, NULL, "RGB hilite color" },
- /* 0x1e */ { "DefHilite", 0, NULL, "Use default hilite color" },
- /* 0x1f */ { "OpColor", NA, OpColor, "RGB OpColor for arithmetic modes" },
- /* 0x20 */ { "Line", 8, Line, "pnLoc (point), newPt (point)" },
- /* 0x21 */ { "LineFrom", 4, LineFrom, "newPt (point)" },
- /* 0x22 */ { "ShortLine", 6, ShortLine, "pnLoc (point, dh, dv (-128 .. 127))" },
- /* 0x23 */ { "ShortLineFrom", 2, ShortLineFrom, "dh, dv (-128 .. 127)" },
- /* 0x24 */ res(WORD_LEN),
- /* 0x25 */ res(WORD_LEN),
- /* 0x26 */ res(WORD_LEN),
- /* 0x27 */ res(WORD_LEN),
- /* 0x28 */ { "LongText", NA, LongText, "txLoc (point), count (0..255), text" },
- /* 0x29 */ { "DHText", NA, DHText, "dh (0..255), count (0..255), text" },
- /* 0x2a */ { "DVText", NA, DVText, "dv (0..255), count (0..255), text" },
- /* 0x2b */ { "DHDVText", NA, DHDVText, "dh, dv (0..255), count (0..255), text" },
- /* 0x2c */ res(WORD_LEN),
- /* 0x2d */ res(WORD_LEN),
- /* 0x2e */ res(WORD_LEN),
- /* 0x2f */ res(WORD_LEN),
- /* 0x30 */ { "frameRect", 8, frameRect, "rect" },
- /* 0x31 */ { "paintRect", 8, paintRect, "rect" },
- /* 0x32 */ { "eraseRect", 8, NULL, "rect" },
- /* 0x33 */ { "invertRect", 8, NULL, "rect" },
- /* 0x34 */ { "fillRect", 8, NULL, "rect" },
- /* 0x35 */ res(8),
- /* 0x36 */ res(8),
- /* 0x37 */ res(8),
- /* 0x38 */ { "frameSameRect", 0, frameSameRect, "rect" },
- /* 0x39 */ { "paintSameRect", 0, paintSameRect, "rect" },
- /* 0x3a */ { "eraseSameRect", 0, NULL, "rect" },
- /* 0x3b */ { "invertSameRect", 0, NULL, "rect" },
- /* 0x3c */ { "fillSameRect", 0, NULL, "rect" },
- /* 0x3d */ res(0),
- /* 0x3e */ res(0),
- /* 0x3f */ res(0),
- /* 0x40 */ { "frameRRect", 8, NULL, "rect" },
- /* 0x41 */ { "paintRRect", 8, NULL, "rect" },
- /* 0x42 */ { "eraseRRect", 8, NULL, "rect" },
- /* 0x43 */ { "invertRRect", 8, NULL, "rect" },
- /* 0x44 */ { "fillRRrect", 8, NULL, "rect" },
- /* 0x45 */ res(8),
- /* 0x46 */ res(8),
- /* 0x47 */ res(8),
- /* 0x48 */ { "frameSameRRect", 0, NULL, "rect" },
- /* 0x49 */ { "paintSameRRect", 0, NULL, "rect" },
- /* 0x4a */ { "eraseSameRRect", 0, NULL, "rect" },
- /* 0x4b */ { "invertSameRRect", 0, NULL, "rect" },
- /* 0x4c */ { "fillSameRRect", 0, NULL, "rect" },
- /* 0x4d */ res(0),
- /* 0x4e */ res(0),
- /* 0x4f */ res(0),
- /* 0x50 */ { "frameOval", 8, NULL, "rect" },
- /* 0x51 */ { "paintOval", 8, NULL, "rect" },
- /* 0x52 */ { "eraseOval", 8, NULL, "rect" },
- /* 0x53 */ { "invertOval", 8, NULL, "rect" },
- /* 0x54 */ { "fillOval", 8, NULL, "rect" },
- /* 0x55 */ res(8),
- /* 0x56 */ res(8),
- /* 0x57 */ res(8),
- /* 0x58 */ { "frameSameOval", 0, NULL, "rect" },
- /* 0x59 */ { "paintSameOval", 0, NULL, "rect" },
- /* 0x5a */ { "eraseSameOval", 0, NULL, "rect" },
- /* 0x5b */ { "invertSameOval", 0, NULL, "rect" },
- /* 0x5c */ { "fillSameOval", 0, NULL, "rect" },
- /* 0x5d */ res(0),
- /* 0x5e */ res(0),
- /* 0x5f */ res(0),
- /* 0x60 */ { "frameArc", 12, NULL, "rect, startAngle, arcAngle" },
- /* 0x61 */ { "paintArc", 12, NULL, "rect, startAngle, arcAngle" },
- /* 0x62 */ { "eraseArc", 12, NULL, "rect, startAngle, arcAngle" },
- /* 0x63 */ { "invertArc", 12, NULL, "rect, startAngle, arcAngle" },
- /* 0x64 */ { "fillArc", 12, NULL, "rect, startAngle, arcAngle" },
- /* 0x65 */ res(12),
- /* 0x66 */ res(12),
- /* 0x67 */ res(12),
- /* 0x68 */ { "frameSameArc", 4, NULL, "rect, startAngle, arcAngle" },
- /* 0x69 */ { "paintSameArc", 4, NULL, "rect, startAngle, arcAngle" },
- /* 0x6a */ { "eraseSameArc", 4, NULL, "rect, startAngle, arcAngle" },
- /* 0x6b */ { "invertSameArc", 4, NULL, "rect, startAngle, arcAngle" },
- /* 0x6c */ { "fillSameArc", 4, NULL, "rect, startAngle, arcAngle" },
- /* 0x6d */ res(4),
- /* 0x6e */ res(4),
- /* 0x6f */ res(4),
- /* 0x70 */ { "framePoly", NA, skip_poly_or_region, "poly" },
- /* 0x71 */ { "paintPoly", NA, paintPoly, "poly" },
- /* 0x72 */ { "erasePoly", NA, skip_poly_or_region, "poly" },
- /* 0x73 */ { "invertPoly", NA, skip_poly_or_region, "poly" },
- /* 0x74 */ { "fillPoly", NA, skip_poly_or_region, "poly" },
- /* 0x75 */ resf(skip_poly_or_region),
- /* 0x76 */ resf(skip_poly_or_region),
- /* 0x77 */ resf(skip_poly_or_region),
- /* 0x78 */ { "frameSamePoly", 0, NULL, "poly (NYI)" },
- /* 0x79 */ { "paintSamePoly", 0, NULL, "poly (NYI)" },
- /* 0x7a */ { "eraseSamePoly", 0, NULL, "poly (NYI)" },
- /* 0x7b */ { "invertSamePoly", 0, NULL, "poly (NYI)" },
- /* 0x7c */ { "fillSamePoly", 0, NULL, "poly (NYI)" },
- /* 0x7d */ res(0),
- /* 0x7e */ res(0),
- /* 0x7f */ res(0),
- /* 0x80 */ { "frameRgn", NA, skip_poly_or_region, "region" },
- /* 0x81 */ { "paintRgn", NA, skip_poly_or_region, "region" },
- /* 0x82 */ { "eraseRgn", NA, skip_poly_or_region, "region" },
- /* 0x83 */ { "invertRgn", NA, skip_poly_or_region, "region" },
- /* 0x84 */ { "fillRgn", NA, skip_poly_or_region, "region" },
- /* 0x85 */ resf(skip_poly_or_region),
- /* 0x86 */ resf(skip_poly_or_region),
- /* 0x87 */ resf(skip_poly_or_region),
- /* 0x88 */ { "frameSameRgn", 0, NULL, "region (NYI)" },
- /* 0x89 */ { "paintSameRgn", 0, NULL, "region (NYI)" },
- /* 0x8a */ { "eraseSameRgn", 0, NULL, "region (NYI)" },
- /* 0x8b */ { "invertSameRgn", 0, NULL, "region (NYI)" },
- /* 0x8c */ { "fillSameRgn", 0, NULL, "region (NYI)" },
- /* 0x8d */ res(0),
- /* 0x8e */ res(0),
- /* 0x8f */ res(0),
- /* 0x90 */ { "BitsRect", NA, BitsRect, "copybits, rect clipped" },
- /* 0x91 */ { "BitsRgn", NA, BitsRegion, "copybits, rgn clipped" },
- /* 0x92 */ res(WORD_LEN),
- /* 0x93 */ res(WORD_LEN),
- /* 0x94 */ res(WORD_LEN),
- /* 0x95 */ res(WORD_LEN),
- /* 0x96 */ res(WORD_LEN),
- /* 0x97 */ res(WORD_LEN),
- /* 0x98 */ { "PackBitsRect", NA, BitsRect, "packed copybits, rect clipped" },
- /* 0x99 */ { "PackBitsRgn", NA, BitsRegion, "packed copybits, rgn clipped" },
- /* 0x9a */ { "Opcode_9A", NA, Opcode_9A, "the mysterious opcode 9A" },
- /* 0x9b */ res(WORD_LEN),
- /* 0x9c */ res(WORD_LEN),
- /* 0x9d */ res(WORD_LEN),
- /* 0x9e */ res(WORD_LEN),
- /* 0x9f */ res(WORD_LEN),
- /* 0xa0 */ { "ShortComment", 2, ShortComment, "kind (word)" },
- /* 0xa1 */ { "LongComment", NA, LongComment, "kind (word), size (word), data" }
- };
-
- struct const_name {
- int value;
- char* name;
- };
-
- static char* const_name ARGS(( struct const_name* table, int ct));
-
- struct const_name transfer_name[] = {
- { 0, "srcCopy" },
- { 1, "srcOr" },
- { 2, "srcXor" },
- { 3, "srcBic" },
- { 4, "notSrcCopy" },
- { 5, "notSrcOr" },
- { 6, "notSrcXor" },
- { 7, "notSrcBic" },
- { 32, "blend" },
- { 33, "addPin" },
- { 34, "addOver" },
- { 35, "subPin" },
- { 36, "transparent" },
- { 37, "adMax" },
- { 38, "subOver" },
- { 39, "adMin" },
- { -1, 0 }
- };
-
- struct const_name font_name[] = {
- { 0, "systemFont" },
- { 1, "applFont" },
- { 2, "newYork" },
- { 3, "geneva" },
- { 4, "monaco" },
- { 5, "venice" },
- { 6, "london" },
- { 7, "athens" },
- { 8, "sanFran" },
- { 9, "toronto" },
- { 11, "cairo" },
- { 12, "losAngeles" },
- { 20, "times" },
- { 21, "helvetica" },
- { 22, "courier" },
- { 23, "symbol" },
- { 24, "taliesin" },
- { -1, 0 }
- };
-
- struct const_name ps_just_name[] = {
- { 0, "no" },
- { 1, "left" },
- { 2, "center" },
- { 3, "right" },
- { 4, "full" },
- { -1, 0 }
- };
-
- struct const_name ps_flip_name[] = {
- { 0, "no" },
- { 1, "horizontal" },
- { 2, "vertical" },
- { -1, 0 }
- };
-
- #define FNT_BOLD (1)
- #define FNT_ITALIC (2)
- #define FNT_ULINE (4)
- #define FNT_OUTLINE (8)
- #define FNT_SHADOW (16)
- #define FNT_CONDENSE (32)
- #define FNT_EXTEND (64)
-
- static int align = 0;
- static FILE* ifp;
-
- int
- main(argc, argv)
- int argc;
- char* argv[];
- {
- int argn;
- int header;
- char* usage =
- "[-verbose] [-fullres] [-noheader] [-quickdraw] [-fontdir file] [pictfile]";
-
- ppm_init( &argc, argv );
-
- argn = 1;
- verbose = 0;
- fullres = 0;
- header = 1;
- recognize_comment = 1;
-
- while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
- if (pm_keymatch(argv[argn], "-verbose", 2))
- verbose++;
- else if (pm_keymatch(argv[argn], "-fullres", 3))
- fullres = 1;
- else if (pm_keymatch(argv[argn], "-noheader", 2))
- header = 0;
- else if (pm_keymatch(argv[argn], "-quickdraw", 2))
- recognize_comment = 0;
- else if (pm_keymatch(argv[argn], "-fontdir", 3)) {
- argn++;
- if (!argv[argn])
- pm_usage(usage);
- else
- load_fontdir(argv[argn]);
- }
- else
- pm_usage(usage);
- ++argn;
- }
-
- if (load_fontdir("fontdir") < 0)
- pm_message("warning: can't load font directory 'fontdir'\n", 0,0,0,0);
-
- if (argn < argc) {
- ifp = pm_openr(argv[argn]);
- ++argn;
- } else
- ifp = stdin;
-
- if (argn != argc)
- pm_usage(usage);
-
- if (header) {
- stage = "Reading 512 byte header";
- skip(512);
- }
-
- interpret_pict();
- exit(0);
- }
-
- static void
- interpret_pict()
- {
- byte ch;
- word picSize;
- word opcode;
- word len;
- int version;
- int i;
-
- for (i = 0; i < 64; i++)
- pen_pat.pix[i] = bkpat.pix[i] = fillpat.pix[i] = 1;
- pen_width = pen_height = 1;
- pen_mode = 0; /* srcCopy */
- pen_trf = transfer(pen_mode);
- text_mode = 0; /* srcCopy */
- text_trf = transfer(text_mode);
-
- stage = "Reading picture size";
- picSize = read_word();
-
- if (verbose)
- pm_message("picture size = %d (0x%x)", picSize, picSize, 0, 0, 0);
-
- stage = "reading picture frame";
- read_rect(&picFrame);
-
- if (verbose) {
- dump_rect("Picture frame:", &picFrame);
- pm_message("Picture size is %d x %d",
- picFrame.right - picFrame.left,
- picFrame.bottom - picFrame.top, 0, 0, 0);
- }
-
- if (!fullres)
- alloc_planes();
-
- while ((ch = read_byte()) == 0)
- ;
- if (ch != 0x11)
- pm_error("No version number");
-
- switch (read_byte()) {
- case 1:
- version = 1;
- break;
- case 2:
- if (read_byte() != 0xff)
- pm_error("can only do version 2, subcode 0xff");
- version = 2;
- break;
- default:
- pm_error("Unknown version");
- }
-
- if (verbose)
- pm_message("PICT version %d", version, 0, 0, 0, 0);
-
- while((opcode = get_op(version)) != 0xff) {
- if (opcode < 0xa2) {
- if (verbose) {
- stage = optable[opcode].name;
- if (!strcmp(stage, "reserved"))
- pm_message("reserved opcode=0x%x", opcode, 0, 0, 0, 0);
- else
- pm_message("%s", stage = optable[opcode].name, 0, 0, 0, 0);
- }
-
- if (optable[opcode].impl != NULL)
- (*optable[opcode].impl)(version);
- else if (optable[opcode].len >= 0)
- skip(optable[opcode].len);
- else switch (optable[opcode].len) {
- case WORD_LEN:
- len = read_word();
- skip(len);
- break;
- default:
- pm_error("can't do length of %d",
- optable[opcode].len);
- }
- }
- else if (opcode == 0xc00) {
- if (verbose)
- pm_message("HeaderOp", 0, 0, 0, 0, 0);
- stage = "HeaderOp";
- skip(24);
- }
- else if (opcode >= 0xa2 && opcode <= 0xaf) {
- stage = "skipping reserved";
- if (verbose)
- pm_message("%s 0x%x", stage, opcode, 0, 0, 0);
- skip(read_word());
- }
- else if (opcode >= 0xb0 && opcode <= 0xcf) {
- /* just a reserved opcode, no data */
- if (verbose)
- pm_message("reserved 0x%x", opcode, 0, 0, 0);
- }
- else if (opcode >= 0xd0 && opcode <= 0xfe) {
- stage = "skipping reserved";
- if (verbose)
- pm_message("%s 0x%x", stage, opcode, 0, 0, 0);
- skip(read_long());
- }
- else if (opcode >= 0x100 && opcode <= 0x7fff) {
- stage = "skipping reserved";
- if (verbose)
- pm_message("%s 0x%x", stage, opcode, 0, 0, 0);
- skip((opcode >> 7) & 255);
- }
- else if (opcode >= 0x8000 && opcode <= 0x80ff) {
- /* just a reserved opcode */
- if (verbose)
- pm_message("reserved 0x%x", opcode, 0, 0, 0, 0);
- }
- else if (opcode >= 8100 && opcode <= 0xffff) {
- stage = "skipping reserved";
- if (verbose)
- pm_message("%s 0x%x", stage, opcode, 0, 0, 0);
- skip(read_long());
- }
- else
- pm_error("can't handle opcode of %x", opcode);
- }
- output_ppm(version);
- }
-
- /* allocation is same for version 1 or version 2. We are super-duper
- * wasteful of memory for version 1 picts. Someday, we'll separate
- * things and only allocate a byte per pixel for version 1 (or heck,
- * even only a bit, but that would require even more extra work).
- */
-
- static void alloc_planes()
- {
- rowlen = picFrame.right - picFrame.left;
- collen = picFrame.bottom - picFrame.top;
-
- clip_rect.top = picFrame.top;
- clip_rect.left = picFrame.left;
- clip_rect.bottom = picFrame.bottom;
- clip_rect.top = picFrame.top;
-
- planelen = rowlen * collen;
- if ((red = (word*)malloc(planelen * sizeof(word))) == NULL ||
- (green = (word*)malloc(planelen * sizeof(word))) == NULL ||
- (blue = (word*)malloc(planelen * sizeof(word))) == NULL)
- {
-
- pm_error("not enough memory to hold picture");
- }
- /* initialize background to white */
- memset(red, 255, planelen * sizeof(word));
- memset(green, 255, planelen * sizeof(word));
- memset(blue, 255, planelen * sizeof(word));
- }
-
- static void
- compact_plane(plane, planelen)
- register word* plane;
- register int planelen;
- {
- register byte* p;
-
- for (p = (byte*)plane; planelen-- > 0; )
- *p++ = (*plane++ >> 8) & 255;
- }
-
- static void
- output_ppm(version)
- int version;
- {
- int width;
- int height;
- register char* r;
- register char* g;
- register char* b;
- pixel* pixelrow;
- register pixel* pP;
- int row;
- register int col;
-
- if (fullres)
- do_blits();
-
- stage = "writing PPM";
-
- width = picFrame.right - picFrame.left;
- height = picFrame.bottom - picFrame.top;
- r = (char*) red;
- compact_plane((word*) r, width * height);
- g = (char*) green;
- compact_plane((word*) g, width * height);
- b = (char*) blue;
- compact_plane((word*) b, width * height);
-
- ppm_writeppminit(stdout, width, height, (pixval) 255, 0 );
- pixelrow = ppm_allocrow(width);
- for (row = 0; row < height; ++row) {
- for (col = 0, pP = pixelrow; col < width;
- ++col, ++pP, ++r, ++g, ++b) {
- PPM_ASSIGN(*pP, *r, *g, *b);
- }
-
- ppm_writeppmrow(stdout, pixelrow, width, (pixval) 255, 0 );
- }
- pm_close(stdout);
- }
-
- static void
- do_blits()
- {
- struct blit_info* bi;
- int srcwidth, dstwidth, srcheight, dstheight;
- double scale, scalelow, scalehigh;
- double xscale = 1.0;
- double yscale = 1.0;
- double lowxscale, highxscale, lowyscale, highyscale;
- int xscalecalc = 0, yscalecalc = 0;
-
- if (!blit_list) return;
-
- fullres = 0;
-
- for (bi = blit_list; bi; bi = bi->next) {
- srcwidth = rectwidth(&bi->srcRect);
- dstwidth = rectwidth(&bi->dstRect);
- srcheight = rectheight(&bi->srcRect);
- dstheight = rectheight(&bi->dstRect);
- if (srcwidth > dstwidth) {
- scalelow = (double)(srcwidth ) / (double)dstwidth;
- scalehigh = (double)(srcwidth + 1.0) / (double)dstwidth;
- switch (xscalecalc) {
- case 0:
- lowxscale = scalelow;
- highxscale = scalehigh;
- xscalecalc = 1;
- break;
- case 1:
- if (scalelow < highxscale && scalehigh > lowxscale) {
- if (scalelow > lowxscale) lowxscale = scalelow;
- if (scalehigh < highxscale) highxscale = scalehigh;
- }
- else {
- scale = (lowxscale + highxscale) / 2.0;
- xscale = (double)srcwidth / (double)dstwidth;
- if (scale > xscale) xscale = scale;
- xscalecalc = 2;
- }
- break;
- case 2:
- scale = (double)srcwidth / (double)dstwidth;
- if (scale > xscale) xscale = scale;
- break;
- }
- }
-
- if (srcheight > dstheight) {
- scalelow = (double)(srcheight ) / (double)dstheight;
- scalehigh = (double)(srcheight + 1.0) / (double)dstheight;
- switch (yscalecalc) {
- case 0:
- lowyscale = scalelow;
- highyscale = scalehigh;
- yscalecalc = 1;
- break;
- case 1:
- if (scalelow < highyscale && scalehigh > lowyscale) {
- if (scalelow > lowyscale) lowyscale = scalelow;
- if (scalehigh < highyscale) highyscale = scalehigh;
- }
- else {
- scale = (lowyscale + highyscale) / 2.0;
- yscale = (double)srcheight / (double)dstheight;
- if (scale > yscale) yscale = scale;
- yscalecalc = 2;
- }
- break;
- case 2:
- scale = (double)srcheight / (double)dstheight;
- if (scale > yscale) yscale = scale;
- break;
- }
- }
- }
-
- if (xscalecalc == 1) {
- if (1.0 >= lowxscale && 1.0 <= highxscale)
- xscale = 1.0;
- else
- xscale = lowxscale;
- }
- if (yscalecalc == 1) {
- if (1.0 >= lowyscale && 1.0 <= lowyscale)
- yscale = 1.0;
- else
- yscale = lowyscale;
- }
-
- if (xscale != 1.0 || yscale != 1.0) {
- for (bi = blit_list; bi; bi = bi->next)
- rectscale(&bi->dstRect, xscale, yscale);
-
- pm_message("Scaling output by %f in X and %f in Y",
- xscale, yscale, 0, 0, 0);
- rectscale(&picFrame, xscale, yscale);
- }
-
- alloc_planes();
-
- for (bi = blit_list; bi; bi = bi->next) {
- blit(&bi->srcRect, &bi->srcBounds, bi->srcwid, bi->srcplane,
- bi->pixSize,
- &bi->dstRect, &picFrame, rowlen,
- bi->colour_map,
- bi->mode);
- }
- }
-
- /*
- * This could use read_pixmap, but I'm too lazy to hack read_pixmap.
- */
-
- static void
- Opcode_9A(version)
- int version;
- {
- #ifdef DUMP
- FILE *fp = fopen("data", "w");
- int ch;
- if (fp == NULL) exit(1);
- while ((ch = fgetc(ifp)) != EOF) fputc(ch, fp);
- exit(0);
- #else
- struct pixMap p;
- struct Rect srcRect;
- struct Rect dstRect;
- byte* pm;
- int pixwidth;
- word mode;
-
- /* skip fake len, and fake EOF */
- skip(4);
- read_word(); /* version */
- read_rect(&p.Bounds);
- pixwidth = p.Bounds.right - p.Bounds.left;
- p.packType = read_word();
- p.packSize = read_long();
- p.hRes = read_long();
- p.vRes = read_long();
- p.pixelType = read_word();
- p.pixelSize = read_word();
- p.pixelSize = read_word();
- p.cmpCount = read_word();
- p.cmpSize = read_word();
- p.planeBytes = read_long();
- p.pmTable = read_long();
- p.pmReserved = read_long();
-
- if (p.pixelSize == 16)
- pixwidth *= 2;
- else if (p.pixelSize == 32)
- pixwidth *= 3;
-
- read_rect(&srcRect);
- if (verbose)
- dump_rect("source rectangle:", &srcRect);
-
- read_rect(&dstRect);
- if (verbose)
- dump_rect("destination rectangle:", &dstRect);
-
- mode = read_word();
- if (verbose)
- pm_message("transfer mode = %s", const_name(transfer_name, mode),0,0,0,0);
-
- pm = unpackbits(&p.Bounds, 0, p.pixelSize);
-
- if (blit(&srcRect, &(p.Bounds), pixwidth, pm, p.pixelSize,
- &dstRect, &picFrame, rowlen,
- (struct RGBColour*)0,
- mode))
- {
- free(pm);
- }
- #endif
- }
-
- static void
- BitsRect(version)
- int version;
- {
- word rowBytes;
-
- stage = "Reading rowBytes for bitsrect";
- rowBytes = read_word();
-
- if (verbose)
- pm_message("rowbytes = 0x%x (%d)", rowBytes, rowBytes & 0x7fff, 0, 0, 0);
-
- if (rowBytes & 0x8000)
- do_pixmap(version, rowBytes, 0);
- else
- do_bitmap(version, rowBytes, 0);
- }
-
- static void
- BitsRegion(version)
- int version;
- {
- word rowBytes;
-
- stage = "Reading rowBytes for bitsregion";
- rowBytes = read_word();
-
- if (rowBytes & 0x8000)
- do_pixmap(version, rowBytes, 1);
- else
- do_bitmap(version, rowBytes, 1);
- }
-
- static void
- do_bitmap(version, rowBytes, is_region)
- int version;
- int rowBytes;
- int is_region;
- {
- struct Rect Bounds;
- struct Rect srcRect;
- struct Rect dstRect;
- word mode;
- byte* pm;
- static struct RGBColour colour_table[] = { {65535L, 65535L, 65535L}, {0, 0, 0} };
-
- read_rect(&Bounds);
- read_rect(&srcRect);
- read_rect(&dstRect);
- mode = read_word();
- if (verbose)
- pm_message("transfer mode = %s", const_name(transfer_name, mode),0,0,0,0);
-
- if (is_region)
- skip_poly_or_region(version);
-
- stage = "unpacking rectangle";
-
- pm = unpackbits(&Bounds, rowBytes, 1);
-
- if (blit(&srcRect, &Bounds, Bounds.right - Bounds.left, pm, 8,
- &dstRect, &picFrame, rowlen,
- colour_table,
- mode))
- {
- free(pm);
- }
- }
-
- #if __STDC__
- static void
- do_pixmap( int version, word rowBytes, int is_region )
- #else /*__STDC__*/
- static void
- do_pixmap(version, rowBytes, is_region)
- int version;
- word rowBytes;
- int is_region;
- #endif /*__STDC__*/
- {
- word mode;
- struct pixMap p;
- word pixwidth;
- byte* pm;
- struct RGBColour* colour_table;
- struct Rect srcRect;
- struct Rect dstRect;
-
- read_pixmap(&p, NULL);
-
- pixwidth = p.Bounds.right - p.Bounds.left;
-
- if (verbose)
- pm_message("%d x %d rectangle", pixwidth,
- p.Bounds.bottom - p.Bounds.top, 0, 0, 0);
-
- colour_table = read_colour_table();
-
- read_rect(&srcRect);
-
- if (verbose)
- dump_rect("source rectangle:", &srcRect);
-
- read_rect(&dstRect);
-
- if (verbose)
- dump_rect("destination rectangle:", &dstRect);
-
- mode = read_word();
-
- if (verbose)
- pm_message("transfer mode = %s", const_name(transfer_name, mode),0,0,0,0);
-
- if (is_region)
- skip_poly_or_region(version);
-
- stage = "unpacking rectangle";
-
- pm = unpackbits(&p.Bounds, rowBytes, p.pixelSize);
-
- if (blit(&srcRect, &(p.Bounds), pixwidth, pm, 8,
- &dstRect, &picFrame, rowlen,
- colour_table,
- mode))
- {
- free(colour_table);
- free(pm);
- }
- }
-
- static struct blit_info* add_blit_list()
- {
- struct blit_info* bi;
-
- if (!(bi = (struct blit_info*)malloc(sizeof(struct blit_info))))
- pm_error("out of memory for blit list");
-
- bi->next = 0;
- *last_bl = bi;
- last_bl = &(bi->next);
-
- return bi;
- }
-
- /* Various transfer functions for blits.
- *
- * Note src[Not]{Or,Xor,Copy} only work if the source pixmap was originally
- * a bitmap.
- * There's also a small bug that the foreground and background colours
- * are not used in a srcCopy; this wouldn't be hard to fix.
- * It IS a problem since the foreground and background colours CAN be changed.
- */
-
- #define rgb_all_same(x, y) \
- ((x)->red == (y) && (x)->green == (y) && (x)->blue == (y))
- #define rgb_is_white(x) rgb_all_same((x), 0xffff)
- #define rgb_is_black(x) rgb_all_same((x), 0)
-
- static void srcCopy(src, dst)
- struct RGBColour* src;
- struct RGBColour* dst;
- {
- if (rgb_is_black(src))
- *dst = foreground;
- else
- *dst = background;
- }
-
- static void srcOr(src, dst)
- struct RGBColour* src;
- struct RGBColour* dst;
- {
- if (rgb_is_black(src))
- *dst = foreground;
- }
-
- static void srcXor(src, dst)
- struct RGBColour* src;
- struct RGBColour* dst;
- {
- dst->red ^= ~src->red;
- dst->green ^= ~src->green;
- dst->blue ^= ~src->blue;
- }
-
- static void srcBic(src, dst)
- struct RGBColour* src;
- struct RGBColour* dst;
- {
- if (rgb_is_black(src))
- *dst = background;
- }
-
- static void notSrcCopy(src, dst)
- struct RGBColour* src;
- struct RGBColour* dst;
- {
- if (rgb_is_white(src))
- *dst = foreground;
- else if (rgb_is_black(src))
- *dst = background;
- }
-
- static void notSrcOr(src, dst)
- struct RGBColour* src;
- struct RGBColour* dst;
- {
- if (rgb_is_white(src))
- *dst = foreground;
- }
-
- static void notSrcBic(src, dst)
- struct RGBColour* src;
- struct RGBColour* dst;
- {
- if (rgb_is_white(src))
- *dst = background;
- }
-
- static void notSrcXor(src, dst)
- struct RGBColour* src;
- struct RGBColour* dst;
- {
- dst->red ^= src->red;
- dst->green ^= src->green;
- dst->blue ^= src->blue;
- }
-
- static void addOver(src, dst)
- struct RGBColour* src;
- struct RGBColour* dst;
- {
- dst->red += src->red;
- dst->green += src->green;
- dst->blue += src->blue;
- }
-
- static void addPin(src, dst)
- struct RGBColour* src;
- struct RGBColour* dst;
- {
- if ((long)dst->red + (long)src->red > (long)op_colour.red)
- dst->red = op_colour.red;
- else
- dst->red = dst->red + src->red;
-
- if ((long)dst->green + (long)src->green > (long)op_colour.green)
- dst->green = op_colour.green;
- else
- dst->green = dst->green + src->green;
-
- if ((long)dst->blue + (long)src->blue > (long)op_colour.blue)
- dst->blue = op_colour.blue;
- else
- dst->blue = dst->blue + src->blue;
- }
-
- static void subOver(src, dst)
- struct RGBColour* src;
- struct RGBColour* dst;
- {
- dst->red -= src->red;
- dst->green -= src->green;
- dst->blue -= src->blue;
- }
-
- /* or maybe its src - dst; my copy of Inside Mac is unclear */
- static void subPin(src, dst)
- struct RGBColour* src;
- struct RGBColour* dst;
- {
- if ((long)dst->red - (long)src->red < (long)op_colour.red)
- dst->red = op_colour.red;
- else
- dst->red = dst->red - src->red;
-
- if ((long)dst->green - (long)src->green < (long)op_colour.green)
- dst->green = op_colour.green;
- else
- dst->green = dst->green - src->green;
-
- if ((long)dst->blue - (long)src->blue < (long)op_colour.blue)
- dst->blue = op_colour.blue;
- else
- dst->blue = dst->blue - src->blue;
- }
-
- static void adMax(src, dst)
- struct RGBColour* src;
- struct RGBColour* dst;
- {
- if (src->red > dst->red) dst->red = src->red;
- if (src->green > dst->green) dst->green = src->green;
- if (src->blue > dst->blue) dst->blue = src->blue;
- }
-
- static void adMin(src, dst)
- struct RGBColour* src;
- struct RGBColour* dst;
- {
- if (src->red < dst->red) dst->red = src->red;
- if (src->green < dst->green) dst->green = src->green;
- if (src->blue < dst->blue) dst->blue = src->blue;
- }
-
- static void blend(src, dst)
- struct RGBColour* src;
- struct RGBColour* dst;
- {
- #define blend_component(cmp) \
- ((long)src->cmp * (long)op_colour.cmp) / 65536 + \
- ((long)dst->cmp * (long)(65536 - op_colour.cmp) / 65536)
-
- dst->red = blend_component(red);
- dst->green = blend_component(green);
- dst->blue = blend_component(blue);
- }
-
- static void transparent(src, dst)
- struct RGBColour* src;
- struct RGBColour* dst;
- {
- if (src->red != background.red || src->green != background.green ||
- src->blue != background.blue)
- {
- *dst = *src;
- }
- }
-
- static transfer_func transfer(mode)
- int mode;
- {
- switch (mode) {
- case 0: return srcCopy;
- case 1: return srcOr;
- case 2: return srcXor;
- case 3: return srcBic;
- case 4: return notSrcCopy;
- case 5: return notSrcOr;
- case 6: return notSrcXor;
- case 7: return notSrcBic;
- case 32: return blend;
- case 33: return addPin;
- case 34: return addOver;
- case 35: return subPin;
- case 36: return transparent;
- case 37: return adMax;
- case 38: return subOver;
- case 39: return adMin;
- default:
- if (mode != 0)
- pm_message("no transfer function for code %s, using srcCopy",
- const_name(transfer_name, mode), 0, 0, 0, 0);
- return srcCopy;
- }
- }
-
- static int
- blit(srcRect, srcBounds, srcwid, srcplane, pixSize, dstRect, dstBounds, dstwid, colour_map, mode)
- struct Rect* srcRect;
- struct Rect* srcBounds;
- int srcwid;
- byte* srcplane;
- int pixSize;
- struct Rect* dstRect;
- struct Rect* dstBounds;
- int dstwid;
- struct RGBColour* colour_map;
- int mode;
- {
- struct Rect clipsrc;
- struct Rect clipdst;
- register byte* src;
- register word* reddst;
- register word* greendst;
- register word* bluedst;
- register int i;
- register int j;
- int dstoff;
- int xsize;
- int ysize;
- int srcadd;
- int dstadd;
- struct RGBColour* ct;
- int pkpixsize;
- struct blit_info* bi;
- struct RGBColour src_c, dst_c;
- transfer_func trf;
-
- if (ps_text)
- return;
-
- /* almost got it. clip source rect with source bounds.
- * clip dest rect with dest bounds. if source and
- * destination are not the same size, use pnmscale
- * to get a nicely sized rectangle.
- */
- rectinter(srcBounds, srcRect, &clipsrc);
- rectinter(dstBounds, dstRect, &clipdst);
-
- if (fullres) {
- bi = add_blit_list();
- bi->srcRect = clipsrc;
- bi->srcBounds = *srcBounds;
- bi->srcwid = srcwid;
- bi->srcplane = srcplane;
- bi->pixSize = pixSize;
- bi->dstRect = clipdst;
- bi->colour_map = colour_map;
- bi->mode = mode;
- return 0;
- }
-
- if (verbose) {
- dump_rect("copying from:", &clipsrc);
- dump_rect("to: ", &clipdst);
- pm_message("a %d x %d area to a %d x %d area",
- rectwidth(&clipsrc), rectheight(&clipsrc),
- rectwidth(&clipdst), rectheight(&clipdst), 0);
- }
-
- pkpixsize = 1;
- if (pixSize == 16)
- pkpixsize = 2;
-
- src = srcplane + (clipsrc.top - srcBounds->top) * srcwid +
- (clipsrc.left - srcBounds->left) * pkpixsize;
- xsize = clipsrc.right - clipsrc.left;
- ysize = clipsrc.bottom - clipsrc.top;
- srcadd = srcwid - xsize * pkpixsize;
-
- dstoff = (clipdst.top - dstBounds->top) * dstwid +
- (clipdst.left - dstBounds->left);
- reddst = red + dstoff;
- greendst = green + dstoff;
- bluedst = blue + dstoff;
- dstadd = dstwid - (clipdst.right - clipdst.left);
-
- /* get rid of Text mask mode bit, if (erroneously) set */
- if ((mode & ~64) == 0)
- trf = 0; /* optimized srcCopy */
- else
- trf = transfer(mode & ~64);
-
- if (!rectsamesize(&clipsrc, &clipdst)) {
- #ifdef STANDALONE
- fprintf(stderr,
- "picttoppm: standalone version can't scale rectangles yet, sorry.\n");
- fprintf(stderr, "picttoppm: skipping this rectangle.\n");
- return;
- #else
- FILE* pnmscale;
- char* tmpfile = tmpnam((char*)0);
- char command[1024];
- register byte* redsrc;
- register byte* greensrc;
- register byte* bluesrc;
- int greenpix;
- FILE* scaled;
- int cols, rows, format;
- pixval maxval;
- pixel* row;
- pixel* rowp;
-
- #if (defined(AMIGA) || defined(VMS))
- char ami_tmpfile[L_tmpnam];
- int ami_result;
- tmpnam(ami_tmpfile);
- if (!(pnmscale = fopen(ami_tmpfile, "w")))
- pm_error("cannot create temporary file '%s'", ami_tmpfile);
- #else /* AMIGA or VMS */
- sprintf(command, "pnmscale -xsize %d -ysize %d > %s",
- rectwidth(&clipdst), rectheight(&clipdst), tmpfile);
-
- pm_message("running 'pnmscale -xsize %d -ysize %d' on a %d x %d image",
- rectwidth(&clipdst), rectheight(&clipdst),
- rectwidth(&clipsrc), rectheight(&clipsrc), 0);
-
- if (!(pnmscale = popen(command, "w"))) {
- pm_message("cannot execute command '%s'", command, 0, 0, 0, 0);
- pm_perror("popen");
- }
- #endif /* AMIGA or VMS */
-
- /* This should really be PPM_MAXMAXVAL, but that can be big, and then
- * I'd have to conditionally output raw/not-raw PPM, which is a pain.
- */
- #define MY_MAXVAL (255)
-
- fprintf(pnmscale, "P6\n%d %d\n%d\n",
- rectwidth(&clipsrc), rectheight(&clipsrc), MY_MAXVAL);
-
- #define REDEPTH(c, oldmax) ((c) * ((MY_MAXVAL) + 1) / (oldmax + 1))
-
- switch (pixSize) {
- case 8:
- for (i = 0; i < ysize; ++i) {
- for (j = 0; j < xsize; ++j) {
- ct = colour_map + *src++;
- fputc(REDEPTH(ct->red, 65535L), pnmscale);
- fputc(REDEPTH(ct->green, 65535L), pnmscale);
- fputc(REDEPTH(ct->blue, 65535L), pnmscale);
- }
- src += srcadd;
- }
- break;
- case 16:
- for (i = 0; i < ysize; ++i) {
- for (j = 0; j < xsize; ++j) {
- fputc(REDEPTH((*src & 0x7c) >> 2, 32), pnmscale);
- greenpix = (*src++ & 3) << 3;
- greenpix |= (*src & 0xe0) >> 5;
- fputc(REDEPTH(greenpix, 32), pnmscale);
- fputc(REDEPTH((*src++ & 0x1f) << 11, 32), pnmscale);
- }
- src += srcadd;
- }
- break;
- case 32:
- srcadd = srcwid - xsize;
- redsrc = src;
- greensrc = src + (srcwid / 3);
- bluesrc = greensrc + (srcwid / 3);
-
- for (i = 0; i < ysize; ++i) {
- for (j = 0; j < xsize; ++j) {
- fputc(REDEPTH(*redsrc++, 256), pnmscale);
- fputc(REDEPTH(*greensrc++, 256), pnmscale);
- fputc(REDEPTH(*bluesrc++, 256), pnmscale);
- }
- redsrc += srcadd;
- greensrc += srcadd;
- bluesrc += srcadd;
- }
- }
-
- #if (defined(AMIGA) || defined(VMS))
- if( fclose(pnmscale) != 0 ) {
- unlink(ami_tmpfile);
- pm_perror("write error");
- }
- sprintf(command, "pnmscale -xsize %d -ysize %d %s > %s",
- rectwidth(&clipdst), rectheight(&clipdst), ami_tmpfile, tmpfile);
- pm_message("running 'pnmscale -xsize %d -ysize %d' on a %d x %d image",
- rectwidth(&clipdst), rectheight(&clipdst),
- rectwidth(&clipsrc), rectheight(&clipsrc), 0);
- ami_result = system(command);
- unlink(ami_tmpfile);
- #ifndef VMS
- if( ami_result != 0 ) {
- #else
- if( ami_result == 0 ) {
- #endif
- unlink(tmpfile);
- pm_perror("pnmscale failed");
- }
- #else /* AMIGA or VMS */
- if (pclose(pnmscale)) {
- pm_message("pnmscale failed", 0, 0, 0, 0, 0);
- pm_perror("pclose");
- }
- #endif /* AMIGA or VMS */
- ppm_readppminit(scaled = pm_openr(tmpfile), &cols, &rows,
- &maxval, &format);
- row = ppm_allocrow(cols);
- /* couldn't hurt to assert cols, rows and maxval... */
-
- if (trf == 0) {
- while (rows-- > 0) {
- ppm_readppmrow(scaled, row, cols, maxval, format);
- for (i = 0, rowp = row; i < cols; ++i, ++rowp) {
- *reddst++ = PPM_GETR(*rowp) * 65536L / (maxval + 1);
- *greendst++ = PPM_GETG(*rowp) * 65536L / (maxval + 1);
- *bluedst++ = PPM_GETB(*rowp) * 65536L / (maxval + 1);
- }
- reddst += dstadd;
- greendst += dstadd;
- bluedst += dstadd;
- }
- }
- else {
- while (rows-- > 0) {
- ppm_readppmrow(scaled, row, cols, maxval, format);
- for (i = 0, rowp = row; i < cols; i++, rowp++) {
- dst_c.red = *reddst;
- dst_c.green = *greendst;
- dst_c.blue = *bluedst;
- src_c.red = PPM_GETR(*rowp) * 65536L / (maxval + 1);
- src_c.green = PPM_GETG(*rowp) * 65536L / (maxval + 1);
- src_c.blue = PPM_GETB(*rowp) * 65536L / (maxval + 1);
- (*trf)(&src_c, &dst_c);
- *reddst++ = dst_c.red;
- *greendst++ = dst_c.green;
- *bluedst++ = dst_c.blue;
- }
- reddst += dstadd;
- greendst += dstadd;
- bluedst += dstadd;
- }
- }
-
- pm_close(scaled);
- ppm_freerow(row);
- unlink(tmpfile);
- return;
- #endif /* STANDALONE */
- }
-
- if (trf == 0) {
- /* optimized srcCopy blit ('cause it was implemented first) */
- switch (pixSize) {
- case 8:
- for (i = 0; i < ysize; ++i) {
- for (j = 0; j < xsize; ++j) {
- ct = colour_map + *src++;
- *reddst++ = ct->red;
- *greendst++ = ct->green;
- *bluedst++ = ct->blue;
- }
- src += srcadd;
- reddst += dstadd;
- greendst += dstadd;
- bluedst += dstadd;
- }
- break;
- case 16:
- for (i = 0; i < ysize; ++i) {
- for (j = 0; j < xsize; ++j) {
- *reddst++ = (*src & 0x7c) << 9;
- *greendst = (*src++ & 3) << 14;
- *greendst++ |= (*src & 0xe0) << 6;
- *bluedst++ = (*src++ & 0x1f) << 11;
- }
- src += srcadd;
- reddst += dstadd;
- greendst += dstadd;
- bluedst += dstadd;
- }
- break;
- case 32:
- srcadd = (srcwid / 3) - xsize;
- for (i = 0; i < ysize; ++i) {
- for (j = 0; j < xsize; ++j)
- *reddst++ = *src++ << 8;
-
- reddst += dstadd;
- src += srcadd;
-
- for (j = 0; j < xsize; ++j)
- *greendst++ = *src++ << 8;
-
- greendst += dstadd;
- src += srcadd;
-
- for (j = 0; j < xsize; ++j)
- *bluedst++ = *src++ << 8;
-
- bluedst += dstadd;
- src += srcadd;
- }
- }
- }
- else {
- #define grab_destination() \
- dst_c.red = *reddst; \
- dst_c.green = *greendst; \
- dst_c.blue = *bluedst
-
- #define put_destination() \
- *reddst++ = dst_c.red; \
- *greendst++ = dst_c.green; \
- *bluedst++ = dst_c.blue
-
- /* generalized (but slow) blit */
- switch (pixSize) {
- case 8:
- for (i = 0; i < ysize; ++i) {
- for (j = 0; j < xsize; ++j) {
- grab_destination();
- (*trf)(colour_map + *src++, &dst_c);
- put_destination();
- }
- src += srcadd;
- reddst += dstadd;
- greendst += dstadd;
- bluedst += dstadd;
- }
- break;
- case 16:
- for (i = 0; i < ysize; ++i) {
- for (j = 0; j < xsize; ++j) {
- grab_destination();
- src_c.red = (*src & 0x7c) << 9;
- src_c.green = (*src++ & 3) << 14;
- src_c.green |= (*src & 0xe0) << 6;
- src_c.blue = (*src++ & 0x1f) << 11;
- (*trf)(&src_c, &dst_c);
- put_destination();
- }
- src += srcadd;
- reddst += dstadd;
- greendst += dstadd;
- bluedst += dstadd;
- }
- break;
- case 32:
- srcadd = srcwid / 3;
- for (i = 0; i < ysize; i++) {
- for (j = 0; j < xsize; j++) {
- grab_destination();
- src_c.red = *src << 8;
- src_c.green = src[srcadd] << 8;
- src_c.blue = src[srcadd * 2] << 8;
- (*trf)(&src_c, &dst_c);
- put_destination();
- src++;
- }
- src += srcwid - xsize;
- reddst += dstadd;
- greendst += dstadd;
- bluedst += dstadd;
- }
- }
- }
- return 1;
- }
-
- #if __STDC__
- static byte*
- unpackbits( struct Rect* bounds, word rowBytes, int pixelSize )
- #else /*__STDC__*/
- static byte*
- unpackbits(bounds, rowBytes, pixelSize)
- struct Rect* bounds;
- word rowBytes;
- int pixelSize;
- #endif /*__STDC__*/
- {
- byte* linebuf;
- byte* pm;
- byte* pm_ptr;
- register int i,j,k,l;
- word pixwidth;
- int linelen;
- int len;
- byte* bytepixels;
- int buflen;
- int pkpixsize;
- int rowsize;
-
- if (pixelSize <= 8)
- rowBytes &= 0x7fff;
-
- stage = "unpacking packbits";
-
- pixwidth = bounds->right - bounds->left;
-
- pkpixsize = 1;
- if (pixelSize == 16) {
- pkpixsize = 2;
- pixwidth *= 2;
- }
- else if (pixelSize == 32)
- pixwidth *= 3;
-
- if (rowBytes == 0)
- rowBytes = pixwidth;
-
- rowsize = pixwidth;
- if (rowBytes < 8)
- rowsize = 8 * rowBytes; /* worst case expansion factor */
-
- /* we're sloppy and allocate some extra space because we can overshoot
- * by as many as 8 bytes when we unpack the raster lines. Really, I
- * should be checking to see if we go over the scan line (it is
- * possible) and complain of a corrupt file. That fix is more complex
- * (and probably costly in CPU cycles) and will have to come later.
- */
- if ((pm = (byte*)malloc((rowsize * (bounds->bottom - bounds->top) + 8) * sizeof(byte))) == NULL)
- pm_error("no mem for packbits rectangle");
-
- /* Sometimes we get rows with length > rowBytes. I'll allocate some
- * extra for slop and only die if the size is _way_ out of wack.
- */
- if ((linebuf = (byte*)malloc(rowBytes + 100)) == NULL)
- pm_error("can't allocate memory for line buffer");
-
- if (rowBytes < 8) {
- /* ah-ha! The bits aren't actually packed. This will be easy */
- for (i = 0; i < bounds->bottom - bounds->top; i++) {
- pm_ptr = pm + i * pixwidth;
- read_n(buflen = rowBytes, (char*) linebuf);
- bytepixels = expand_buf(linebuf, &buflen, pixelSize);
- for (j = 0; j < buflen; j++)
- *pm_ptr++ = *bytepixels++;
- }
- }
- else {
- for (i = 0; i < bounds->bottom - bounds->top; i++) {
- pm_ptr = pm + i * pixwidth;
- if (rowBytes > 250 || pixelSize > 8)
- linelen = read_word();
- else
- linelen = read_byte();
-
- if (verbose > 1)
- pm_message("linelen: %d", linelen, 0, 0, 0, 0);
-
- if (linelen > rowBytes) {
- pm_message("linelen > rowbytes! (%d > %d) at line %d",
- linelen, rowBytes, i, 0, 0);
- }
-
- read_n(linelen, (char*) linebuf);
-
- for (j = 0; j < linelen; ) {
- if (linebuf[j] & 0x80) {
- len = ((linebuf[j] ^ 255) & 255) + 2;
- buflen = pkpixsize;
- bytepixels = expand_buf(linebuf + j+1, &buflen, pixelSize);
- for (k = 0; k < len; k++) {
- for (l = 0; l < buflen; l++)
- *pm_ptr++ = *bytepixels++;
- bytepixels -= buflen;
- }
- j += 1 + pkpixsize;
- }
- else {
- len = (linebuf[j] & 255) + 1;
- buflen = len * pkpixsize;
- bytepixels = expand_buf(linebuf + j+1, &buflen, pixelSize);
- for (k = 0; k < buflen; k++)
- *pm_ptr++ = *bytepixels++;
- j += len * pkpixsize + 1;
- }
- }
- }
- }
-
- free(linebuf);
-
- return pm;
- }
-
- static byte*
- expand_buf(buf, len, bits_per_pixel)
- byte* buf;
- int* len;
- int bits_per_pixel;
- {
- static byte pixbuf[256 * 8];
- register byte* src;
- register byte* dst;
- register int i;
-
- src = buf;
- dst = pixbuf;
-
- switch (bits_per_pixel) {
- case 8:
- case 16:
- case 32:
- return buf;
- case 4:
- for (i = 0; i < *len; i++) {
- *dst++ = (*src >> 4) & 15;
- *dst++ = *src++ & 15;
- }
- *len *= 2;
- break;
- case 2:
- for (i = 0; i < *len; i++) {
- *dst++ = (*src >> 6) & 3;
- *dst++ = (*src >> 4) & 3;
- *dst++ = (*src >> 2) & 3;
- *dst++ = *src++ & 3;
- }
- *len *= 4;
- break;
- case 1:
- for (i = 0; i < *len; i++) {
- *dst++ = (*src >> 7) & 1;
- *dst++ = (*src >> 6) & 1;
- *dst++ = (*src >> 5) & 1;
- *dst++ = (*src >> 4) & 1;
- *dst++ = (*src >> 3) & 1;
- *dst++ = (*src >> 2) & 1;
- *dst++ = (*src >> 1) & 1;
- *dst++ = *src++ & 1;
- }
- *len *= 8;
- break;
- default:
- pm_error("bad bits per pixel in expand_buf");
- }
- return pixbuf;
- }
-
- static void
- Clip(version)
- int version;
- {
- word len;
-
- len = read_word();
-
- if (len == 0x000a) { /* null rgn */
- read_rect(&clip_rect);
- /* XXX should clip this by picFrame */
- if (verbose)
- dump_rect("clipping to", &clip_rect);
- }
- else
- skip(len - 2);
- }
-
- static void
- read_pixmap(p, rowBytes)
- struct pixMap* p;
- word* rowBytes;
- {
- stage = "getting pixMap header";
-
- if (rowBytes != NULL)
- *rowBytes = read_word();
-
- read_rect(&p->Bounds);
- p->version = read_word();
- p->packType = read_word();
- p->packSize = read_long();
- p->hRes = read_long();
- p->vRes = read_long();
- p->pixelType = read_word();
- p->pixelSize = read_word();
- p->cmpCount = read_word();
- p->cmpSize = read_word();
- p->planeBytes = read_long();
- p->pmTable = read_long();
- p->pmReserved = read_long();
-
- if (verbose) {
- pm_message("pixelType: %d", p->pixelType, 0, 0, 0, 0);
- pm_message("pixelSize: %d", p->pixelSize, 0, 0, 0, 0);
- pm_message("cmpCount: %d", p->cmpCount, 0, 0, 0, 0);
- pm_message("cmpSize: %d", p->cmpSize, 0, 0, 0, 0);
- }
-
- if (p->pixelType != 0)
- pm_error("sorry, I only do chunky format");
- if (p->cmpCount != 1)
- pm_error("sorry, cmpCount != 1");
- if (p->pixelSize != p->cmpSize)
- pm_error("oops, pixelSize != cmpSize");
- }
-
- static struct RGBColour*
- read_colour_table()
- {
- longword ctSeed;
- word ctFlags;
- word ctSize;
- word val;
- int i;
- struct RGBColour* colour_table;
-
- stage = "getting color table info";
-
- ctSeed = read_long();
- ctFlags = read_word();
- ctSize = read_word();
-
- if (verbose) {
- pm_message("ctSeed: %d", ctSeed, 0, 0, 0, 0);
- pm_message("ctFlags: %d", ctFlags, 0, 0, 0, 0);
- pm_message("ctSize: %d", ctSize, 0, 0, 0, 0);
- }
-
- stage = "reading colour table";
-
- if ((colour_table = (struct RGBColour*) malloc(sizeof(struct RGBColour) * (ctSize + 1))) == NULL)
- pm_error("no memory for colour table");
-
- for (i = 0; i <= ctSize; i++) {
- val = read_word();
- /* The indicies in a device colour table are bogus and usually == 0.
- * so I assume we allocate up the list of colours in order.
- */
- if (ctFlags & 0x8000)
- val = i;
- if (val > ctSize)
- pm_error("pixel value greater than colour table size");
- colour_table[val].red = read_word();
- colour_table[val].green = read_word();
- colour_table[val].blue = read_word();
-
- if (verbose > 1)
- pm_message("%d: [%d,%d,%d]", val,
- colour_table[val].red,
- colour_table[val].green,
- colour_table[val].blue, 0);
- }
-
- return colour_table;
- }
-
- static void
- OpColor(version)
- int version;
- {
- op_colour.red = read_word();
- op_colour.green = read_word();
- op_colour.blue = read_word();
- }
-
- /* these 3 do nothing but skip over their data! */
- static void
- BkPixPat(version)
- int version;
- {
- read_pattern();
- }
-
- static void
- PnPixPat(version)
- int version;
- {
- read_pattern();
- }
-
- static void
- FillPixPat(version)
- int version;
- {
- read_pattern();
- }
-
- /* this just skips over a version 2 pattern. Probabaly will return
- * a pattern in the fabled complete version.
- */
- static void
- read_pattern()
- {
- word PatType;
- word rowBytes;
- struct pixMap p;
- byte* pm;
- struct RGBColour* ct;
-
- stage = "Reading a pattern";
-
- PatType = read_word();
-
- switch (PatType) {
- case 2:
- skip(8); /* old pattern data */
- skip(5); /* RGB for pattern */
- break;
- case 1:
- skip(8); /* old pattern data */
- read_pixmap(&p, &rowBytes);
- ct = read_colour_table();
- pm = unpackbits(&p.Bounds, rowBytes, p.pixelSize);
- free(pm);
- free(ct);
- break;
- default:
- pm_error("unknown pattern type in read_pattern");
- }
- }
-
- static void BkPat(version)
- int version;
- {
- read_8x8_pattern(&bkpat);
- }
-
- static void PnPat(version)
- int version;
- {
- read_8x8_pattern(&pen_pat);
- }
-
- static void FillPat(version)
- int version;
- {
- read_8x8_pattern(&fillpat);
- }
-
- static void
- read_8x8_pattern(pat)
- struct Pattern* pat;
- {
- byte buf[8], *exp;
- int len, i;
-
- read_n(len = 8, (char*)buf);
- if (verbose) {
- pm_message("pattern: %02x%02x%02x%02x",
- buf[0], buf[1], buf[2], buf[3], 0);
- pm_message("pattern: %02x%02x%02x%02x",
- buf[4], buf[5], buf[6], buf[7], 0);
- }
- exp = expand_buf(buf, &len, 1);
- for (i = 0; i < 64; i++)
- pat->pix[i] = *exp++;
- }
-
- static void PnSize(version)
- int version;
- {
- pen_height = read_word();
- pen_width = read_word();
- if (verbose)
- pm_message("pen size %d x %d", pen_width, pen_height, 0, 0, 0);
- }
-
- static void PnMode(version)
- int version;
- {
- pen_mode = read_word();
-
- if (pen_mode >= 8 && pen_mode < 15)
- pen_mode -= 8;
- if (verbose)
- pm_message("pen transfer mode = %s",
- const_name(transfer_name, pen_mode), 0, 0, 0, 0);
-
- pen_trf = transfer(pen_mode);
- }
-
- static void read_rgb(rgb)
- struct RGBColour* rgb;
- {
- rgb->red = read_word();
- rgb->green = read_word();
- rgb->blue = read_word();
- }
-
- static void RGBFgCol(v)
- int v;
- {
- read_rgb(&foreground);
- if (verbose)
- pm_message("foreground now [%d,%d,%d]",
- foreground.red, foreground.green, foreground.blue, 0, 0);
- }
-
- static void RGBBkCol(v)
- int v;
- {
- read_rgb(&background);
- if (verbose)
- pm_message("background now [%d,%d,%d]",
- background.red, background.green, background.blue, 0, 0);
- }
-
- static void read_point(p)
- struct Point* p;
- {
- p->y = read_word();
- p->x = read_word();
- }
-
- static void read_short_point(p)
- struct Point* p;
- {
- p->x = read_signed_byte();
- p->y = read_signed_byte();
- }
-
- #define PIXEL_INDEX(x,y) ((y) - picFrame.top) * rowlen + (x) - picFrame.left
-
- static void draw_pixel(x, y, clr, trf)
- int x, y;
- struct RGBColour* clr;
- transfer_func trf;
- {
- register i;
- struct RGBColour dst;
-
- if (x < clip_rect.left || x >= clip_rect.right ||
- y < clip_rect.top || y >= clip_rect.bottom)
- {
- return;
- }
-
- i = PIXEL_INDEX(x, y);
- dst.red = red[i];
- dst.green = green[i];
- dst.blue = blue[i];
- (*trf)(clr, &dst);
- red[i] = dst.red;
- green[i] = dst.green;
- blue[i] = dst.blue;
- }
-
- static void draw_pen_rect(r)
- struct Rect* r;
- {
- register i = PIXEL_INDEX(r->left, r->top);
- register int x, y;
- struct RGBColour dst;
- int rowadd = rowlen - (r->right - r->left);
-
- for (y = r->top; y < r->bottom; y++) {
- for (x = r->left; x < r->right; x++) {
- dst.red = red[i];
- dst.green = green[i];
- dst.blue = blue[i];
- if (pen_pat.pix[(x & 7) + (y & 7) * 8])
- (*pen_trf)(&black, &dst);
- else
- (*pen_trf)(&white, &dst);
- red[i] = dst.red;
- green[i] = dst.green;
- blue[i] = dst.blue;
-
- i++;
- }
- i += rowadd;
- }
- }
-
- static void draw_pen(x, y)
- int x, y;
- {
- struct Rect penrect;
-
- penrect.left = x;
- penrect.right = x + pen_width;
- penrect.top = y;
- penrect.bottom = y + pen_height;
-
- rectinter(&penrect, &clip_rect, &penrect);
-
- draw_pen_rect(&penrect);
- }
-
- /*
- * Digital Line Drawing
- * by Paul Heckbert
- * from "Graphics Gems", Academic Press, 1990
- */
-
- /* absolute value of a */
- #define ABS(a) (((a)<0) ? -(a) : (a))
- /* take binary sign of a, either -1, or 1 if >= 0 */
- #define SGN(a) (((a)<0) ? -1 : 1)
-
- /*
- * digline: draw digital line from (x1,y1) to (x2,y2),
- * calling a user-supplied procedure at each pixel.
- * Does no clipping. Uses Bresenham's algorithm.
- *
- * Paul Heckbert 3 Sep 85
- */
- static void scan_line(x1,y1,x2,y2)
- short x1,y1,x2,y2;
- {
- int d, x, y, ax, ay, sx, sy, dx, dy;
-
- if (pen_width == 0 && pen_height == 0)
- return;
-
- dx = x2-x1; ax = ABS(dx)<<1; sx = SGN(dx);
- dy = y2-y1; ay = ABS(dy)<<1; sy = SGN(dy);
-
- x = x1;
- y = y1;
- if (ax>ay) { /* x dominant */
- d = ay-(ax>>1);
- for (;;) {
- draw_pen(x, y);
- if (x==x2) return;
- if ((x > rowlen) && (sx > 0)) return;
- if (d>=0) {
- y += sy;
- d -= ax;
- }
- x += sx;
- d += ay;
- }
- }
- else { /* y dominant */
- d = ax-(ay>>1);
- for (;;) {
- draw_pen(x, y);
- if (y==y2) return;
- if ((y > collen) && (sy > 0)) return;
- if (d>=0) {
- x += sx;
- d -= ay;
- }
- y += sy;
- d += ax;
- }
- }
- }
-
- static void Line(v)
- int v;
- {
- struct Point p1;
- read_point(&p1);
- read_point(¤t);
- if (verbose)
- pm_message("(%d,%d) to (%d, %d)",
- p1.x,p1.y,current.x,current.y, 0);
- scan_line(p1.x,p1.y,current.x,current.y);
- }
-
- static void LineFrom(v)
- int v;
- {
- struct Point p1;
- read_point(&p1);
- if (verbose)
- pm_message("(%d,%d) to (%d, %d)",
- current.x,current.y,p1.x,p1.y, 0);
-
- if (!fullres)
- scan_line(current.x,current.y,p1.x,p1.y);
-
- current.x = p1.x;
- current.y = p1.y;
- }
-
- static void ShortLine(v)
- int v;
- {
- struct Point p1;
- read_point(&p1);
- read_short_point(¤t);
- if (verbose)
- pm_message("(%d,%d) delta (%d, %d)",
- p1.x,p1.y,current.x,current.y, 0);
- current.x += p1.x;
- current.y += p1.y;
-
- if (!fullres)
- scan_line(p1.x,p1.y,current.x,current.y);
- }
-
- static void ShortLineFrom(v)
- int v;
- {
- struct Point p1;
- read_short_point(&p1);
- if (verbose)
- pm_message("(%d,%d) delta (%d, %d)",
- current.x,current.y,p1.x,p1.y, 0);
- p1.x += current.x;
- p1.y += current.y;
- if (!fullres)
- scan_line(current.x,current.y,p1.x,p1.y);
- current.x = p1.x;
- current.y = p1.y;
- }
-
- static void paintRect(v)
- int v;
- {
- read_rect(&cur_rect);
- do_paintRect(&cur_rect);
- }
-
- static void paintSameRect(v)
- int v;
- {
- do_paintRect(&cur_rect);
- }
-
- static void do_paintRect(prect)
- struct Rect* prect;
- {
- struct Rect rect;
-
- if (fullres)
- return;
-
- if (verbose)
- dump_rect("painting", prect);
-
- rectinter(&clip_rect, prect, &rect);
-
- draw_pen_rect(&rect);
- }
-
- static void frameRect(v)
- int v;
- {
- read_rect(&cur_rect);
- do_frameRect(&cur_rect);
- }
-
- static void frameSameRect(v)
- int v;
- {
- do_frameRect(&cur_rect);
- }
-
- static void do_frameRect(rect)
- struct Rect* rect;
- {
- register int x, y;
-
- if (fullres)
- return;
-
- if (verbose)
- dump_rect("framing", rect);
-
- if (pen_width == 0 || pen_height == 0)
- return;
-
- for (x = rect->left; x <= rect->right - pen_width; x += pen_width) {
- draw_pen(x, rect->top);
- draw_pen(x, rect->bottom - pen_height);
- }
-
- for (y = rect->top; y <= rect->bottom - pen_height ; y += pen_height) {
- draw_pen(rect->left, y);
- draw_pen(rect->right - pen_width, y);
- }
- }
-
- /* a stupid shell sort - I'm so embarassed */
-
- static void poly_sort(sort_index, points)
- int sort_index;
- struct Point points[];
- {
- int d,i,j,k,temp;
-
- /* initialize and set up sort interval */
- d = 4;
- while (d<=sort_index) d <<= 1;
- d -= 1;
-
- while (d > 1) {
- d >>= 1;
- for (j = 0; j <= (sort_index-d); j++) {
- for(i = j; i >= 0; i -= d) {
- if ((points[i+d].y < points[i].y) ||
- ((points[i+d].y == points[i].y) &&
- (points[i+d].x <= points[i].x))) {
- /* swap x1,y1 with x2,y2 */
- temp = points[i].y;
- points[i].y = points[i+d].y;
- points[i+d].y = temp;
- temp = points[i].x;
- points[i].x = points[i+d].x;
- points[i+d].x = temp;
- }
- }
- }
- }
- }
-
- /* Watch out for the lack of error checking in the next two functions ... */
-
- static void scan_poly(np, pts)
- int np;
- struct Point pts[];
- {
- int dx,dy,dxabs,dyabs,i,scan_index,j,k,px,py;
- int sdx,sdy,x,y,toggle,old_sdy,sy0;
-
- /* This array needs to be at least as large as the largest dimension of
- the bounding box of the poly (but I don't check for overflows ...) */
- struct Point coord[5000];
-
- scan_index = 0;
-
- /* close polygon */
- px = pts[np].x = pts[0].x;
- py = pts[np].y = pts[0].y;
-
- /* This section draws the polygon and stores all the line points
- * in an array. This doesn't work for concave or non-simple polys.
- */
- /* are y levels same for first and second points? */
- if (pts[1].y == pts[0].y) {
- coord[scan_index].x = px;
- coord[scan_index].y = py;
- scan_index++;
- }
-
- #define sign(x) ((x) > 0 ? 1 : ((x)==0 ? 0:(-1)) )
-
- old_sdy = sy0 = sign(pts[1].y - pts[0].y);
- for (j=0; j<np; j++) {
- /* x,y difference between consecutive points and their signs */
- dx = pts[j+1].x - pts[j].x;
- dy = pts[j+1].y - pts[j].y;
- sdx = SGN(dx);
- sdy = SGN(dy);
- dxabs = abs(dx);
- dyabs = abs(dy);
- x = y = 0;
-
- if (dxabs >= dyabs)
- {
- for (k=0; k < dxabs; k++) {
- y += dyabs;
- if (y >= dxabs) {
- y -= dxabs;
- py += sdy;
- if (old_sdy != sdy) {
- old_sdy = sdy;
- scan_index--;
- }
- coord[scan_index].x = px+sdx;
- coord[scan_index].y = py;
- scan_index++;
- }
- px += sdx;
- draw_pen(px, py);
- }
- }
- else
- {
- for (k=0; k < dyabs; k++) {
- x += dxabs;
- if (x >= dyabs) {
- x -= dyabs;
- px += sdx;
- }
- py += sdy;
- if (old_sdy != sdy) {
- old_sdy = sdy;
- if (sdy != 0) scan_index--;
- }
- draw_pen(px,py);
- coord[scan_index].x = px;
- coord[scan_index].y = py;
- scan_index++;
- }
- }
- }
-
- /* after polygon has been drawn now fill it */
-
- scan_index--;
- if (sy0 + sdy == 0) scan_index--;
-
- poly_sort(scan_index, coord);
-
- toggle = 0;
- for (i = 0; i < scan_index; i++) {
- if ((coord[i].y == coord[i+1].y) && (toggle == 0))
- {
- for (j = coord[i].x; j <= coord[i+1].x; j++)
- draw_pen(j, coord[i].y);
- toggle = 1;
- }
- else
- toggle = 0;
- }
- }
-
-
- static void paintPoly(v)
- int v;
- {
- struct Rect bb;
- struct Point pts[100];
- int i, np = (read_word() - 10) >> 2;
-
- read_rect(&bb);
- for (i=0; i<np; ++i)
- read_point(&pts[i]);
-
- /* scan convert poly ... */
- if (!fullres)
- scan_poly(np, pts);
- }
-
- static void PnLocHFrac(version)
- int version;
- {
- word frac = read_word();
-
- if (verbose)
- pm_message("PnLocHFrac = %d", frac, 0, 0, 0, 0);
- }
-
- static void TxMode(version)
- int version;
- {
- text_mode = read_word();
-
- if (text_mode >= 8 && text_mode < 15)
- text_mode -= 8;
- if (verbose)
- pm_message("text transfer mode = %s",
- const_name(transfer_name, text_mode), 0, 0, 0, 0);
-
- /* ignore the text mask bit 'cause we don't handle it yet */
- text_trf = transfer(text_mode & ~64);
- }
-
- static void TxFont(version)
- int version;
- {
- text_font = read_word();
- if (verbose)
- pm_message("text font %s", const_name(font_name, text_font), 0, 0, 0, 0);
- }
-
- static void TxFace(version)
- int version;
- {
- text_face = read_byte();
- if (verbose)
- pm_message("text face %d", text_face, 0, 0, 0, 0);
- }
-
- static void TxSize(version)
- int version;
- {
- text_size = read_word();
- if (verbose)
- pm_message("text size %d", text_size, 0, 0, 0, 0);
- }
-
- static void
- skip_text()
- {
- skip(read_byte());
- }
-
- static void
- LongText(version)
- int version;
- {
- struct Point p;
-
- read_point(&p);
- do_text(p.x, p.y);
- }
-
- static void
- DHText(version)
- int version;
- {
- current.x += read_byte();
- do_text(current.x, current.y);
- }
-
- static void
- DVText(version)
- int version;
- {
- current.y += read_byte();
- do_text(current.x, current.y);
- }
-
- static void
- DHDVText(version)
- int version;
- {
- byte dh, dv;
-
- dh = read_byte();
- dv = read_byte();
-
- if (verbose)
- pm_message("dh, dv = %d, %d", dh, dv, 0, 0, 0);
-
- current.x += dh;
- current.y += dv;
- do_text(current.x, current.y);
- }
-
- static void
- #ifdef __STDC__
- do_text(word x, word y)
- #else
- do_text(x, y)
- word x;
- word y;
- #endif
- {
- int len, dy, w, h;
- struct glyph* glyph;
-
- if (fullres) {
- skip_text();
- return;
- }
-
- if (!(tfont = get_font(text_font, text_size, text_face)))
- tfont = pbm_defaultfont("bdf");
-
- if (ps_text) {
- do_ps_text(x, y);
- return;
- }
-
- for (len = read_byte(); len > 0; len--) {
- if (!(glyph = tfont->glyph[read_byte()]))
- continue;
-
- dy = y - glyph->height - glyph->y;
- for (h = 0; h < glyph->height; h++) {
- for (w = 0; w < glyph->width; w++) {
- if (glyph->bmap[h * glyph->width + w])
- draw_pixel(x + w + glyph->x, dy, &black, text_trf);
- else
- draw_pixel(x + w + glyph->x, dy, &white, text_trf);
- }
- dy++;
- }
- x += glyph->xadd;
- }
-
-
- current.x = x;
- current.y = y;
- }
-
- static void
- #ifdef __STDC__
- do_ps_text(word tx, word ty)
- #else
- do_ps_text(tx, ty)
- word tx;
- word ty;
- #endif
- {
- int len, width, i, w, h, x, y, rx, ry, o;
- byte str[256], ch;
- struct glyph* glyph;
-
- current.x = tx;
- current.y = ty;
-
- if (!ps_cent_set) {
- ps_cent_x += tx;
- ps_cent_y += ty;
- ps_cent_set = 1;
- }
-
- len = read_byte();
-
- /* XXX this width calculation is not completely correct */
- width = 0;
- for (i = 0; i < len; i++) {
- ch = str[i] = read_byte();
- if (tfont->glyph[ch])
- width += tfont->glyph[ch]->xadd;
- }
-
- if (verbose) {
- str[len] = '\0';
- pm_message("ps text: %s", str);
- }
-
- /* XXX The width is calculated in order to do different justifications.
- * However, I need the width of original text to finish the job.
- * In other words, font metrics for Quickdraw fonts
- */
-
- x = tx;
-
- for (i = 0; i < len; i++) {
- if (!(glyph = tfont->glyph[str[i]]))
- continue;
-
- y = ty - glyph->height - glyph->y;
- for (h = 0; h < glyph->height; h++) {
- for (w = 0; w < glyph->width; w++) {
- rx = x + glyph->x + w;
- ry = y;
- rotate(&rx, &ry);
- if ((rx >= picFrame.left) && (rx < picFrame.right) &&
- (ry >= picFrame.top) && (ry < picFrame.bottom))
- {
- o = PIXEL_INDEX(rx, ry);
- if (glyph->bmap[h * glyph->width + w]) {
- red[o] = foreground.red;
- green[o] = foreground.green;
- blue[o] = foreground.blue;
- }
- }
- }
- y++;
- }
- x += glyph->xadd;
- }
- }
-
- /* This only does 0, 90, 180 and 270 degree rotations */
-
- static void rotate(x, y)
- int *x;
- int *y;
- {
- int tmp;
-
- if (ps_rotation >= 315 || ps_rotation <= 45)
- return;
-
- *x -= ps_cent_x;
- *y -= ps_cent_y;
-
- if (ps_rotation > 45 && ps_rotation < 135) {
- tmp = *x;
- *x = *y;
- *y = tmp;
- }
- else if (ps_rotation >= 135 && ps_rotation < 225) {
- *x = -*x;
- }
- else if (ps_rotation >= 225 && ps_rotation < 315) {
- tmp = *x;
- *x = *y;
- *y = -tmp;
- }
- *x += ps_cent_x;
- *y += ps_cent_y;
- }
-
- static void
- skip_poly_or_region(version)
- int version;
- {
- stage = "skipping polygon or region";
- skip(read_word() - 2);
- }
-
- static
- void picComment(type, length)
- word type;
- int length;
- {
- switch (type) {
- case 150:
- if (verbose) pm_message("TextBegin");
- if (length < 6)
- break;
- ps_just = read_byte();
- ps_flip = read_byte();
- ps_rotation = read_word();
- ps_linespace = read_byte();
- length -= 5;
- if (recognize_comment)
- ps_text = 1;
- ps_cent_set = 0;
- if (verbose) {
- pm_message("%s justification, %s flip, %d degree rotation, %d/2 linespacing",
- const_name(ps_just_name, ps_just),
- const_name(ps_flip_name, ps_flip),
- ps_rotation, ps_linespace, 0);
- }
- break;
- case 151:
- if (verbose) pm_message("TextEnd");
- ps_text = 0;
- break;
- case 152:
- if (verbose) pm_message("StringBegin");
- break;
- case 153:
- if (verbose) pm_message("StringEnd");
- break;
- case 154:
- if (verbose) pm_message("TextCenter");
- if (length < 8)
- break;
- ps_cent_y = read_word();
- if (ps_cent_y > 32767)
- ps_cent_y -= 65536;
- skip(2); /* ignore fractional part */
- ps_cent_x = read_word();
- if (ps_cent_x > 32767)
- ps_cent_x -= 65536;
- skip(2); /* ignore fractional part */
- length -= 8;
- if (verbose)
- pm_message("offset %d %d", ps_cent_x, ps_cent_y);
- break;
- case 155:
- if (verbose) pm_message("LineLayoutOff");
- break;
- case 156:
- if (verbose) pm_message("LineLayoutOn");
- break;
- case 160:
- if (verbose) pm_message("PolyBegin");
- break;
- case 161:
- if (verbose) pm_message("PolyEnd");
- break;
- case 163:
- if (verbose) pm_message("PolyIgnore");
- break;
- case 164:
- if (verbose) pm_message("PolySmooth");
- break;
- case 165:
- if (verbose) pm_message("picPlyClo");
- break;
- case 180:
- if (verbose) pm_message("DashedLine");
- break;
- case 181:
- if (verbose) pm_message("DashedStop");
- break;
- case 182:
- if (verbose) pm_message("SetLineWidth");
- break;
- case 190:
- if (verbose) pm_message("PostScriptBegin");
- break;
- case 191:
- if (verbose) pm_message("PostScriptEnd");
- break;
- case 192:
- if (verbose) pm_message("PostScriptHandle");
- break;
- case 193:
- if (verbose) pm_message("PostScriptFile");
- break;
- case 194:
- if (verbose) pm_message("TextIsPostScript");
- break;
- case 195:
- if (verbose) pm_message("ResourcePS");
- break;
- case 200:
- if (verbose) pm_message("RotateBegin");
- break;
- case 201:
- if (verbose) pm_message("RotateEnd");
- break;
- case 202:
- if (verbose) pm_message("RotateCenter");
- break;
- case 210:
- if (verbose) pm_message("FormsPrinting");
- break;
- case 211:
- if (verbose) pm_message("EndFormsPrinting");
- break;
- default:
- if (verbose) pm_message("%d", type);
- break;
- }
- if (length > 0)
- skip(length);
- }
-
- static void
- ShortComment(version)
- int version;
- {
- picComment(read_word(), 0);
- }
-
- static void
- LongComment(version)
- int version;
- {
- word type;
-
- type = read_word();
- picComment(type, read_word());
- }
-
- static int
- rectwidth(r)
- struct Rect* r;
- {
- return r->right - r->left;
- }
-
- static int
- rectheight(r)
- struct Rect* r;
- {
- return r->bottom - r->top;
- }
-
- static int
- rectequal(r1, r2)
- struct Rect* r1;
- struct Rect* r2;
- {
- return r1->top == r2->top &&
- r1->bottom == r2->bottom &&
- r1->left == r2->left &&
- r1->right == r2->right;
- }
-
- static int
- rectsamesize(r1, r2)
- struct Rect* r1;
- struct Rect* r2;
- {
- return r1->right - r1->left == r2->right - r2->left &&
- r1->bottom - r1->top == r2->bottom - r2->top ;
- }
-
- static void
- rectinter(r1, r2, r3)
- struct Rect* r1;
- struct Rect* r2;
- struct Rect* r3;
- {
- r3->left = max(r1->left, r2->left);
- r3->top = max(r1->top, r2->top);
- r3->right = min(r1->right, r2->right);
- r3->bottom = min(r1->bottom, r2->bottom);
- }
-
- static void
- rectscale(r, xscale, yscale)
- struct Rect* r;
- double xscale;
- double yscale;
- {
- r->left *= xscale;
- r->right *= xscale;
- r->top *= yscale;
- r->bottom *= yscale;
- }
-
- static void
- read_rect(r)
- struct Rect* r;
- {
- r->top = read_word();
- r->left = read_word();
- r->bottom = read_word();
- r->right = read_word();
- }
-
- static void
- dump_rect(s, r)
- char* s;
- struct Rect* r;
- {
- pm_message("%s (%d,%d) (%d,%d)",
- s, r->left, r->top, r->right, r->bottom);
- }
-
- static char*
- const_name(table, ct)
- struct const_name* table;
- int ct;
- {
- static char numbuf[32];
- int i;
-
- for (i = 0; table[i].name; i++)
- if (table[i].value == ct)
- return table[i].name;
-
- sprintf(numbuf, "%d", ct);
- return numbuf;
- }
-
- /*
- * All data in version 2 is 2-byte word aligned. Odd size data
- * is padded with a null.
- */
- static word
- get_op(version)
- int version;
- {
- if ((align & 1) && version == 2) {
- stage = "aligning for opcode";
- read_byte();
- }
-
- stage = "reading opcode";
-
- if (version == 1)
- return read_byte();
- else
- return read_word();
- }
-
- static longword
- read_long()
- {
- word i;
-
- i = read_word();
- return (i << 16) | read_word();
- }
-
- static word
- read_word()
- {
- byte b;
-
- b = read_byte();
-
- return (b << 8) | read_byte();
- }
-
- static byte
- read_byte()
- {
- int c;
-
- if ((c = fgetc(ifp)) == EOF)
- pm_error("EOF / read error while %s", stage);
-
- ++align;
- return c & 255;
- }
-
- static signed_byte
- read_signed_byte()
- {
- return (signed_byte)read_byte();
- }
-
- static void
- skip(n)
- int n;
- {
- static byte buf[1024];
-
- align += n;
-
- for (; n > 0; n -= 1024)
- if (fread(buf, n > 1024 ? 1024 : n, 1, ifp) != 1)
- pm_error("EOF / read error while %s", stage);
- }
-
- static void
- read_n(n, buf)
- int n;
- char* buf;
- {
- align += n;
-
- if (fread(buf, n, 1, ifp) != 1)
- pm_error("EOF / read error while %s", stage);
- }
-
- #ifdef STANDALONE
-
- /* glue routines if you don't have PBM+ handy; these are only good enough
- * for picttoppm's purposes!
- */
-
- static char* outfile;
-
- void pm_message(fmt, p1, p2, p3, p4, p5)
- char* fmt;
- int p1, p2, p3, p4, p5;
- {
- fprintf(stderr, "picttoppm: ");
- fprintf(stderr, fmt, p1, p2, p3, p4, p5);
- fprintf(stderr, "\n");
- }
-
- void pm_error(fmt, p1, p2, p3, p4, p5)
- char* fmt;
- int p1, p2, p3, p4, p5;
- {
- pm_message(fmt, p1, p2, p3, p4, p5);
- exit(1);
- }
-
- int pm_keymatch(arg, opt, minlen)
- char* arg, *opt;
- int minlen;
- {
- for (; *arg && *arg == *opt; arg++, opt++)
- minlen--;
- return !*arg && minlen <= 0;
- }
-
- void ppm_init(argc, argv)
- int* argc;
- char** argv;
- {
- outfile = "standard output";
- }
-
- FILE* pm_openr(file)
- char* file;
- {
- FILE* fp;
-
- if (!(fp = fopen(file, "rb"))) {
- fprintf(stderr, "picttoppm: can't read file %s\n", file);
- exit(1);
- }
- outfile = file;
- return fp;
- }
-
- void writerr()
- {
- fprintf(stderr, "picttoppm: write error on %s\n", outfile);
- exit(1);
- }
-
- void pm_usage(u)
- char* u;
- {
- fprintf(stderr, "usage: picttoppm %s\n", u);
- exit(1);
- }
-
- void ppm_writeppminit(fp, width, height, maxval, forceplain)
- FILE* fp;
- int width, height, maxval, forceplain;
- {
- if (fprintf(fp, "P6\n%d %d\n%d\n", width, height, maxval) == EOF)
- writerr();
- }
-
- pixel* ppm_allocrow(width)
- int width;
- {
- pixel* r;
-
- if (!(r = (pixel*)malloc(width * sizeof(pixel)))) {
- fprintf(stderr, "picttoppm: out of memory\n");
- exit(1);
- }
- return r;
- }
-
- void ppm_writeppmrow(fp, row, width, maxval, forceplain)
- FILE* fp;
- pixel* row;
- int width, maxval, forceplain;
- {
- while (width--) {
- if (fputc(row->r, fp) == EOF) writerr();
- if (fputc(row->g, fp) == EOF) writerr();
- if (fputc(row->b, fp) == EOF) writerr();
- row++;
- }
- }
-
- void pm_close(fp)
- FILE* fp;
- {
- if (fclose(fp) == EOF)
- writerr();
- }
-
- #endif /* STANDALONE */
-
- /* Some font searching routines */
-
- struct fontinfo {
- int font;
- int size;
- int style;
- char* filename;
- struct font* loaded;
- struct fontinfo* next;
- };
-
- static struct fontinfo* fontlist = 0;
- static struct fontinfo** fontlist_ins = &fontlist;
-
- int load_fontdir(dirfile)
- char* dirfile;
- {
- FILE* fp;
- int n, nfont;
- char* arg[5], line[1024];
- struct fontinfo* fontinfo;
-
- if (!(fp = fopen(dirfile, "r")))
- return -1;
-
- nfont = 0;
- while (fgets(line, 1024, fp)) {
- if ((n = mk_argvn(line, arg, 5)) == 0 || arg[0][0] == '#')
- continue;
- if (n != 4)
- continue;
- if (!(fontinfo = (struct fontinfo*)malloc(sizeof(struct fontinfo))) ||
- !(fontinfo->filename = (char*)malloc(strlen(arg[3]) + 1)))
- {
- pm_error("out of memory for font information");
- }
-
- fontinfo->font = atoi(arg[0]);
- fontinfo->size = atoi(arg[1]);
- fontinfo->style = atoi(arg[2]);
- strcpy(fontinfo->filename, arg[3]);
- fontinfo->loaded = 0;
-
- fontinfo->next = 0;
- *fontlist_ins = fontinfo;
- fontlist_ins = &fontinfo->next;
- nfont++;
- }
-
- return nfont;
- }
-
- static int abs_value(x)
- int x;
- {
- if (x < 0)
- return -x;
- else
- return x;
- }
-
- static struct font* get_font(font, size, style)
- int font;
- int size;
- int style;
- {
- int closeness, bestcloseness;
- struct fontinfo* fi, *best;
-
- best = 0;
- for (fi = fontlist; fi; fi = fi->next) {
- closeness = abs_value(fi->font - font) * 10000 +
- abs_value(fi->size - size) * 100 +
- abs_value(fi->style - style);
- if (!best || closeness < bestcloseness) {
- best = fi;
- bestcloseness = closeness;
- }
- }
-
- if (best) {
- if (best->loaded)
- return best->loaded;
-
- if (best->loaded = pbm_loadbdffont(best->filename))
- return best->loaded;
- }
-
- /* It would be better to go looking for the nth best font, really */
- return 0;
- }
-
- #ifdef VMS
- unlink(p)
- char *p;
- {delete(p);}
- #endif
-