#include "ET++.ph" #include "Converter.h" #include "Class.h" #include "Port.h" #include "Bitmap.h" #include "DevBitmap.h" #include "Picture.h" #include "PictPort.h" #include "String.h" #include "Data.h" #include "WindowColorMap.h" #include "TypeMatcher.h" #include "ET_stdio.h" static const Symbol cDocTypeMacPict("MACPICT"); #include "pict.xpm3" SmartBitmap gPictIcon(pict); Ink *mode[8]; static struct { Ink *ink; char bits[8]; } patmap[30]; static struct { int id; GrFont fid; } fmap[10] = { { 0, eFontChicago }, { 1, eFontHelvetica }, { 2, eFontTimes }, { 3, eFontHelvetica }, { 4, eFontCourier }, { 20, eFontTimes }, { 21, eFontHelvetica }, { 22, eFontCourier }, { 23, eFontSymbol }, { 15011, eFontAvantgarde } }; static void getrect(IStream &is, Rectangle &r) { r.origin.y= (short) is.GetBigEndian(2); r.origin.x= (short) is.GetBigEndian(2); r.extent.y= (short) is.GetBigEndian(2) - r.origin.y; r.extent.x= (short) is.GetBigEndian(2) - r.origin.x; } static Ink *FindInk(IStream &is) { byte pat[8]; int i; if (patmap[0].ink == 0) { patmap[0].ink= gInkWhite; patmap[1].ink= gInkBlack; memset(&patmap[1].bits, 0xff, 8); } is.read(pat, 8); for (i= 0; patmap[i].ink; i++) if (strncmp(patmap[i].bits, (char*)pat, 8) == 0) return patmap[i].ink; strncpy(patmap[i].bits, (char*)pat, 8); Bitmap *bm= new Bitmap(gPoint8); patmap[i].ink= bm; DevBitmap *dbm= bm->GetDevBitmap(); BitmapInfo bi(bm->Size(), 1, 1); for (int y= 0; y < 8; y++) dbm->SetRow(&bi, y, &pat[y]); return bm; } static void readpixmap(IStream &is, Port *port, bool draw, bool direct, bool region) { register int x, y, l, n; register DevBitmap *dbm; Bitmap *bm; Rectangle r, src, dst; int depth, count, packtype, rowbytes; if (direct) is.GetBigEndian(4); /* baseAddr */ rowbytes= (short) is.GetBigEndian(2); /* rowbytes */ getrect(is, r); if (rowbytes & 0x8000) { rowbytes= rowbytes & 0x7fff; is.GetBigEndian(2); /* version */ packtype= (int) is.GetBigEndian(2); /* packType */ is.GetBigEndian(4); /* packSize */ is.GetBigEndian(4); /* hres.hres */ is.GetBigEndian(4); /* vres.vres */ is.GetBigEndian(2); /* pixelType */ is.GetBigEndian(2); /* pixelSize */ count= (int) is.GetBigEndian(2); /* cmpCount */ depth= (int) is.GetBigEndian(2); /* cmpSize */ depth= depth * count; is.GetBigEndian(4); /* planeBytes */ is.GetBigEndian(4); /* pmTable */ is.GetBigEndian(4); /* pmReserved */ bm= new Bitmap(r.extent, depth); if (!direct) { is.GetBigEndian(4); /* ctSeed */ is.GetBigEndian(2); int cl= (int) is.GetBigEndian(2); if (cl >= 0) { u_short r, g, b, v; for (int i= 0; i <= cl; i++) { v= (u_short) is.GetBigEndian(2); r= (u_short) is.GetBigEndian(2); g= (u_short) is.GetBigEndian(2); b= (u_short) is.GetBigEndian(2); RGB rgb(r/256, g/256, b/256); bm->ChangeRGB(i, &rgb); } } } } else { depth= 1; bm= new Bitmap(r.extent, depth); } getrect(is, src); getrect(is, dst); is.GetBigEndian(2); /* mode */ if (region) is.seek((short) is.GetBigEndian(2)-2, TRUE); // skip region byte *buf= new byte[rowbytes]; dbm= bm->GetDevBitmap(); BitmapInfo bi(bm->Size(), depth, 1); for (y= 0; y < r.extent.y; y++) { register byte *bp= buf; if (rowbytes < 8) { is.read(bp, rowbytes); bp+= rowbytes; } else { if (rowbytes > 250) n= (short) is.GetBigEndian(2); else n= is.GetByte(); while (n > 0) { l= is.GetChar(); n--; if (l < 0) { l= -l+1; memset(bp, is.GetByte(), l); n--; } else { l++; is.read(bp, l); n-= l; } bp+= l; } } if (packtype == 4) { int l= (bp-buf)/3; for (x= 0; x < r.extent.x; x++) { RGB rgb(buf[x], buf[l+x], buf[l+l+x]); bm->SetRGB(x, y, &rgb); } } else dbm->SetRow(&bi, y, buf); } delete buf; if (bm && draw) port->ShowBitmap(gInkBlack, dst, bm); } static Ink *readcolor(IStream &is) { u_int r, g, b; r= (u_int) is.GetBigEndian(2); g= (u_int) is.GetBigEndian(2); b= (u_int) is.GetBigEndian(2); return new_RGBColor(r / 257, g / 257, b / 257); } static void MacPictParse(IStream &is, Port *port, int version) { register int i, l, c; u_int op; int npts= 0, done= 0, code, num= 1, denom= 1, pensize= 1, ps= 12; byte s[10000]; short a1, a2, a3, a4; GrFont font= eFontTimes; GrFace face= eFacePlain; Rectangle cliprect, r; Point origin, rad(4), tp, p1, p, d, pts[1000]; bool draw= TRUE, stroke= TRUE; Rectangle oldclip(port->GetCliprect()); mode[0]= gInkBlack; mode[1]= gInkBlack; mode[2]= gInkWhite; mode[3]= gInkXor; mode[4]= gInkBlack; mode[5]= gInkBlack; mode[6]= gInkBlack; mode[7]= gInkBlack; while (! done && is) { if (version == 1) { op= is.GetByte(); } else { if (is.tell() & 1) is.GetByte(); // pad op= (short) is.GetBigEndian(2); } switch (op) { case 0x00: /* no op */ break; case 1: /* clip */ c= (short) is.GetBigEndian(2); getrect(is, cliprect); if (cliprect.IsNotEmpty()) { draw= TRUE; port->Clip(oldclip); port->ClipFurther(cliprect); } else draw= FALSE; is.seek(c-10, TRUE); break; case 2: /* background pattern */ mode[2]= FindInk(is); break; case 3: /* text font */ c= (short) is.GetBigEndian(2); font= eFontDefault; for (i= 0; i < 10; i++) if (fmap[i].id == c) { font= fmap[i].fid; break; } if (i >= 10) fprintf(stderr, "Font ?: %d\n", c); break; case 4: /* text face */ face= (GrFace) is.GetByte(); // face= eFacePlain; break; case 5: /* text mode */ is.GetBigEndian(2); break; case 6: /* space extra */ is.seek(4, TRUE); break; case 7: /* pen size */ pensize= (short) is.GetBigEndian(2); a1= (short) is.GetBigEndian(2); if (pensize == 0 && a1 == 0) stroke= FALSE; else { stroke= TRUE; if (pensize != a1) pensize= (pensize+a1)/2; pensize= (pensize*num)/denom; } break; case 8: /* pen mode */ is.GetBigEndian(2); break; case 9: /* pen pat */ mode[1]= FindInk(is); break; case 0x0a: /* fill pat */ mode[4]= FindInk(is); break; case 0x0b: /* oval size */ rad.y= (short) is.GetBigEndian(2); rad.x= (short) is.GetBigEndian(2); break; case 0x0c: /* origin */ origin.y= (short) is.GetBigEndian(2); origin.x= (short) is.GetBigEndian(2); fprintf(stderr, "origin: %d,%d\n", origin.x, origin.y); break; case 0x0d: /* text size */ ps= (short) is.GetBigEndian(2); break; case 0x0e: /* fg color */ is.seek(4, TRUE); break; case 0x0f: /* bg color */ is.seek(4, TRUE); break; case 0x10: /* text ratio */ is.seek(8, TRUE); break; case 0x11: /* version */ version= is.GetByte(); break; case 0x12: case 0x13: case 0x14: break; case 0x15: is.GetBigEndian(2); break; case 0x16: is.GetBigEndian(2); break; case 0x17: case 0x18: case 0x19: break; case 0x1a: mode[1]= readcolor(is); break; case 0x1b: mode[2]= readcolor(is); break; case 0x1c: // highlight flag break; case 0x1d: readcolor(is); break; case 0x1e: // default highlight color break; case 0x1f: readcolor(is); break; case 0x20: /* line from, to */ p1.y= (short) is.GetBigEndian(2); p1.x= (short) is.GetBigEndian(2); p.y= (short) is.GetBigEndian(2); p.x= (short) is.GetBigEndian(2); if (stroke && draw) port->StrokeLine(mode[1], pensize, eDefaultCap, p1, p); break; case 0x21: /* line from */ p1= p; p.y= (short) is.GetBigEndian(2); p.x= (short) is.GetBigEndian(2); if (stroke && draw) port->StrokeLine(mode[1], pensize, eDefaultCap, p1, p); break; case 0x22: /* short line from, to(dh, dv) */ p.y= (short) is.GetBigEndian(2); p.x= (short) is.GetBigEndian(2); d.x= is.GetChar(); d.y= is.GetChar(); if (stroke && draw) port->StrokeLine(mode[1], pensize, eDefaultCap, p, p+d); p+= d; break; case 0x23: /* short line from (dh, dv) */ d.x= is.GetChar(); d.y= is.GetChar(); if (stroke && draw) port->StrokeLine(mode[1], pensize, eDefaultCap, p, p+d); p+= d; break; case 0x24: case 0x25: case 0x26: case 0x27: is.seek((short) is.GetBigEndian(2), TRUE); break; case 0x28: /* long text */ tp.y= (short) is.GetBigEndian(2); tp.x= (short) is.GetBigEndian(2); l= is.GetByte(); is.read(s, l); if (draw) port->ShowString(new_Font(font, ps, face), mode[1], tp, (byte*)s, l); break; case 0x29: /* dh text */ tp.x+= is.GetByte(); l= is.GetByte(); is.read(s, l); if (draw) port->ShowString(new_Font(font, ps, face), mode[1], tp, (byte*)s, l); break; case 0x2a: /* dv text */ tp.y+= is.GetByte(); l= is.GetByte(); is.read(s, l); if (draw) port->ShowString(new_Font(font, ps, face), mode[1], tp, (byte*)s, l); break; case 0x2b: /* dh, dv text */ tp.x+= is.GetByte(); tp.y+= is.GetByte(); l= is.GetByte(); is.read(s, l); if (draw) port->ShowString(new_Font(font, ps, face), mode[1], tp, (byte*)s, l); break; case 0x2c: case 0x2d: case 0x2e: case 0x2f: is.seek((short) is.GetBigEndian(2), TRUE); break; case 0x30: /* framerect */ getrect(is, r); if (stroke && draw) port->StrokeRect(mode[1], pensize, r); break; case 0x31: /* paintrect */ case 0x32: /* eraserect */ case 0x33: /* invertrect */ case 0x34: /* fillrect */ case 0x35: case 0x36: case 0x37: getrect(is, r); if (draw) port->FillRect(mode[op & 7], r); break; case 0x38: /* frame same rect */ if (stroke && draw) port->StrokeRect(mode[1], pensize, r); break; case 0x39: /* paint same rect */ case 0x3a: /* erase same rect */ case 0x3b: /* invert same rect */ case 0x3c: /* fill same rect */ case 0x3d: case 0x3e: case 0x3f: if (draw) port->FillRect(mode[op & 7], r); break; case 0x40: /* frame R rect */ getrect(is, r); if (stroke && draw) port->StrokeRRect(mode[1], pensize, r, rad); break; case 0x41: /* paint R rect */ case 0x42: /* erase R rect */ case 0x43: /* invert R rect */ case 0x44: /* fill R rect */ case 0x45: case 0x46: case 0x47: getrect(is, r); if (draw) port->FillRRect(mode[op & 7], r, rad); break; case 0x48: /* frame same R rect */ if (stroke && draw) port->StrokeRRect(mode[1], pensize, r, rad); break; case 0x49: /* paint same R rect */ case 0x4a: /* erase same R rect */ case 0x4b: /* invert same R rect */ case 0x4c: /* fill same R rect */ case 0x4d: case 0x4e: case 0x4f: if (draw) port->FillRRect(mode[op & 7], r, rad); break; case 0x50: /* frame oval */ getrect(is, r); if (stroke && draw) port->StrokeOval(mode[1], pensize, r); break; case 0x51: /* paint oval */ case 0x52: /* erase oval */ case 0x53: /* invert oval */ case 0x54: /* fill oval */ case 0x55: case 0x56: case 0x57: getrect(is, r); if (draw) port->FillOval(mode[op & 7], r); break; case 0x58: /* frame same oval */ if (stroke && draw) port->StrokeOval(mode[1], pensize, r); break; case 0x59: /* paint same oval */ case 0x5a: /* erase same oval */ case 0x5b: /* invert same oval */ case 0x5c: /* fill same oval */ case 0x5d: case 0x5e: case 0x5f: if (draw) port->FillOval(mode[op & 7], r); break; case 0x60: /* frame arc */ getrect(is, r); a1= (short) is.GetBigEndian(2); a2= (short) is.GetBigEndian(2); if (stroke && draw) port->StrokeWedge(mode[1], pensize, eDefaultCap, r, a1, a2); break; case 0x61: /* paint arc */ case 0x62: /* erase arc */ case 0x63: /* invert arc */ case 0x64: /* fill arc */ case 0x65: case 0x66: case 0x67: getrect(is, r); a1= (short) is.GetBigEndian(2); a2= (short) is.GetBigEndian(2); if (draw) port->FillWedge(mode[op & 7], r, a1, a2); break; case 0x68: /* frame same arc */ a1= (short) is.GetBigEndian(2); a2= (short) is.GetBigEndian(2); if (stroke && draw) port->StrokeWedge(mode[1], pensize, eDefaultCap, r, a1, a2); break; case 0x69: /* paint same arc */ case 0x6a: /* erase same arc */ case 0x6b: /* invert same arc */ case 0x6c: /* fill same arc */ case 0x6d: case 0x6e: case 0x6f: a1= (short) is.GetBigEndian(2); a2= (short) is.GetBigEndian(2); if (draw) port->FillWedge(mode[op & 7], r, a1, a2); break; case 0x70: /* frame poly */ c= (short) is.GetBigEndian(2); getrect(is, r); npts= (c-10)/4; for (i= 0; i < npts; i++) { pts[i].y= (short) is.GetBigEndian(2); pts[i].x= (short) is.GetBigEndian(2); } if (stroke && draw) port->StrokePolygon(gPoint0, mode[1], pts, npts, ePolyDefault, pensize, eDefaultCap); break; case 0x71: /* paint poly */ case 0x72: /* erase poly */ case 0x73: /* invert poly */ case 0x74: /* fill poly */ case 0x75: case 0x76: case 0x77: c= (short) is.GetBigEndian(2); getrect(is, r); npts= (c-10)/4; for (i= 0; i < npts; i++) { pts[i].y= (short) is.GetBigEndian(2); pts[i].x= (short) is.GetBigEndian(2); } if (draw) port->FillPolygon(gPoint0, mode[op & 7], pts, npts, ePolyDefault); break; case 0x78: /* frame same poly */ if (stroke && draw) port->StrokePolygon(gPoint0, mode[1], pts, npts, ePolyDefault, pensize, eDefaultCap); break; case 0x79: /* paint same poly */ case 0x7a: /* erase same poly */ case 0x7b: /* invert same poly */ case 0x7c: /* fill same poly */ case 0x7d: case 0x7e: case 0x7f: if (draw) port->FillPolygon(gPoint0, mode[op & 7], pts, npts, ePolyDefault); break; case 0x80: /* frame region */ case 0x81: /* paint region */ case 0x82: /* erase region */ case 0x83: /* invert region */ case 0x84: /* fill region */ case 0x85: case 0x86: case 0x87: c= (short) is.GetBigEndian(2); getrect(is, r); is.seek(c-10, TRUE); break; case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: break; case 0x90: case 0x98: readpixmap(is, port, draw, FALSE, FALSE); break; case 0x91: case 0x99: readpixmap(is, port, draw, FALSE, TRUE); break; case 0x9a: readpixmap(is, port, draw, TRUE, FALSE); break; case 0x9b: readpixmap(is, port, draw, TRUE, TRUE); break; case 0xa0: /* comment */ code= (short) is.GetBigEndian(2); l= 0; goto Comment; case 0xa1: /* comment */ code= (short) is.GetBigEndian(2); l= (short) is.GetBigEndian(2); Comment: switch (code) { case 150: // TextBegin break; case 151: // TextEnd break; case 152: // StringBegin break; case 153: // StringEnd break; case 154: // TextCenter break; case 155: // LineLayoutOff break; case 156: // LineLayoutOn break; case 160: // PolyBegin break; case 161: // PolyEnd break; case 163: // PolyIgnore break; case 164: // PolySmooth break; case 165: // PolyClose break; case 180: // DashedLine is.read(s, l); port->GiveHint(66666, l, s); l= 0; break; case 181: // DashedStop port->GiveHint(66667, 0, 0); break; case 182: /* FractLineWidth */ num= (short) is.GetBigEndian(2); denom= (short) is.GetBigEndian(2); l-= 4; break; case 196: case 190: port->GiveHint(eHintEPSFStart, 0, 0); break; case 191: port->GiveHint(eHintEPSFEnd, 0, 0); break; case 192: break; case 200: a1= (short) is.GetBigEndian(2); a2= (short) is.GetBigEndian(2); port->GiveHint(77777, -1, form("%d rotate\n", 360-a2)); l-= 4; break; case 201: port->GiveHint(77778, -1, form("grestore\n")); break; case 202: port->GiveHint(eHintPostScript, -1, form("gsave\n%d %d translate\n", p.x, p.y)); a1= (short) is.GetBigEndian(2); a2= (short) is.GetBigEndian(2); a3= (short) is.GetBigEndian(2); a4= (short) is.GetBigEndian(2); port->GiveHint(eHintPostScript, -1, form("%d.%d %d.%d translate\n", a3, a4, a1, a2)); l-= 8; break; default: // fprintf(stderr, "Comment(%d) %d\n", code, l); break; } is.seek(l, TRUE); break; case 0xfe: l= (int) is.GetBigEndian(4); is.seek(c, TRUE); break; case 0xff: /* end */ c= (short) is.GetBigEndian(2); done= 1; break; default: is.seek(op >> 7, TRUE); break; } } } static int PICTVersion(IStream &is) { int pos= 0; u_char buf[512]; for (int ntry= 0; ntry < 2; ntry++) { //is.seek(2+8, TRUE); is.read(buf, 2+8); if (is.fail()) return 0; pos+= 10; u_short id= (short) is.GetBigEndian(2); if (is.fail()) return 0; pos+= 2; if (id == 0x1101) return 1; if (id == 0x0011) { if ((short) is.GetBigEndian(2) == 0x02ff) return 2; if (is.fail()) { fprintf(stderr, "too short 2\n"); return 0; } pos+= 2; } is.read(buf, 512-pos); //is.seek(512, FALSE); if (is.fail()) return 0; } return 0; } //---- PICTFileTypeMatcher ----------------------------------------------------- class PICTFileTypeMatcher: public TypeMatcher { public: PICTFileTypeMatcher(const Symbol &t) : TypeMatcher(t, 0, 0, FALSE) { } bool MatchContents(Data*, const char*, int); Bitmap *GetBitmap() { return gPictIcon; } }; static PICTFileTypeMatcher pictmatcher(cDocTypeMacPict); bool PICTFileTypeMatcher::MatchContents(Data*, const char *buf, int len) { IStream is(buf, len); return PICTVersion(is) != 0; } //---- MacPictConverter -------------------------------------------------------- class MacPictConverter : public Converter { public: MetaDef(MacPictConverter); MacPictConverter() { } const char *AsString() { return "Macintosh PICT"; } Object *Convert(Data *data, Class *want); bool CanConvert(Data *data, Class *want) { return data->Type() == cDocTypeMacPict && want == Meta(Picture); } }; NewMetaImpl0(MacPictConverter,Converter); Object *MacPictConverter::Convert(Data *data, Class*) { IStream is(data->GetStreamBufForReading(), 0, FALSE); int version= PICTVersion(is); if (version > 0) { Picture *pict= new Picture; PictPort *pp= new PictPort(pict); MacPictParse(is, pp, version); SafeDelete(pp); return pict; } return 0; }