home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
NETWORK
/
netpbm_src.lzh
/
NETPBM
/
PPM
/
picttoppm.c
< prev
next >
Wrap
Text File
|
1996-11-26
|
75KB
|
3,345 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 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;
#ifndef _OSK
char* tmpfile = tmpnam((char*)0);
#else
char myname[20] = "/r0/picttopbmXXXXXX";
char* tmpfile = mktemp(myname);
#endif
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