This is picttoppm.c in view mode; [Download] [Up]
/* * 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 to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation. This software is provided "as is" without express or * implied warranty. * * 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
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.