OpGrabAllFrames Class Reference

Performs an operation to grab all of the frame layers and preview them. More...

#include <frameops.h>

Inheritance diagram for OpGrabAllFrames:

OpGrabFrame Operation MessageHandler ListItem CCObject SimpleCCObject OpSaveAnimatedGIF OpBrowserPreview List of all members.

Public Member Functions

 OpGrabAllFrames ()
void Do (OpDescriptor *pOpDesc)
 Tries to grab the selected animation frame (i.e. layer).

Static Public Attributes

static BOOL ms_ForceRefreshOfAllFrames = FALSE

Protected Member Functions

void CreateGlobalPalette (DWORD NumColsInPalette, BOOL RegenerateAllFrames)

Private Member Functions

 CC_DECLARE_DYNCREATE (OpGrabAllFrames)

Detailed Description

Performs an operation to grab all of the frame layers and preview them.

Author:
Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
Date:
23/4/97
See also:
-

Definition at line 610 of file frameops.h.


Constructor & Destructor Documentation

OpGrabAllFrames::OpGrabAllFrames  )  [inline]
 

Definition at line 615 of file frameops.h.

00615 { } // nothing yet 


Member Function Documentation

OpGrabAllFrames::CC_DECLARE_DYNCREATE OpGrabAllFrames   )  [private]
 

void OpGrabAllFrames::CreateGlobalPalette DWORD  NumColsInPalette,
BOOL  RegenerateAllFrames
[protected]
 

Definition at line 3029 of file frameops.cpp.

03030 {
03031     ERROR3IF(!m_pBitmapFilter, "No bitmap filter to use when generating global palette");
03032     if (!m_pBitmapFilter)
03033         return;
03034 
03035     PaletteOptimiser* pPalOpt = new PaletteOptimiser();
03036     if (!pPalOpt)
03037         return;
03038     pPalOpt->Initialise();
03039 
03040     // Go through all the frame layers in the spread and export them
03041     KernelBitmap * pBitmap = NULL;
03042     Layer* pCurrentLayer = NULL;
03043 
03044     // Set the filter to generate preview bitmaps
03045     m_pBitmapFilter->SetGrabMode(GrabFrameFilter::GRABMODE_PREVIEW);
03046 
03047     pBitmap = NULL;
03048     pCurrentLayer = m_pSpread->FindFirstFrameLayer();
03049 
03050     while (pCurrentLayer != NULL)
03051     {
03052         // see if the user has hidden the frame
03053         if (!pCurrentLayer->IsPseudoFrame() || pCurrentLayer->IsHiddenFrame())
03054         {
03055             // It is either an invalid frame or it is hidden. In both cases but especially
03056             // the second we should ensure that if there is a generated bitmap then we
03057             // vape it as it is now out of date.
03058             pCurrentLayer->SetGeneratedBitmap(NULL);
03059 
03060             // Move to the next bitmap in the animation
03061             pCurrentLayer = pCurrentLayer->FindNextFrameLayer();
03062 
03063             // Go to the next frame
03064             continue;
03065         }
03066 
03067         // Set up the visibility of the other layers using this layer
03068         // as the new temporary and acting active layer
03069         FrameSGallery::FixOtherLayersFromActive(pCurrentLayer);
03070         // This is the layer that we are adding to the global palette
03071         m_pLayer = pCurrentLayer;
03072 
03073         // Render a bitmap of the entire image being exported
03074         KernelBitmap* pTestBitmap=NULL;
03075         m_pBitmapFilter->DoCreateBitmap(this, m_pDocument, &pTestBitmap);
03076 
03077         // not enough memory? or no content worth talking about then give up!
03078         if (!pTestBitmap || !pTestBitmap->GetActualBitmap())
03079         {
03080             FailAndExecute();
03081             End();
03082             return;
03083         }
03084 
03085         // We need to pass Gavin a 32bbp bitmap with an empty channel (rather than an
03086         // alpha channel).  Lets quickly create one (I am sure this is not the best way
03087         // of doing this but it will do for now).
03088         UINT32 nPixels = pTestBitmap->GetActualBitmap()->GetBitmapSize() / 3;
03089         RGBQUAD* pNewBitmap = new RGBQUAD[nPixels];
03090         UINT32 width    = pTestBitmap->GetActualBitmap()->GetBitmapInfoHeader()->biWidth;
03091         UINT32 height   = pTestBitmap->GetActualBitmap()->GetBitmapInfoHeader()->biHeight;
03092         BYTE* pOldBitmapBytes = (BYTE*)pTestBitmap->GetActualBitmap()->GetBitmapBits();
03093         UINT32 bytesPerLine = BYTESPERLINE(width, 24);
03094         for (UINT32 y = 0; y < height; ++y)
03095             for (UINT32 x = 0; x < width; x++)
03096             {
03097                 pNewBitmap[y * width + x].rgbBlue       = pOldBitmapBytes[bytesPerLine * y + x * 3 + 0];
03098                 pNewBitmap[y * width + x].rgbGreen      = pOldBitmapBytes[bytesPerLine * y + x * 3 + 1];
03099                 pNewBitmap[y * width + x].rgbRed        = pOldBitmapBytes[bytesPerLine * y + x * 3 + 2];
03100                 pNewBitmap[y * width + x].rgbReserved   = 0;
03101             }
03102 
03103         // add the stats to the palette optimiser
03104         pPalOpt->AddStats(pNewBitmap, nPixels);
03105 
03106         delete pNewBitmap;
03107         delete pTestBitmap;
03108 
03109         // Move to the next bitmap in the animation
03110         pCurrentLayer = pCurrentLayer->FindNextFrameLayer();
03111     }
03112 
03113     // set the global palette
03114     pPalOpt->SnapToBrowserPalette(0);
03115     pPalOpt->SnapToPrimaries(1);
03116     pPalOpt->AddSystemColours((m_pSpread->GetSpreadAnimPropertiesParam().GetUseSystemCols() == TRUE));
03117     pPalOpt->UseBrowserPalette(0);
03118     pPalOpt->SetFast(TRUE);
03119 
03120     INT32 ColoursToOptimise = camMax(2, NumColsInPalette-1);
03121 
03122     // tell the optimiser that we have finished gathering the stats
03123     pPalOpt->GenPalette(ColoursToOptimise);
03124 
03125     LOGPALETTE * pGlobalPal = DIBUtil::AllocateLogPalette(ColoursToOptimise + 1);
03126 
03127     pGlobalPal->palNumEntries = ColoursToOptimise;
03128 
03129     // get the optimised palette from the optimser
03130     pPalOpt->GetPalette( pGlobalPal, ColoursToOptimise);
03131 
03132      // we want to add a transparent colour to this palette
03133     pGlobalPal->palNumEntries = camMin(255,pGlobalPal->palNumEntries+1);
03134 
03135     // the first entry in the palette is special it should be the background colour as it will
03136     // be what is visible if the background is not transparent so swap the first entry into
03137     // the last and set the last
03138     pGlobalPal->palPalEntry[ pGlobalPal->palNumEntries-1 ].peRed    = pGlobalPal->palPalEntry[ 0 ].peRed;
03139     pGlobalPal->palPalEntry[ pGlobalPal->palNumEntries-1 ].peGreen  = pGlobalPal->palPalEntry[ 0 ].peGreen;
03140     pGlobalPal->palPalEntry[ pGlobalPal->palNumEntries-1 ].peBlue   = pGlobalPal->palPalEntry[ 0 ].peBlue;
03141     pGlobalPal->palPalEntry[ pGlobalPal->palNumEntries-1 ].peFlags  = 0;
03142 
03143     DocColour dcol = Page::GetPageColour();
03144     INT32 r = 255, g = 255, b = 255;
03145     dcol.GetRGBValue(&r,&g,&b);
03146 
03147     pGlobalPal->palPalEntry[ 0 ].peRed      = (BYTE)r;
03148     pGlobalPal->palPalEntry[ 0 ].peGreen    = (BYTE)g;
03149     pGlobalPal->palPalEntry[ 0 ].peBlue     = (BYTE)b;
03150     pGlobalPal->palPalEntry[ 0 ].peFlags    = 255; // the transp entry - not renderable
03151 
03152     // remove the optimiser
03153     delete pPalOpt;
03154 
03155     // save this global palette for later
03156     m_pBitmapFilter->SetGlobalOptimisedPalette(pGlobalPal);
03157     m_pBitmapFilter->AlterPaletteContents(pGlobalPal);
03158 
03159     // Undo our change to the filter
03160     m_pBitmapFilter->SetGrabMode(GrabFrameFilter::GRABMODE_FOROUTPUT);
03161 }

void OpGrabAllFrames::Do OpDescriptor pOpDesc  )  [virtual]
 

Tries to grab the selected animation frame (i.e. layer).

Author:
Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
Date:
22/4/97
Parameters:
OpDescriptor (unused) [INPUTS]
- [OUTPUTS]
Returns:
-

Errors: -

See also:
-

Reimplemented from OpGrabFrame.

Definition at line 3178 of file frameops.cpp.

03179 {
03180     // Get useful data and set up items before starting the grab process
03181     if (!StartGrab())
03182     {
03183         // We failed to grab the frame
03184         FailAndExecute();
03185         End();
03186         return; 
03187     } 
03188 
03189     // If required, allow the op to get a filename from the user.
03190     // This also allows them access to the options via the button on the save dialog box.
03191     // This is why we must do this first rather than after we have generated the frames.
03192     if (!GetFileNameFromUser())
03193     {
03194         // We failed to grab the frame
03195         FailAndExecute();
03196         End();
03197         return; 
03198     } 
03199 
03200     // Get our static pointer to the Preview Dialog.
03201     PreviewDialog* pPreviewDlg = PreviewDialog::GetPreviewDialog();
03202     // If the preview dialog is already open, find the selected frame layer.
03203     BOOL PlayAnimation = TRUE;
03204     if (pPreviewDlg)
03205     {
03206         // Note the current state of the playing
03207         PlayAnimation = pPreviewDlg->GetPlayAnimation();
03208         // Force the dialog into stop mode
03209         pPreviewDlg->StopPreviewing();
03210     }
03211 
03212     // Create a special Bitmap filter, that creates a bitmap
03213     // and puts it in the tree   
03214     ERROR3IF(m_pBitmapFilter != NULL,"Already have a pBitmapFilter!");
03215     m_pBitmapFilter = new GrabFrameFilter();
03216     if (m_pBitmapFilter == NULL)
03217     {
03218         // We failed to grab the frame
03219         // Try and put back the selection that we recorded at the start
03220         PutBackTheSelection();
03221         FailAndExecute();
03222         End();
03223         return; 
03224     }
03225 
03226     // Get the stored cliprect from the spread.
03227     // This may be blank if the frames have not been generated before.
03228     DocRect OldBoundingRect = m_pSpread->GetAnimationBoundingRect();
03229     // Get the filter to work out the new rectangle 
03230     m_pBitmapFilter->SetUpClippingRectangleForExport(m_pSpread, DRAWING);
03231     DocRect NewBoundingRect = m_pBitmapFilter->GetClipRect();
03232     // Save away the new bounding rectangle
03233     m_pSpread->SetAnimationBoundingRect(NewBoundingRect);
03234     m_ExportParams.SetAnimationBoundingRect(NewBoundingRect);
03235     // If they are different then we must regenerate all frames
03236     BOOL RegenerateAllFrames = ms_ForceRefreshOfAllFrames; // used to be = FALSE (sjk)
03237     ms_ForceRefreshOfAllFrames = FALSE; // have used the force refresh
03238 
03239     if (NewBoundingRect != OldBoundingRect)
03240         RegenerateAllFrames = TRUE;
03241 
03242     Quality OldQuality = m_pSpread->GetAnimationQuality();
03243 
03244     // AMB doesn't understand what the following lines were meant to do. Quality
03245     // is a linear scale. And in any case this doesn't compile (unsurprisingly)
03246     // Quality NewQuality = m_pView->RenderQuality;
03247     // NewQuality.Antialias = Quality::FullAntialias;
03248     // NewQuality.Transparency = Quality::FullTransparency;
03249     Quality NewQuality(Quality::QualityMax);
03250 
03251     // Save away the new quality
03252     m_pSpread->SetAnimationQuality(NewQuality);
03253     if (NewQuality != OldQuality)
03254         RegenerateAllFrames = TRUE;
03255 
03256     // Check if somebody has edited the page background layer. If they have then
03257     // regenerate all frames
03258     Layer * pPageBackground = m_pSpread->FindFirstPageBackgroundLayer();
03259     if (pPageBackground)
03260     {
03261         if (pPageBackground->IsEdited())
03262             RegenerateAllFrames = TRUE;
03263     }
03264 
03265     // If the user has a global optimised palette and they have edited one layer
03266     // then we have really no choice but to always regenerate all frames
03267     // as the user may have changed something that will affect the colours in the palette.
03268     //DITHER            Dither;
03269     WEB_PALETTE     WebPalette          = PAL_GLOBAL;
03270     PALETTE_COLOURS ColoursPalette      = PALCOL_BROWSER;
03271     DWORD           NumColsInPalette;
03272     m_pSpread->GetAnimationColours(NULL, &WebPalette, &ColoursPalette, &NumColsInPalette, NULL);
03273     if (WebPalette == PAL_GLOBAL && ColoursPalette == PALCOL_OPTIMIZED)
03274     {
03275         // check to see if one of the frame layers has been edited
03276         Layer * pTestLayer = m_pSpread->FindFirstFrameLayer();
03277         while (pTestLayer)
03278         {
03279             if (pTestLayer->IsEdited() && pTestLayer->IsPseudoFrame())
03280             {
03281                 // Somebody has edited one of the frames so we must regenerate all
03282                 RegenerateAllFrames = TRUE;
03283                 break;
03284             }
03285             pTestLayer = pTestLayer->FindNextFrameLayer();
03286         }
03287     }
03288 
03289     // Check all the layers to see if they contain a single bitmap which we can use
03290     // instead of generating one.
03291     // This will mark all valid single bitmaps using the reference in the layer
03292     if (!CheckAllForSingleBitmaps(m_pSpread, m_pBitmapFilter))
03293     {
03294         // Try and put back the selection that we recorded at the start
03295         PutBackTheSelection();
03296         delete m_pBitmapFilter;
03297         m_pBitmapFilter = NULL;
03298         // We failed to clean up after grabbing the frame
03299         FailAndExecute();
03300         End();
03301         return; 
03302     } 
03303     
03304     // As this will affect us during grabbing, we should force it into the known
03305     // non-interferring state
03306     BOOL CurrentVisEdState = Layer::ActiveLayerVisibleAndEditable;
03307     Layer::ActiveLayerVisibleAndEditable = FALSE;
03308     // The all visible flag will also do this for us. 
03309     Document* pDoc = m_pSpread->FindParentDocument();
03310     BOOL CurrentAllVisibleState = FALSE;
03311     if (pDoc != NULL)
03312     {
03313         CurrentAllVisibleState = pDoc->IsAllVisible();
03314         pDoc->SetAllVisible(FALSE);
03315     }
03316 
03317     // SMFIX Do we need a global palette for all the frames?
03318     BOOL CreatingGlobalPalette = (WebPalette == PAL_GLOBAL && ColoursPalette == PALCOL_OPTIMIZED);
03319 
03320 
03321     // if we are having a global palette then get an optimiser to create one from the bitmaps
03322     if (CreatingGlobalPalette)
03323         CreateGlobalPalette(NumColsInPalette, RegenerateAllFrames);
03324 
03325     // Go through all the frame layers in the spread and export them
03326     KernelBitmap * pBitmap = NULL;
03327     Layer* pCurrentLayer = NULL;
03328 
03329     // Set the filter to generate output bitmaps
03330     m_pBitmapFilter->SetGrabMode(GrabFrameFilter::GRABMODE_FOROUTPUT);
03331 
03332     // go round once unless we are creating a global palette then go round twice
03333     pBitmap = NULL;
03334     pCurrentLayer = m_pSpread->FindFirstFrameLayer();
03335 
03336     while (pCurrentLayer != NULL)
03337     {
03338         // see if the user has hidden the frame
03339         if (!pCurrentLayer->IsPseudoFrame() || pCurrentLayer->IsHiddenFrame())
03340         {
03341             // It is either an invalid frame or it is hidden. In both cases but especially
03342             // the second we should ensure that if there is a generated bitmap then we
03343             // vape it as it is now out of date.
03344             pCurrentLayer->SetGeneratedBitmap(NULL);
03345 
03346             // Move to the next bitmap in the animation
03347             pCurrentLayer = pCurrentLayer->FindNextFrameLayer();
03348 
03349             // Go to the next frame
03350             continue;
03351         }
03352 
03353         // Set up the visibility of the other layers using this layer
03354         // as the new temporary and acting active layer
03355         FrameSGallery::FixOtherLayersFromActive(pCurrentLayer);
03356             
03357         // This is where the real work starts!  
03358         // This is the layer that we want grabbing
03359         m_pLayer = pCurrentLayer;
03360 
03361         // Check to see if we have a single bitmap on the layer which is stored
03362         // in a NodeBitmap at a 1:1 scale and is 8bpp or less and the palette matches
03363         // the present options.
03364         // If it passes all these tests, then set pBitmap to be that bitmap.
03365         //if (!CheckIfSingleBitmap(pCurrentLayer, &pBitmap))
03366         // If there is a referenced bitmap then we can use this instead of generating one
03367         pBitmap = m_pLayer->GetReferencedBitmap();
03368         if (pBitmap == NULL)
03369         {
03370             // Look to see if we have a bitmap for this layer
03371             KernelBitmap * pOldBitmap = pCurrentLayer->GetGeneratedBitmap(); 
03372             
03373             // Look to see if any visible foreground layers below this one have
03374             // been edited
03375             BOOL LayersBelowEdited = FALSE;
03376             // Only check if we are not already forced to regnerate all frames
03377             if (!RegenerateAllFrames)
03378             {
03379                 Layer * pTestLayer = pCurrentLayer;
03380                 pTestLayer = pTestLayer->FindPrevFrameLayer();
03381                 while (pTestLayer)
03382                 {
03383                     // Dont disclude hidden frames as they can affect the make up of the current frame
03384                     if (pTestLayer->IsEdited() && pTestLayer->IsPseudoFrame() &&
03385                         pTestLayer->IsVisible())
03386                     {
03387                         LayersBelowEdited = TRUE;
03388                         break;
03389                     }
03390                     pTestLayer = pTestLayer->FindPrevFrameLayer();
03391                 }
03392             }
03393 
03394             // we are getting the bitmaps themselves
03395             // check that the quality it was last captured at was the same as the current quality
03396             Quality CurrentFrameQuality = pCurrentLayer->GetCaptureQuality();
03397 
03398             // For a number of reasons we may need to regenerate the bitmap for this frame
03399             // If nay are true then regenerate, otherwise reuse the old one
03400             if (pOldBitmap == NULL || LayersBelowEdited || RegenerateAllFrames ||
03401                 pCurrentLayer->IsEdited() || CurrentFrameQuality != NewQuality)
03402             {
03403                 // Turn this frame into a bitmap
03404                 pBitmap = GrabTheFrame();
03405             }
03406             else
03407             {
03408                 // Reuse the old bitmap that was generated
03409                 pBitmap = pOldBitmap;
03410 
03411                 // test to see that this bitmap uses the correct palette if required
03412                 // otherwise we will have to grab it anyway
03413                 if (CreatingGlobalPalette)
03414                 {
03415                     // compare palettes
03416                     LOGPALETTE * pGlobalPalette = m_pBitmapFilter->GetGlobalOptimisedPalette();
03417                     if (!pBitmap->GetActualBitmap()->ArePalettesTheSame(pGlobalPalette, 0))
03418                     {
03419                         // NOTE:  This happens when the preview window has just gone and generated a bitmap
03420                         // using a locally optimal palette rather than our globally optimal palette and in
03421                         // the process it has replaced our cache version with its dodgy bitmap.
03422                         TRACEALL( _T("Bum bitmap passed to us with wrong palette, grab a fresh one"));
03423                         pBitmap = GrabTheFrame();
03424                     }
03425                 }
03426             }
03427         }
03428 
03429         BOOL bAddLayer = pBitmap != 0;
03430         if (bAddLayer)
03431         {
03432             // We have a bitmap so add this layer pairing to our export list
03433             bAddLayer = m_ExportParams.AddLayerAndBitmap(pCurrentLayer, pBitmap);
03434         }
03435 
03436         if (!bAddLayer)
03437         {
03438             // We failed to grab the frame or failed to add it to our export list
03439 
03440             // Put back the active layer's visibilty and selection
03441             Layer::ActiveLayerVisibleAndEditable = CurrentVisEdState;
03442             FrameSGallery::FixOtherLayersFromActive(m_pLayer);
03443             // Try and put back the selection that we recorded at the start
03444             PutBackTheSelection();
03445             FailAndExecute();
03446             End();
03447             return; 
03448         } 
03449 
03450         //TRACEUSER( "SimonK", _T("colours in frame %d\n"), pBitmap->GetNumPaletteEntries());
03451 
03452         // Note the capture quality that the frame was captured at but only if we worked correctly
03453         pCurrentLayer->SetCaptureQuality(NewQuality);
03454 
03455         // Move to the next bitmap in the animation
03456         pCurrentLayer = pCurrentLayer->FindNextFrameLayer();
03457     }
03458 
03459     // Put back the active layer's visibilty and selection
03460     Layer::ActiveLayerVisibleAndEditable = CurrentVisEdState;
03461 
03462     // Put back the all visible state
03463     if (pDoc != NULL)
03464         pDoc->SetAllVisible(CurrentAllVisibleState);
03465 
03466     Layer *pActiveLayer = m_pSpread->FindActiveLayer();
03467     if (pActiveLayer)
03468         FrameSGallery::FixOtherLayersFromActive(pActiveLayer);
03469 
03470     // Go and mark all layers as not edited now that we have finished the grabbing
03471     // process
03472     Layer* pLayer = m_pSpread->FindFirstFrameLayer();
03473     while (pLayer != NULL)
03474     {
03475         // This is just as a double check
03476         if (pLayer->IsPseudoFrame())
03477         {
03478             // Clear the edited flag on the layer
03479             pLayer->SetEdited(FALSE);
03480 #ifdef _DEBUG
03481             // Tell the frame gallery to update its display of the frame
03482             BROADCAST_TO_ALL(LayerMsg(pLayer, LayerMsg::REDRAW_LAYER));
03483 #endif
03484         }
03485 
03486         // Move to the next frame layer in the animation
03487         pLayer = pLayer->FindNextFrameLayer();
03488     }
03489 
03490     // If we found a page background layer above, now mark it as not edited
03491     if (pPageBackground)
03492         pPageBackground->SetEdited(FALSE);
03493 
03494     // Clean up after the grabbing process
03495     if (!EndGrab())
03496     {
03497         // We failed to clean up after grabbing the frame
03498         delete m_pBitmapFilter;
03499         m_pBitmapFilter = NULL;
03500         FailAndExecute();
03501         End();
03502         return; 
03503     } 
03504 
03505 
03506     // Grab all frames should usually play the animation.
03507     // If the preview dialog is open and in stop mode then it should continue in stop mode.
03508     // In this case we should have noted this before calling stop at the start of this function
03509     // So up the play state we noted earlier before we preview
03510     PreviewDialog * pPreviewDialog = PreviewDialog::GetPreviewDialog();
03511     INT32 CurrentFrame = 0;
03512     if (pPreviewDialog != NULL)
03513     {
03514         pPreviewDialog->SetPlayAnimation(PlayAnimation);
03515         CurrentFrame = pPreviewDialog->GetCurrentItem();
03516     }
03517 
03518     // Fire up the preview dialog box with the bitmaps in our list
03519     if (!PreviewAnimation())
03520     {
03521         // We failed to preview the bitmap
03522         delete m_pBitmapFilter;
03523         m_pBitmapFilter = NULL;
03524         FailAndExecute();
03525         End();
03526         return; 
03527     } 
03528 
03529     // If the dialog is still there then select the new frame to be displayed
03530     // Default is frame 0 so only do it if the requested item is different to this
03531     pPreviewDialog = PreviewDialog::GetPreviewDialog();
03532     if (pPreviewDialog && CurrentFrame != 0)
03533         pPreviewDialog->SelectCurrentFrame(CurrentFrame);
03534 
03535     // remove the filter as we have no more use for it
03536     delete m_pBitmapFilter;
03537     m_pBitmapFilter = NULL;
03538     
03539     End(); 
03540     return;
03541 }


Member Data Documentation

BOOL OpGrabAllFrames::ms_ForceRefreshOfAllFrames = FALSE [static]
 

Definition at line 621 of file frameops.h.


The documentation for this class was generated from the following files:
Generated on Sat Nov 10 03:58:15 2007 for Camelot by  doxygen 1.4.4