#include <frameops.h>
Inheritance diagram for OpGrabAllFrames:
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) |
Definition at line 610 of file frameops.h.
|
Definition at line 615 of file frameops.h.
|
|
|
|
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 }
|
|
Tries to grab the selected animation frame (i.e. layer).
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 }
|
|
Definition at line 621 of file frameops.h. |