minow@mountn.dec.com (Martin Minow) (07/08/90)
Thanks for all the good replies to my question on reading a 300 dpi PICT into a (72 dpi) window. Here's the code I use to read and write PICTs into an offscreen GrafPort. Martin Minow minow@bolt.enet.dec.com /* ReadPicture.c */ /* * Picture I/O * * For some reason, the PICT dimensions do not correctly * describe the picture: it loses its 300 dpi resolution * when read in. MAGIC scales the PICT by a factor of 4. * We should get the "real" scale factor by inserting * our function into the StdBits bottleneck. */ #include "CleanPICT.h" #include <SysErr.h> #define MAGIC(size) ((((long) size) * (4 * 72)) / 72) /* * See TechNote 27 (original format), and the Essential * MacTutor, vol 3, p 417. (This is now unused.) */ typedef struct { OSType fType; /* 'DRWG' for MacPaint files */ short hdrID; /* 'MD' for MacPaint format */ short version; /* File version */ short prRec[60]; /* 120 byte print record */ Fixed xOrigin; /* Drawing origin */ Fixed yOrigin; /* Drawing origin */ Fixed xScale; /* Screen resolution */ Fixed yScale; /* Screen resolution */ short atrState[31]; /* Drawing attribute state */ short lCnt; /* Top-level objects */ short lTot; /* Total number of objects */ long lSiz; /* Total size of list */ Long top; /* Box enclosing all objects */ Long left; Long bottom; Long right; short filler1[141]; /* 282 bytes unused */ } MacDrawHdrRec; static int PICTfile; /* The file ioRefNum */ /* * Use this to peek into the bitmap as it is read in. * The peeking is done by jumping into the Debugger. */ pascal void myStdBits( BitMap *, Rect *, Rect *, int, RgnHandle); pascal void read_picture_data(Ptr, int); pascal void write_picture_data(Ptr, int); /* * read_picture() reads the picture from the PICT file, * constructing the window at the proper size. * "window" is really a document structure: * typedef struct { * WindowRecord window; * GrafPtr pictPort; -- offscreen grafport * Rect pictSize; -- true PICT size * } DocumentRecord; * The DOC macro handles type casting and dereferencing. */ OSErr read_picture(window, theFile) WindowPtr window; /* Read into this document */ int theFile; /* From this open PICT file */ { PicHandle handle; QDProcs procedures; OSErr status; long size; long place; Rect box; GrafPtr oldPort; MacDrawHdrRec header; PICTfile = theFile; handle = (PicHandle) NewHandle(sizeof (Picture)); if (handle == NIL) { DebugStr("\pCan't get memory for picture"); return (MemError()); } /* * Read the MacDraw header record -- that was a * good idea, but it didn't work as the headers * are garbage in the PICT I'm using. */ if (sizeof header != 512) DebugStr("\pMacDrawHdrRec wrong size!"); read_picture_data((Ptr) &header, sizeof header); HLock(handle); read_picture_data((Ptr) *handle, sizeof (Picture)); HUnlock(handle); box = (**handle).picFrame; DOC.pictSize = box; box.right = MAGIC(box.right); box.bottom = MAGIC(box.bottom); GetPort(&oldPort); /* * Create an offscreen GrafPort. See TechNote 41. */ DOC.pictPort = CreateOSGrafPort(box); if (DOC.pictPort == NIL) { DebugStr("\pNo memory for picture"); SetPort(oldPort); return (MemError()); } SetStdProcs(&procedures); DOC.pictPort->grafProcs = &procedures; procedures.getPicProc = (Ptr) read_picture_data; /* procedures.bitsProc = (Ptr) myStdBits; -- unused */ DrawPicture(handle, &box); DOC.pictPort->grafProcs = NIL; DisposHandle((Handle) handle); SetPort(oldPort); /* * Check for errors by getting the file position and * checking that it is at the end of file. */ if ((status = GetEOF(PICTfile, &size)) != noErr || (status = GetFPos(PICTfile, &place)) != noErr) { DebugStr("\pCan't get EOF or file position"); return (status); } if (size != place) { DebugStr("\pDidn't read entire picture"); return (dsSysErr); } /* * Ok so far. Now, change the window size so the * picture fills the window -- but keep the proportions * as close to the original as possible. */ SetRect( &box, 2, GetMBarHeight() * 2, width(DOC.pictSize) + 2, GetMBarHeight() * 2 + height(DOC.pictSize) ); if (box.bottom > (screenBits.bounds.bottom - 2)) { box.bottom = screenBits.bounds.bottom - 2; size = height(box); box.right = box.left + ((long) width(box) * size) / height(DOC.pictSize); } if (box.right > (screenBits.bounds.right - 2)) { box.right = screenBits.bounds.right - 2; size = width(box); box.bottom = box.top + ((long) height(box) * size) / width(DOC.pictSize); } SizeWindow(window, width(box), height(box), TRUE); InvalRect(&window->portRect); ShowWindow(window); return (MemError()); } /* * This should implement a "vanilla" StdBits -- for some * reason, though, it "bombs" when it runs to completion: * probably because its called with a NULL argument at * eof. It was only used to check that the created * "MAGIC" bitmap is the same size as the bitmap inside * of the PICT -- by running the function under the * debugger. */ pascal void myStdBits(srcBits, srcRect, dstRect, mode, maskRgn) BitMap *srcBits; Rect *srcRect; Rect *dstRect; short mode; RgnHandle maskRgn; { CopyBits( srcBits, &thePort->portBits, srcRect, dstRect, mode, maskRgn ); } /* * Called indirectly to read a chunk of picture data. */ pascal void read_picture_data(data_ptr, byte_count) Ptr data_ptr; int byte_count; { OSErr status; long count; count = byte_count; status = FSRead(PICTfile, &count, data_ptr); if (status != noErr) DebugStr("\pReading picture"); } /* * write_picture() writes the current picture to a * specified (open) file. It should be redone to * add error handling. */ void write_picture(window, theFile) WindowPtr window; int theFile; { PicHandle picHandle; QDProcs procedures; int i; long temp; Picture header; GrafPtr tempPort; GrafPtr oldPort; GetPort(&oldPort); PICTfile = theFile; /* * Write a dummy MacPaint header */ temp = 0L; for (i = 0; i < 512; i += sizeof temp) write_picture_data((Ptr) &temp, (int) sizeof temp); header.picSize = 0; header.picFrame = DOC.pictSize; write_picture_data((Ptr) &header, (int) sizeof header); /* * Write the picture by creating a GrafPort with the * same dimensions as the original, then drawing the * cleaned up picture. Can this be done without * creating a new GrafPort? */ tempPort = CreateOSGrafPort(DOC.pictSize); if (tempPort == NIL) { DebugStr("\pNo space for temp port"); return; } SetStdProcs(&procedures); tempPort->grafProcs = &procedures; procedures.putPicProc = (Ptr) write_picture_data; picHandle = OpenPicture(&tempPort->portRect); CopyOSGrafPort(DOC.pictPort, tempPort); ClosePicture(); KillPicture(picHandle); DeleteOSGrafPort(tempPort); DOC.pictPort->grafProcs = NIL; SetPort(oldPort); } /* * Called indirectly to write a chunk of picture data. */ pascal void write_picture_data(data_ptr, byte_count) Ptr data_ptr; int byte_count; { OSErr status; long count; count = byte_count; status = FSWrite(PICTfile, &count, data_ptr); if (status != noErr) DebugStr("\pWriting picture"); }