Offscreen Region.c

/*
    File:       Offscreen Region.c
 
    Contains:   Print clipped offscreen:  Takes a text string, turns it into a region and
                copies a clipped bitmap (just a pattern in this case, but it could be 
                anything) to the printing grafPort.  The effect is patterned text here, 
                but any image could be showing through the text.
    
                You can also see the clipped image on the screen by turning on DrawStuffToScreen.
                Do this with qdToScreen below.
 
                This sample is a rewrite of the 'Offscreen region MaskRgn' sample.
 
 
    Written by: Tim Carroll and Ingrid Kelly    
 
    Copyright:  Copyright © 1994-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
 
    Change History (most recent first):
                7/26/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                11/96                       Rewritten as 'Print clipped offscreen' to fix 
                                            problems printing to PostScript printers (changed
                                            maskRgn to clipping the region before sending to the
                                            printing port since PS printers don't support maskRgn)
    
                
 
*/
 
/*************************************************************************************
#
#   CONDITIONALS
#
#   There are a number of conditionals used to control exactly how the code runs.
#
#
#   qDebugging  -- Whether or not additional debugging code should be inserted.  With this
#   turned on, most errors will DebugStr almost immediately and return errors as the error
#   propagates up the calling chain.  This is slower, but if you've found a weird bug,
#   this is the fastest way to replicate it.
#
#   qdToScreen -- if this is set to 1, we draw to the screen instead of to the printer.
#
*************************************************************************************/
 
#define qDebugging 1
#define qdToScreen 0
 
 
/*********************************************************************************
#   ERROR HANDLING MACROS
#
#   These macros can be used to implement nice error handling within a function.
#   Essentially, all errors jump to an error handler at the end of the function, which
#   should cleanup  any leftovers and return the appropriate error result.
#
#   Note that the error handlers take a message string.  This should be a good
#   indication of the actual error, and it will appear when debugging is turned on.
#
#   Note that any additional sanity checking code can be added to any function by using
#
    
    #if qDebugging
        // do additional sanity checking here.
    #endif
#
#   For example, this could be used to check the internal validity of an object before
#   taking an action.
#   
*********************************************************************************/
 
#ifndef qDebugging
    #define qDebugging 0
#endif
 
#if qDebugging
    #define SIGNAL_ERROR(msg)       {DebugStr(msg); goto error;}
#else
    #define SIGNAL_ERROR(msg)       {goto error;}
#endif
 
#define FAIL_NIL(y,msg)         if (y == NULL) SIGNAL_ERROR(msg)
#define FAIL_OSERR(y,msg)       if (y != noErr) SIGNAL_ERROR(msg)
#define FAIL_FALSE(y,msg)       if (!y) SIGNAL_ERROR(msg)
 
 
 
#include <Printing.h>
#include <QDOffscreen.h>
#include <Fonts.h>
 
 
void        main (void);
OSStatus    PrintStuff (void);
OSStatus    DrawStuff (Rect theWorld);
OSStatus    PrepareOffScreens(void);
OSStatus    KillOffscreens(void);
OSStatus    DrawStuffToScreen(void);
 
/*------ globals --------------------------------------------------------------------------*/
 
GWorldPtr   gMaskOffscreen = NULL, gImageOffscreen = NULL;
RgnHandle   gMaskRegion = NULL;
Rect        gBoundsRect;
 
/*------ main ----------------------------------------------------------------------------*/
//  All main does is the standard mac init, followed by initializing the offscreens
//  and printing.
/*----------------------------------------------------------------------------------------*/
 
void main(void)
{
    OSStatus theErr = noErr;
    
    InitGraf(&qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(nil);
    InitCursor();
 
    theErr = PrepareOffScreens();
    FAIL_OSERR (theErr, "\pError: Failed to prepare the offscreen environment")
    
    #if qdToScreen      
        DrawStuffToScreen();
    while (!Button());
    #else
        PrintStuff ();
    #endif
    
error:
    theErr = KillOffscreens();
    
} /* main */
 
 
/*------ PrepareOffScreens ---------------------------------------------------------------*/
//  PrepareOffScreens sets up the GWorlds and does the actual text clipping.
/*----------------------------------------------------------------------------------------*/
 
OSStatus PrepareOffScreens()
{
    OSStatus theErr = noErr;
    CGrafPtr savePort;
    GDHandle saveDevice;
    short fontNum;
    PixPatHandle image = NULL;
    PixMapHandle thePix = NULL;
    
    SetRect(&gBoundsRect,0,0,700,700);
    GetGWorld(&savePort,&saveDevice);
    
    /* Create the offscreen mask */
    
    theErr = NewGWorld(&gMaskOffscreen, 1, &gBoundsRect, NULL, NULL, 0);
    FAIL_OSERR (theErr, "\pError: Failed to create mask GWorld")
    FAIL_NIL (gMaskOffscreen, "\pError: Failed to create mask GWorld")
    
    thePix = GetGWorldPixMap (gMaskOffscreen);
    FAIL_NIL (thePix, "\pError: Failed to retrieve mask pixmap")
    FAIL_FALSE (LockPixels(thePix), "\pError: Failed to lock the mask pixmap")
    
    SetGWorld(gMaskOffscreen,NULL);
    ClipRect(&gBoundsRect);
    
    ForeColor(blackColor);
    EraseRect(&gBoundsRect);
    GetFNum("\pTimes",&fontNum);
    TextFont(fontNum);
    TextFace(bold);
    TextSize(60);
    MoveTo(10,100);
    DrawString("\pHereÕs our string test");
    
    SetGWorld (savePort,saveDevice);
    
    /* OK, the mask pixmap now has our string in it.  Let's make a region from it. */
 
    gMaskRegion = NewRgn();
    theErr = QDError();
    FAIL_OSERR (theErr, "\pError: Failed to create the mask region")
    FAIL_NIL (gMaskRegion,"\pError: Failed to create the mask region")
    
    theErr = BitMapToRegion(gMaskRegion,&((GrafPtr)gMaskOffscreen)->portBits);
    FAIL_OSERR (theErr, "\pError: Failed to convert the mask to a region")
    
    UnlockPixels (thePix);
    
    
    /* Build the offscreen pixmap that we'll draw to the printer */
    
    theErr = NewGWorld(&gImageOffscreen, 8, &gBoundsRect, NULL, NULL, 0);
    FAIL_OSERR (theErr, "\pError: Failed to create image GWorld")
    FAIL_NIL (gImageOffscreen, "\pError: Failed to create image GWorld")
    
    thePix = GetGWorldPixMap (gImageOffscreen);
    FAIL_NIL (thePix, "\pError: Failed to retrieve image pixmap")
    FAIL_FALSE (LockPixels(thePix), "\pError: Failed to lock the image pixmap")
    
    /* We erase the image, then we use the mask clipping region and draw a color
       pattern to the pixmap */ 
    
    image = GetPixPat(16);
    FAIL_NIL (image, "\pError: Failed to load the pixel pat")
    
    SetGWorld(gImageOffscreen,NULL);
    ClipRect (&gBoundsRect);
    EraseRect (&gBoundsRect);
    
    SetClip(gMaskRegion);
    
    FillCRect(&gBoundsRect, image);
    
    // restore the clip rect
    ClipRect (&gBoundsRect);
    UnlockPixels(thePix);
    
    // Cleanup and return noErr;
    goto cleanup;
    
error:
    if (theErr == noErr)
        theErr = paramErr;
    
cleanup:
    SetGWorld (savePort, saveDevice);
    if (image != NULL)
        DisposePixPat(image);
    
    return theErr;
}
 
/*------ DrawStuff -----------------------------------------------------------------------*/
// DrawStuff CopyBits from the offscreen into the printer/window port.
/*----------------------------------------------------------------------------------------*/
 
OSStatus DrawStuff (Rect theRect)
{
    #pragma unused(theRect)
    OSStatus        theErr = noErr;
    GrafPtr         currentPort;
    PixMapHandle    offscreenPix;
 
    /* Here's where we use CopyBits to copy from gImageOffscreen to the printer/window port */
    
    GetPort(&currentPort);
    
    offscreenPix = GetGWorldPixMap(gImageOffscreen);
    FAIL_NIL (offscreenPix, "\pError: Failed to retrieve image pixmap")
    FAIL_FALSE (LockPixels(offscreenPix), "\pError: Failed to lock the image pixmap")
 
    CopyBits((BitMap*)*offscreenPix,
             &(currentPort)->portBits,
             &gBoundsRect, &gBoundsRect, srcCopy, NULL);
             
    UnlockPixels(offscreenPix);
 
    goto cleanup;
    
error:
    if (theErr == noErr)
        theErr = paramErr;
cleanup:
    return theErr;
}  /* DrawStuff */
 
/*------ PrintStuff ----------------------------------------------------------------------*/
// PrintStuff performs the generic printing calls for printing to the Macintosh Printing
// Manager.
// Sets the current port to the printer port.
/*----------------------------------------------------------------------------------------*/
 
OSStatus PrintStuff ()
{
    OSStatus    theErr = noErr;
    GrafPtr     oldPort;
    THPrint     thePrRecHdl;
    TPPrPort    thePrPort;
    TPrStatus   theStatus;
 
    GetPort(&oldPort);
    
    thePrRecHdl = (THPrint)  NewHandle (sizeof (TPrint));
    theErr = MemError();
    FAIL_OSERR( theErr, "\pError: Failed to allocate a TPrint record")
    FAIL_NIL (thePrRecHdl, "\pError: Failed to allocate a TPrint record")
    
    PrOpen(); //The PrOpen procedure prepares the current printer driver for use. 
    theErr = PrError();
    FAIL_OSERR (theErr, "\pError: Failed to open the printer driver")
    
    PrintDefault(thePrRecHdl);
    PrValidate(thePrRecHdl);
    theErr = PrError();
    FAIL_OSERR (theErr, "\pError: Failed to create a valid print record")
 
    if (! PrStlDialog(thePrRecHdl)) 
        goto cleanup; // user cancelled
              
    if (! PrJobDialog(thePrRecHdl)) 
        goto cleanup; // user cancelled
 
    thePrPort = PrOpenDoc(thePrRecHdl, nil, nil);
    theErr = PrError();
    
    if (theErr == noErr)
    {
        PrOpenPage(thePrPort, nil);
        theErr = PrError();
        
        if (theErr == noErr)
        {
            // Finally, we're ready to draw!
            DrawStuff ((**thePrRecHdl).prInfo.rPage);
            PrClosePage(thePrPort);
        }
        
        PrCloseDoc(thePrPort);
    }
    
    theErr = PrError();
    FAIL_OSERR (theErr, "\pError: Document failed to print")
    
    if ((((TPPrint)*thePrRecHdl)->prJob.bJDocLoop == bSpoolLoop))
        PrPicFile(thePrRecHdl, nil, nil, nil, &theStatus);                
        
    goto cleanup;
    
error:
    if (theErr == noErr)
        theErr = paramErr;
 
    
cleanup:
    SetPort(oldPort);
    PrClose();
    if (thePrRecHdl)
        DisposeHandle ((Handle) thePrRecHdl);
    
    return theErr;
}  /* PrintStuff */
 
/*------ KillOffscreens  ------------------------------------------------------------------*/
// KillOffscreens cleans up the offscreens.
/*----------------------------------------------------------------------------------------*/
 
OSStatus KillOffscreens()
{
    if (gMaskOffscreen)
        DisposeGWorld(gMaskOffscreen);
    if (gImageOffscreen)
        DisposeGWorld(gImageOffscreen);
    if (gMaskRegion)
        DisposeRgn(gMaskRegion);
 
    return noErr;
} /* KillOffscreens */
 
/*------ DrawStuffToScreen  ------------------------------------------------------------------*/
// DrawStuffToScreen sets up the window port.
// Sets the current port to the window port.
/*----------------------------------------------------------------------------------------*/
 
OSStatus DrawStuffToScreen(void)
{
    WindowRef   theWindow = NULL;
    Rect        bounds = gBoundsRect;
    OSStatus    theErr = noErr;
    GrafPtr     savePort;
    
    GetPort (&savePort);
    
    OffsetRect (&bounds, 30,30);
    theWindow = NewCWindow(NULL, &bounds, "\pFoo", true, 0, (WindowRef)-1, false, 0);
    FAIL_NIL (theWindow, "\pError: Failed to create the window")
 
    SetPortWindowPort (theWindow);
    theErr = DrawStuff(gBoundsRect);
    
    goto cleanup;
    
error:
    if (theErr == noErr)
        theErr = paramErr;
    
cleanup:
    SetPort (savePort);
    
    return theErr;
} /* DrawStuffToScreen */