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");
}