/*================================== PatternToOffscreen ===================================*/ SUOffscreen *PTPatternView::BWPatternToOffscreen( const Pattern &inPattern ) { StSaveGWorld save1; CTabHandle theTable = nil; SUOffscreen *theBuffer = nil; try { theTable = SUColorUtils::GetColorTable( 1 ); theBuffer = SUOffscreen::CreateBuffer( DefaultPatternWidth, DefaultPatternHeight, 1, theTable ); //theBuffer->AssignPalette( theTable ); theBuffer->BeginDrawing(); Rect r; ::SetRect( &r, 0, 0, DefaultPatternWidth, DefaultPatternHeight ); ::PenPat( &inPattern ); ::PaintRect( &r ); ::PenNormal(); theBuffer->EndDrawing(); } catch( ... ) { if ( theBuffer ) delete( theBuffer ); if ( theTable ) ::DisposeCTable( theTable ); throw; } if ( theTable ) ::DisposeCTable( theTable ); return( theBuffer ); }
/*================================ SetSelection =================================*/ void PTPaintSelection::SetSelection( PTPaintSelection *inSource ) { if ( inSource->IsEmpty() ) { this->SelectNone(); return; } try { this->DisposeBuffer(); SUOffscreen *sourceBuffer = inSource->mSelectionBuffer; mSelectionBuffer = sourceBuffer->CreateSimilarOffscreen( false ); mSelectionBuffer->CopyFrom( sourceBuffer ); this->SetRawSelection( inSource->GetRegion() ); } catch( ... ) { this->SelectNone(); // if an error occurs, force no selection or things get weird throw; } }
/*=============================================== ParseBWCursor ================================================*/ void PTCursorView::ParseBWCursor( RFMap *inMap, ResIDT inResID, SUOffscreen **outBW, SUOffscreen **outMask, Point *outHotSpot ) { CursHandle h = nil; SUOffscreen *bw = nil, *mask = nil; try { /************************************************** get the raw resource handle **************************************************/ RFResource *theRes = inMap->FindResource( ImageType_Cursor, inResID, false ); ThrowIfNil_( theRes ); h = (CursHandle) theRes->GetResData(); ThrowIfNil_( h ); ::HLock( (Handle) h ); // 2 rowBytes x 16 rows x 2 images + sizeof(Point) if ( ::GetHandleSize( (Handle) h ) != BWCursor_Bytes ) LException::Throw( err_CorruptedResource ); /************************************************** create the bw bitmap **************************************************/ bw = SUOffscreen::CreateBuffer( Cursor_Width, Cursor_Height, 1 ); ThrowIfMemFail_( bw ); //bw->AssignPalette( oneBitTable ); bw->CopyFromRawData( (UInt8*) &(**h).data, BWCursor_RowBytes ); /************************************************** create the mask bitmap **************************************************/ mask = SUOffscreen::CreateBuffer( Cursor_Width, Cursor_Height, 1 ); ThrowIfMemFail_( bw ); mask->CopyFromRawData( (UInt8*) &(**h).mask, BWCursor_RowBytes ); /************************************************** and return stuff to the caller **************************************************/ *outBW = bw; *outMask = mask; *outHotSpot = (**h).hotSpot; } catch( ... ) { SUMiscUtils::DisposeHandle( h ); if ( bw ) delete ( bw ); if ( mask ) delete( mask ); throw; } SUMiscUtils::DisposeHandle( h ); }
void PTRecolorAction::DoIt() { if ( mTable ) { SUOffscreen *currentBuffer = mSettings.currentBuffer; mSettings.thePaintView->CopyToUndo(); mSettings.thePaintView->SelectNone(); /* create a new buffer the same size as the image but with a depth of 8-bits. use the specified color table as the color table. */ SInt32 width = currentBuffer->GetWidth(); SInt32 height = currentBuffer->GetHeight(); SUOffscreen *newBuffer = SUOffscreen::CreateBuffer( width, height, kRecolorDepth, mTable ); /* increase the inverse table size from 4 to 5 bits. this gives substantially better color matching. */ newBuffer->IncreaseInverseTableSize(); /* Copy the image to the 8-bit buffer to downsample the colors and then back to the original 32-bit one */ newBuffer->CopyFrom( currentBuffer ); currentBuffer->CopyFrom( newBuffer ); delete newBuffer; // update the canvas mSettings.theCanvas->DrawFrom( currentBuffer ); } this->PostAsAction(); }
/*=============================================== ChangeImageSize Note: Affects only the pixpat, _not_ the black & white pattern. ================================================*/ void PTPatternView::ChangeImageSize( SInt32 inWidth, SInt32 inHeight, Boolean inStretch ) { ThrowIf_( (inWidth < mMinImageWidth) || (inHeight < mMinImageHeight) ); ThrowIf_( (inWidth > mMaxImageWidth) || (inHeight > mMaxImageHeight) ); ThrowIf_( mResourceType != ImageType_PixPat ); ThrowIfNil_( mColorSample ); ThrowIfNil_( mCurrentImage ); SInt32 savedWidth = mPixPatWidth; // in case of error... SInt32 savedHeight = mPixPatHeight; Boolean changedSize = true; SUOffscreen *newBuffer = nil; Rect destR; try { /***************************************** create a new buffer -- same depth as current one, but new size *****************************************/ newBuffer = mCurrentImage->CreateSimilarOffscreen( false, inWidth, inHeight ); /***************************************** copy the image from the old buffer into the new one *****************************************/ if ( inStretch ) ::SetRect( &destR, 0, 0, inWidth, inHeight ); else ::SetRect( &destR, 0, 0, mCurrentImage->GetWidth(), mCurrentImage->GetHeight() ); newBuffer->CopyFrom( mCurrentImage, &destR ); /***************************************** resize the pixpat sample pane *****************************************/ this->ResizeSampleWell( inWidth, inHeight ); changedSize = true; /***************************************** keep track of the changed size. do this before SetImage() because it may call GetZoomFactor. *****************************************/ mPixPatWidth = inWidth; mPixPatHeight = inHeight; /***************************************** set the current buffer -- this can trigger all sorts of things (canvas resize, etc) *****************************************/ this->SetImage( newBuffer, PTResize_All, redraw_Later ); /***************************************** change the sample pane's buffer. Notes: (1) The sample pane will own the buffer after this call (don't delete it) (2) The previous sample pane buffer will be saved away by the PTResizer object *****************************************/ mColorSample->SetRawBuffer( newBuffer ); } catch( ... ) { /* restore things to the way they were before we were called */ mPixPatWidth = savedWidth; mPixPatHeight = savedHeight; if ( changedSize ) this->ResizeSampleWell( mPixPatWidth, mPixPatHeight ); delete newBuffer; throw; } }
/*================================== ParseColorPattern ===================================*/ void PTPatternView::ParseColorPattern( Handle inPattern, SUOffscreen **outColor, SUOffscreen **outBW ) { // See IM V-79 for details StSaveGWorld save1; StHandleLocker save2( inPattern ); PixPatPtr p = (PixPatPtr) *inPattern; CTabHandle theTable = nil; SUOffscreen *tempColorBuffer = nil, *colorBuffer = nil, *bwBuffer = nil; try { if ( p->patType != 1 ) LException::Throw( err_InvalidImageFormat ); /******************************************* first handle the b&w pattern ********************************************/ bwBuffer = this->BWPatternToOffscreen( p->pat1Data ); /******************************************* now the color pattern ********************************************/ PixMapPtr theMap = (PixMapPtr)( *inPattern + (SInt32) p->patMap ); UInt8 * theData = (UInt8*)( *inPattern + (SInt32) p->patData ); SInt32 depth = theMap->pixelSize; SInt32 width = theMap->bounds.right - theMap->bounds.left; SInt32 height = theMap->bounds.bottom - theMap->bounds.top; SInt32 rowBytes = theMap->rowBytes & 0x3FFF; // clear flags if ( (depth != 1) && (depth != 2) && (depth != 4) && (depth != 8) ) LException::Throw( err_InvalidImageDepth ); if ( (width <= 3) || (width > 64) || (height <= 3) || (height > 64) ) LException::Throw( err_InvalidImageSize ); theTable = SUColorUtils::NewColorTableFromPtr( depth, (UInt8*)( *inPattern + (SInt32)theMap->pmTable) ); tempColorBuffer = SUOffscreen::CreateBuffer( width, height, depth, theTable ); tempColorBuffer->CopyFromRawData( theData, rowBytes ); // now switch to a 32-bit buffer colorBuffer = SUOffscreen::CreateBuffer( width, height, 32 ); colorBuffer->CopyFrom( tempColorBuffer ); } catch( ... ) { delete colorBuffer; delete bwBuffer; delete tempColorBuffer; if ( theTable ) ::DisposeCTable( theTable ); throw; } *outColor = colorBuffer; *outBW = bwBuffer; if ( theTable ) ::DisposeCTable( theTable ); delete tempColorBuffer; }
/*=============================================== InitializeFromResource ================================================*/ void PTPatternView::InitializeFromResource( RFMap *inMap, ResType inResType, ResIDT inResID ) { StSaveGWorld aSaver; StSaveResFile aSaver2; SUOffscreen *colorImage = nil, *bwImage = nil; Handle h = nil; try { mResourceType = inResType; /************************************************** get the raw resource handle **************************************************/ RFResource *theRes = inMap->FindResource( inResType, inResID, false ); ThrowIfNil_( theRes ); h = theRes->GetResData(); ThrowIfNil_( h ); /************************************************** draw the pattern(s) into bitmaps **************************************************/ switch( inResType ) { case ImageType_PixPat: this->ParseColorPattern( h, &colorImage, &bwImage ); mAllowImageResizing = true; break; case ImageType_Pattern: this->ParseBWPattern( h, &bwImage ); break; default: LException::Throw( err_UnknownDataType ); } /************************************************** resize the sample well if the color pattern is bigger than 8x8 **************************************************/ if ( colorImage ) { SInt32 width = colorImage->GetWidth(); SInt32 height = colorImage->GetHeight(); // save these _now_ because SetImage() will trigger a call to // GetZoomFactor() mPixPatWidth = width; mPixPatHeight = height; this->ResizeSampleWell( width, height ); this->SetImage( colorImage, PTResize_All, redraw_Later ); mColorSample->SetBuffer( colorImage, redraw_Dont ); colorImage = nil; // because it belongs to the sample pane now mColorSample->SetTarget( true, redraw_Dont ); mCurrentSamplePane = mColorSample; } else { this->SetImage( bwImage, PTResize_All, redraw_Later ); mCurrentSamplePane = mBWSample; mBWSample->SetTarget( true, redraw_Dont ); } mBWSample->SetBuffer( bwImage, redraw_Dont ); bwImage = nil; // because it belongs to the sample pane now } catch( ... ) { delete( colorImage ); delete( bwImage ); SUMiscUtils::DisposeHandle( h ); throw; } SUMiscUtils::DisposeHandle( h ); }
/*==================================== InitializeOneMember =====================================*/ Boolean PTFamilyView::InitializeOneMember( RFMap *inMap, ResType inResType, ResIDT inResID, SInt32 inWidth, SInt32 inHeight, SInt32 inDepth, SInt32 inOffset, SInt32 inRowBytes, PaneIDT inSamplePaneID, Boolean /* inIsMask */ ) { StSaveResFile aSaver; SUOffscreen *theBuffer = nil; Boolean isUsed = false; /* icon families use the standard color table for their depth */ CTabHandle theTable = SUColorUtils::GetColorTable( inDepth ); try { /****************************************** create the offscreen buffer *******************************************/ theBuffer = SUOffscreen::CreateBuffer( inWidth, inHeight, inDepth, theTable ); /****************************************** if we have a resource, load the data into the offscreen buffer *******************************************/ RFResource *theResource = inMap->FindResource( inResType, inResID, false ); if ( theResource ) { Handle h = theResource->GetResData(); if ( h ) { ::HLock( h ); theBuffer->CopyFromRawData( (UInt8*) *h + inOffset, inRowBytes ); SUMiscUtils::DisposeHandle( h ); isUsed = true; } } /****************************************** initialize the sample pane *******************************************/ PTDraggableTargetBox *thePane = (PTDraggableTargetBox*) this->FindPaneByID( inSamplePaneID ); ThrowIfNil_( thePane ); mSamplePaneList[ mNumSamplePanes++ ] = thePane; thePane->SetUsedFlag( isUsed, redraw_Dont ); // true if the resource exists thePane->SetBuffer( theBuffer, redraw_Dont ); theBuffer = nil; // so we don't delete it below } catch( ... ) { if ( theBuffer ) delete theBuffer; if ( theTable ) ::DisposeCTable( theTable ); throw; } if ( theTable ) ::DisposeCTable( theTable ); return( isUsed ); }
/*=============================================== ParseColorCursor Note: See description of CCrsr structure above. ================================================*/ void PTCursorView::ParseColorCursor( RFMap *inMap, ResIDT inResID, SUOffscreen **outColor, SUOffscreen **outBW, SUOffscreen **outMask, Point *outHotSpot ) { PixMapPtr cMap; SInt32 depth, width, height; CTabHandle theTable = nil; SUOffscreen *cBuffer = nil, *bwBuffer = nil, *maskBuffer = nil, *tempBuffer = nil; CCrsrHandle h = nil; UInt8 *p; try { /************************************************** get the raw resource handle -- this isn't the usual way of loading color cursors, so the fields -- will be raw and not filled in (as when GetCCursor is used) **************************************************/ RFResource *theRes = inMap->FindResource( ImageType_ColorCursor, inResID, false ); ThrowIfNil_( theRes ); h = (CCrsrHandle) theRes->GetResData(); ThrowIfNil_( h ); ::HLock( (Handle) h ); p = (UInt8*) *h; /************************************************** validate the handle a little bit **************************************************/ if ( (UInt16) (**h).crsrType != (UInt16) 0x8001 ) // cast *is* needed - crsrType is signed LException::Throw( err_InvalidImageFormat ); if ( ::GetHandleSize( (Handle) h ) < static_cast<Size>(sizeof(CCrsr)) ) LException::Throw( err_CorruptedResource ); /************************************************** get some info about the cursor **************************************************/ cMap = (PixMapPtr) (p + (SInt32) (**h).crsrMap); if ( cMap->pixelType != 0 ) LException::Throw( err_InvalidImageFormat ); width = cMap->bounds.right - cMap->bounds.left; height = cMap->bounds.bottom - cMap->bounds.top; depth = cMap->pixelSize; if ( (width != Cursor_Width) || (height != Cursor_Height) ) LException::Throw( err_InvalidImageSize ); if ( (depth != 1) && (depth != 2) && (depth != 4) && (depth != 8) ) LException::Throw( err_InvalidImageDepth ); /************************************************** create the bwBuffer and maskBuffer **************************************************/ bwBuffer = SUOffscreen::CreateBuffer( Cursor_Width, Cursor_Height, 1 ); ThrowIfMemFail_( bwBuffer ); bwBuffer->CopyFromRawData( (UInt8*) &(**h).crsr1Data, BWCursor_RowBytes ); maskBuffer = SUOffscreen::CreateBuffer( Cursor_Width, Cursor_Height, 1 ); ThrowIfMemFail_( maskBuffer ); maskBuffer->CopyFromRawData( (UInt8*) &(**h).crsrMask, BWCursor_RowBytes ); /************************************************** allocate the color table. note that the resource may have a minimal color table and QuickDraw doesn't work with anything but a full-sized one. **************************************************/ if ( cMap->pmTable == 0 ) // probably won't happen, but can't hurt to check theTable = SUColorUtils::NewColorTableByDepth( depth ); else theTable = SUColorUtils::NewColorTableFromPtr( depth, p + (SInt32) cMap->pmTable ); /************************************************** allocate the color bitmap **************************************************/ tempBuffer = SUOffscreen::CreateBuffer( width, height, depth, theTable ); SInt32 rowBytes = cMap->rowBytes & 0x3FFF; // clear flag bits if ( rowBytes != 0 ) tempBuffer->CopyFromRawData( p + (SInt32) (**h).crsrData, rowBytes ); /************************************************** now switch it to a 32-bit offscreen **************************************************/ cBuffer = SUOffscreen::CreateBuffer( width, height, 32 ); cBuffer->CopyFrom( tempBuffer ); } catch( ... ) { delete maskBuffer; delete bwBuffer; delete cBuffer; delete tempBuffer; if ( theTable ) ::DisposeCTable( theTable ); SUMiscUtils::DisposeHandle( h ); } // return buffers and info to the caller *outColor = cBuffer; *outBW = bwBuffer; *outMask = maskBuffer; *outHotSpot = (**h).crsrHotSpot; // don't need the color table because the offscreen makes a copy of it if ( theTable ) ::DisposeCTable( theTable ); SUMiscUtils::DisposeHandle( h ); delete tempBuffer; }