home *** CD-ROM | disk | FTP | other *** search
Modula Implementation | 1991-12-21 | 7.2 KB | 274 lines | [TEXT/MPS ] |
- IMPLEMENTATION MODULE MaskImage;
- (*
- HyperCard external to combine a foreground and background
- image according to an anti-aliased mask. Call this XFCN
- from HyperCard as follows:
-
- MaskImage(Foreground, Background, Mask[, Depth])
-
- where Foreground, Background and Mask are picture IDs,
- for example created by PictureFromScrap, and Depth is
- the pixel depth at which to generate the result image
- (default is 16). The function result is a new picture ID
- representing the composite image.
-
- Written by LDO 1991 December 15.
- Took out automatic centring of images 1991 December 21.
- *)
-
- FROM Types IMPORT
- noErr,
- OSErr,
- Rect;
- FROM QuickDraw IMPORT
- ditherCopy,
- srcCopy,
- CTabHandle,
- GDHandle,
- PicHandle,
- ClosePicture,
- CopyBits,
- CopyMask,
- DisposeCTable,
- DrawPicture,
- EraseRect,
- GetCTable,
- OpenPicture;
- IMPORT
- QDOffscreen;
- FROM QDOffscreen IMPORT
- GWorldFlags,
- GWorldPtr,
- DisposeGWorld,
- GetGWorld,
- LockPixels,
- NewGWorld,
- SetGWorld;
- FROM ToolUtils IMPORT
- FixRatio;
- FROM HyperXCmd IMPORT
- XCmdPtr;
- FROM Useful IMPORT
- IgnoreBoolean;
- FROM HCUseful IMPORT
- GetIntArg,
- ReturnError;
- FROM MaskImageCommon IMPORT
- PictureToZero,
- ZeroToPicture;
-
- PROCEDURE TheProc
- (
- ParamPtr : XCmdPtr
- );
- (* entry point for the external. *)
-
- VAR
- ForegroundPicture, BackgroundPicture, MaskPicture : PicHandle;
- PixelDepth : INTEGER;
- ResultPicture : PicHandle;
- Err : OSErr;
-
- PROCEDURE GetArgs;
-
- BEGIN
- ForegroundPicture := ZeroToPicture(ParamPtr, ParamPtr^.params[1]);
- BackgroundPicture := ZeroToPicture(ParamPtr, ParamPtr^.params[2]);
- MaskPicture := ZeroToPicture(ParamPtr, ParamPtr^.params[3]);
- PixelDepth := GetIntArg(ParamPtr, 4, 16)
- END GetArgs;
-
- PROCEDURE GenerateResult;
-
- VAR
- PreviousGWorld : GWorldPtr;
- PreviousGDevice : GDHandle;
- LargeMaskGWorld, SmallMaskGWorld : GWorldPtr;
- ForegroundGWorld, ResultGWorld : GWorldPtr;
- LargeMaskBounds, SmallMaskBounds : Rect;
- LargeSrcBounds, SmallSrcBounds : Rect;
- ResultBounds : Rect;
-
- PROCEDURE InitStorage;
-
- BEGIN
- LargeMaskGWorld := NIL;
- SmallMaskGWorld := NIL;
- ForegroundGWorld := NIL;
- ResultGWorld := NIL
- END InitStorage;
-
- PROCEDURE DisposeStorage;
-
- BEGIN
- IF LargeMaskGWorld <> NIL THEN
- DisposeGWorld(LargeMaskGWorld)
- END (*IF*);
- IF SmallMaskGWorld <> NIL THEN
- DisposeGWorld(SmallMaskGWorld)
- END (*IF*);
- IF ForegroundGWorld <> NIL THEN
- DisposeGWorld(ForegroundGWorld)
- END (*IF*);
- IF ResultGWorld <> NIL THEN
- DisposeGWorld(ResultGWorld)
- END (*IF*)
- END DisposeStorage;
-
- PROCEDURE MagnifyRect
- (
- VAR SrcRect : Rect;
- VAR ResultRect : Rect
- );
- (* sets ResultRect to SrcRect magnified 4x. *)
-
- BEGIN
- ResultRect.top := SrcRect.top * 4;
- ResultRect.left := SrcRect.left * 4;
- ResultRect.bottom := SrcRect.bottom * 4;
- ResultRect.right := SrcRect.right * 4
- END MagnifyRect;
-
- PROCEDURE NewGreyIndexedGWorld
- (
- VAR Result : GWorldPtr;
- PixelDepth : INTEGER; (* 1, 2, 4 or 8 *)
- VAR Bounds : Rect
- );
- (* creates a new GWorld with a colour table
- consisting of a uniform grey ramp at the
- specified pixel depth. *)
-
- VAR
- GreyTable : CTabHandle;
-
- BEGIN
- GreyTable := GetCTable(32 + PixelDepth);
- Err := NewGWorld
- (
- (*@offscreenGWorld :=*) Result,
- (*PixelDepth :=*) PixelDepth,
- (*@boundsRect :=*) Bounds,
- (*cTable :=*) GreyTable,
- (*aGDevice :=*) NIL,
- (*flags :=*) GWorldFlags{QDOffscreen.useTempMem}
- );
- DisposeCTable(GreyTable)
- END NewGreyIndexedGWorld;
-
- BEGIN (*GenerateResult*)
- GetGWorld(PreviousGWorld, PreviousGDevice);
- InitStorage;
- LOOP (*once*)
- SmallSrcBounds := ForegroundPicture^^.picFrame;
- SmallMaskBounds := MaskPicture^^.picFrame;
- MagnifyRect(SmallSrcBounds, LargeSrcBounds);
- MagnifyRect(SmallMaskBounds, LargeMaskBounds);
- (* draw the black-and-white mask at 4x actual size *)
- NewGreyIndexedGWorld(LargeMaskGWorld, 1, LargeSrcBounds);
- IF Err <> noErr THEN
- EXIT
- END (*IF*);
- IgnoreBoolean(LockPixels(LargeMaskGWorld^.portPixMap));
- SetGWorld(LargeMaskGWorld, NIL);
- EraseRect(LargeMaskGWorld^.portRect);
- DrawPicture(MaskPicture, LargeMaskBounds);
- (* dither the mask down to the right size with anti-aliased edges *)
- NewGreyIndexedGWorld(SmallMaskGWorld, 4, SmallSrcBounds);
- IF Err <> noErr THEN
- EXIT
- END (*IF*);
- IgnoreBoolean(LockPixels(SmallMaskGWorld^.portPixMap));
- SetGWorld(SmallMaskGWorld, NIL);
- CopyBits
- (
- (*@srcBits :=*) LargeMaskGWorld^.portBits,
- (*@dstBits :=*) SmallMaskGWorld^.portBits,
- (*@srcRect :=*) LargeMaskGWorld^.portRect,
- (*@dstRect :=*) SmallMaskGWorld^.portRect,
- (*mode :=*) srcCopy + ditherCopy,
- (*maskRgn :=*) NIL
- );
- (* free up some unneeded memory *)
- DisposeGWorld(LargeMaskGWorld);
- LargeMaskGWorld := NIL;
- (* image the foreground picture into a gworld the same size as the mask *)
- Err := NewGWorld
- (
- (*@offscreenGWorld :=*) ForegroundGWorld,
- (*PixelDepth :=*) PixelDepth,
- (*@boundsRect :=*) SmallSrcBounds,
- (*cTable :=*) NIL,
- (*aGDevice :=*) NIL,
- (*flags :=*) GWorldFlags{QDOffscreen.useTempMem}
- );
- IF Err <> noErr THEN
- EXIT
- END (*IF*);
- IgnoreBoolean(LockPixels(ForegroundGWorld^.portPixMap));
- SetGWorld(ForegroundGWorld, NIL);
- EraseRect(ForegroundGWorld^.portRect);
- DrawPicture(ForegroundPicture, SmallSrcBounds);
- (* now to combine everything *)
- ResultBounds := BackgroundPicture^^.picFrame;
- Err := NewGWorld
- (
- (*@offscreenGWorld :=*) ResultGWorld,
- (*PixelDepth :=*) PixelDepth,
- (*@boundsRect :=*) ResultBounds,
- (*cTable :=*) NIL,
- (*aGDevice :=*) NIL,
- (*flags :=*) GWorldFlags{QDOffscreen.useTempMem}
- );
- IF Err <> noErr THEN
- EXIT
- END (*IF*);
- IgnoreBoolean(LockPixels(ResultGWorld^.portPixMap));
- SetGWorld(ResultGWorld, NIL);
- EraseRect(ResultGWorld^.portRect);
- DrawPicture(BackgroundPicture, ResultBounds);
- CopyMask
- (
- (*@srcBits :=*) ForegroundGWorld^.portBits,
- (*@maskBits :=*) SmallMaskGWorld^.portBits,
- (*@dstBits :=*) ResultGWorld^.portBits,
- (*@srcRect :=*) ForegroundGWorld^.portRect,
- (*@maskRect :=*) SmallMaskGWorld^.portRect,
- (*@dstRect :=*) SmallSrcBounds
- );
- (* free up more unneeded memory *)
- DisposeGWorld(SmallMaskGWorld);
- SmallMaskGWorld := NIL;
- DisposeGWorld(ForegroundGWorld);
- ForegroundGWorld := NIL;
- (* now to build the result into a picture *)
- ResultPicture := OpenPicture(ResultGWorld^.portRect);
- CopyBits
- (
- (*@srcBits :=*) ResultGWorld^.portBits,
- (*@dstBits :=*) ResultGWorld^.portBits,
- (*@srcRect :=*) ResultGWorld^.portRect,
- (*@dstRect :=*) ResultGWorld^.portRect,
- (*mode :=*) srcCopy + ditherCopy,
- (*maskRgn :=*) NIL
- );
- ClosePicture;
- (* all done *)
- EXIT
- END (*LOOP*);
- DisposeStorage;
- SetGWorld(PreviousGWorld, PreviousGDevice)
- END GenerateResult;
-
- BEGIN (*TheProc*)
- GetArgs;
- GenerateResult;
- IF Err = noErr THEN
- ParamPtr^.returnValue := PictureToZero(ParamPtr, ResultPicture)
- ELSE
- ReturnError(ParamPtr, Err)
- END (*IF*)
- END TheProc;
-
- END MaskImage.
-