home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / HyperCard / MaskImage / MaskImage.mod < prev   
Text File  |  1991-12-21  |  7KB  |  274 lines

  1. IMPLEMENTATION MODULE MaskImage;
  2. (*
  3.     HyperCard external to combine a foreground and background
  4.     image according to an anti-aliased mask. Call this XFCN
  5.     from HyperCard as follows:
  6.  
  7.         MaskImage(Foreground, Background, Mask[, Depth])
  8.  
  9.     where Foreground, Background and Mask are picture IDs,
  10.     for example created by PictureFromScrap, and Depth is
  11.     the pixel depth at which to generate the result image
  12.     (default is 16). The function result is a new picture ID
  13.     representing the composite image.
  14.  
  15.     Written by LDO 1991 December 15.
  16.     Took out automatic centring of images 1991 December 21.
  17. *)
  18.  
  19.     FROM Types IMPORT
  20.         noErr,
  21.         OSErr,
  22.         Rect;
  23.     FROM QuickDraw IMPORT
  24.         ditherCopy,
  25.         srcCopy,
  26.         CTabHandle,
  27.         GDHandle,
  28.         PicHandle,
  29.         ClosePicture,
  30.         CopyBits,
  31.         CopyMask,
  32.         DisposeCTable,
  33.         DrawPicture,
  34.         EraseRect,
  35.         GetCTable,
  36.         OpenPicture;
  37.     IMPORT
  38.         QDOffscreen;
  39.     FROM QDOffscreen IMPORT
  40.         GWorldFlags,
  41.         GWorldPtr,
  42.         DisposeGWorld,
  43.         GetGWorld,
  44.         LockPixels,
  45.         NewGWorld,
  46.         SetGWorld;
  47.     FROM ToolUtils IMPORT
  48.         FixRatio;
  49.     FROM HyperXCmd IMPORT
  50.         XCmdPtr;
  51.     FROM Useful IMPORT
  52.         IgnoreBoolean;
  53.     FROM HCUseful IMPORT
  54.         GetIntArg,
  55.         ReturnError;
  56.     FROM MaskImageCommon IMPORT
  57.         PictureToZero,
  58.         ZeroToPicture;
  59.  
  60.     PROCEDURE TheProc
  61.       (
  62.         ParamPtr : XCmdPtr
  63.       );
  64.       (* entry point for the external. *)
  65.  
  66.         VAR
  67.             ForegroundPicture, BackgroundPicture, MaskPicture : PicHandle;
  68.             PixelDepth : INTEGER;
  69.             ResultPicture : PicHandle;
  70.             Err : OSErr;
  71.  
  72.         PROCEDURE GetArgs;
  73.  
  74.         BEGIN
  75.             ForegroundPicture := ZeroToPicture(ParamPtr, ParamPtr^.params[1]);
  76.             BackgroundPicture := ZeroToPicture(ParamPtr, ParamPtr^.params[2]);
  77.             MaskPicture := ZeroToPicture(ParamPtr, ParamPtr^.params[3]);
  78.             PixelDepth := GetIntArg(ParamPtr, 4, 16)
  79.         END GetArgs;
  80.  
  81.         PROCEDURE GenerateResult;
  82.  
  83.             VAR
  84.                 PreviousGWorld : GWorldPtr;
  85.                 PreviousGDevice : GDHandle;
  86.                 LargeMaskGWorld, SmallMaskGWorld : GWorldPtr;
  87.                 ForegroundGWorld, ResultGWorld : GWorldPtr;
  88.                 LargeMaskBounds, SmallMaskBounds : Rect;
  89.                 LargeSrcBounds, SmallSrcBounds : Rect;
  90.                 ResultBounds : Rect;
  91.  
  92.             PROCEDURE InitStorage;
  93.  
  94.             BEGIN
  95.                 LargeMaskGWorld := NIL;
  96.                 SmallMaskGWorld := NIL;
  97.                 ForegroundGWorld := NIL;
  98.                 ResultGWorld := NIL
  99.             END InitStorage;
  100.  
  101.             PROCEDURE DisposeStorage;
  102.  
  103.             BEGIN
  104.                 IF LargeMaskGWorld <> NIL THEN
  105.                     DisposeGWorld(LargeMaskGWorld)
  106.                 END (*IF*);
  107.                 IF SmallMaskGWorld <> NIL THEN
  108.                     DisposeGWorld(SmallMaskGWorld)
  109.                 END (*IF*);
  110.                 IF ForegroundGWorld <> NIL THEN
  111.                     DisposeGWorld(ForegroundGWorld)
  112.                 END (*IF*);
  113.                 IF ResultGWorld <> NIL THEN
  114.                     DisposeGWorld(ResultGWorld)
  115.                 END (*IF*)
  116.             END DisposeStorage;
  117.  
  118.             PROCEDURE MagnifyRect
  119.               (
  120.                 VAR SrcRect : Rect;
  121.                 VAR ResultRect : Rect
  122.               );
  123.               (* sets ResultRect to SrcRect magnified 4x. *)
  124.  
  125.             BEGIN
  126.                 ResultRect.top := SrcRect.top * 4;
  127.                 ResultRect.left := SrcRect.left * 4;
  128.                 ResultRect.bottom := SrcRect.bottom * 4;
  129.                 ResultRect.right := SrcRect.right * 4
  130.             END MagnifyRect;
  131.  
  132.             PROCEDURE NewGreyIndexedGWorld
  133.               (
  134.                 VAR Result : GWorldPtr;
  135.                 PixelDepth : INTEGER; (* 1, 2, 4 or 8 *)
  136.                 VAR Bounds : Rect
  137.               );
  138.               (* creates a new GWorld with a colour table
  139.                 consisting of a uniform grey ramp at the
  140.                 specified pixel depth. *)
  141.  
  142.                 VAR
  143.                     GreyTable : CTabHandle;
  144.  
  145.             BEGIN
  146.                 GreyTable := GetCTable(32 + PixelDepth);
  147.                 Err := NewGWorld
  148.                   (
  149.                     (*@offscreenGWorld :=*) Result,
  150.                     (*PixelDepth :=*) PixelDepth,
  151.                     (*@boundsRect :=*) Bounds,
  152.                     (*cTable :=*) GreyTable,
  153.                     (*aGDevice :=*) NIL,
  154.                     (*flags :=*) GWorldFlags{QDOffscreen.useTempMem}
  155.                   );
  156.                 DisposeCTable(GreyTable)
  157.             END NewGreyIndexedGWorld;
  158.  
  159.         BEGIN (*GenerateResult*)
  160.             GetGWorld(PreviousGWorld, PreviousGDevice);
  161.             InitStorage;
  162.             LOOP (*once*)
  163.                 SmallSrcBounds := ForegroundPicture^^.picFrame;
  164.                 SmallMaskBounds := MaskPicture^^.picFrame;
  165.                 MagnifyRect(SmallSrcBounds, LargeSrcBounds);
  166.                 MagnifyRect(SmallMaskBounds, LargeMaskBounds);
  167.               (* draw the black-and-white mask at 4x actual size *)
  168.                 NewGreyIndexedGWorld(LargeMaskGWorld, 1, LargeSrcBounds);
  169.                 IF Err <> noErr THEN
  170.                     EXIT
  171.                 END (*IF*);
  172.                 IgnoreBoolean(LockPixels(LargeMaskGWorld^.portPixMap));
  173.                 SetGWorld(LargeMaskGWorld, NIL);
  174.                 EraseRect(LargeMaskGWorld^.portRect);
  175.                 DrawPicture(MaskPicture, LargeMaskBounds);
  176.               (* dither the mask down to the right size with anti-aliased edges *)
  177.                 NewGreyIndexedGWorld(SmallMaskGWorld, 4, SmallSrcBounds);
  178.                 IF Err <> noErr THEN
  179.                     EXIT
  180.                 END (*IF*);
  181.                 IgnoreBoolean(LockPixels(SmallMaskGWorld^.portPixMap));
  182.                 SetGWorld(SmallMaskGWorld, NIL);
  183.                 CopyBits
  184.                   (
  185.                     (*@srcBits :=*) LargeMaskGWorld^.portBits,
  186.                     (*@dstBits :=*) SmallMaskGWorld^.portBits,
  187.                     (*@srcRect :=*) LargeMaskGWorld^.portRect,
  188.                     (*@dstRect :=*) SmallMaskGWorld^.portRect,
  189.                     (*mode :=*) srcCopy + ditherCopy,
  190.                     (*maskRgn :=*) NIL
  191.                   );
  192.               (* free up some unneeded memory *)
  193.                 DisposeGWorld(LargeMaskGWorld);
  194.                 LargeMaskGWorld := NIL;
  195.               (* image the foreground picture into a gworld the same size as the mask *)
  196.                 Err := NewGWorld
  197.                   (
  198.                     (*@offscreenGWorld :=*) ForegroundGWorld,
  199.                     (*PixelDepth :=*) PixelDepth,
  200.                     (*@boundsRect :=*) SmallSrcBounds,
  201.                     (*cTable :=*) NIL,
  202.                     (*aGDevice :=*) NIL,
  203.                     (*flags :=*) GWorldFlags{QDOffscreen.useTempMem}
  204.                   );
  205.                 IF Err <> noErr THEN
  206.                     EXIT
  207.                 END (*IF*);
  208.                 IgnoreBoolean(LockPixels(ForegroundGWorld^.portPixMap));
  209.                 SetGWorld(ForegroundGWorld, NIL);
  210.                 EraseRect(ForegroundGWorld^.portRect);
  211.                 DrawPicture(ForegroundPicture, SmallSrcBounds);
  212.               (* now to combine everything *)
  213.                 ResultBounds := BackgroundPicture^^.picFrame;
  214.                 Err := NewGWorld
  215.                   (
  216.                     (*@offscreenGWorld :=*) ResultGWorld,
  217.                     (*PixelDepth :=*) PixelDepth,
  218.                     (*@boundsRect :=*) ResultBounds,
  219.                     (*cTable :=*) NIL,
  220.                     (*aGDevice :=*) NIL,
  221.                     (*flags :=*) GWorldFlags{QDOffscreen.useTempMem}
  222.                   );
  223.                 IF Err <> noErr THEN
  224.                     EXIT
  225.                 END (*IF*);
  226.                 IgnoreBoolean(LockPixels(ResultGWorld^.portPixMap));
  227.                 SetGWorld(ResultGWorld, NIL);
  228.                 EraseRect(ResultGWorld^.portRect);
  229.                 DrawPicture(BackgroundPicture, ResultBounds);
  230.                 CopyMask
  231.                   (
  232.                     (*@srcBits :=*) ForegroundGWorld^.portBits,
  233.                     (*@maskBits :=*) SmallMaskGWorld^.portBits,
  234.                     (*@dstBits :=*) ResultGWorld^.portBits,
  235.                     (*@srcRect :=*) ForegroundGWorld^.portRect,
  236.                     (*@maskRect :=*) SmallMaskGWorld^.portRect,
  237.                     (*@dstRect :=*) SmallSrcBounds
  238.                   );
  239.               (* free up more unneeded memory *)
  240.                 DisposeGWorld(SmallMaskGWorld);
  241.                 SmallMaskGWorld := NIL;
  242.                 DisposeGWorld(ForegroundGWorld);
  243.                 ForegroundGWorld := NIL;
  244.               (* now to build the result into a picture *)
  245.                 ResultPicture := OpenPicture(ResultGWorld^.portRect);
  246.                 CopyBits
  247.                   (
  248.                     (*@srcBits :=*) ResultGWorld^.portBits,
  249.                     (*@dstBits :=*) ResultGWorld^.portBits,
  250.                     (*@srcRect :=*) ResultGWorld^.portRect,
  251.                     (*@dstRect :=*) ResultGWorld^.portRect,
  252.                     (*mode :=*) srcCopy + ditherCopy,
  253.                     (*maskRgn :=*) NIL
  254.                   );
  255.                 ClosePicture;
  256.               (* all done *)
  257.                 EXIT
  258.             END (*LOOP*);
  259.             DisposeStorage;
  260.             SetGWorld(PreviousGWorld, PreviousGDevice)
  261.         END GenerateResult;
  262.  
  263.     BEGIN (*TheProc*)
  264.         GetArgs;
  265.         GenerateResult;
  266.         IF Err = noErr THEN
  267.             ParamPtr^.returnValue := PictureToZero(ParamPtr, ResultPicture)
  268.         ELSE
  269.             ReturnError(ParamPtr, Err)
  270.         END (*IF*)
  271.     END TheProc;
  272.  
  273. END MaskImage.
  274.