// This must be called before any frame-saving is attempted. void CAnimationExporter::CreateGif() { if(!g_canvas || !g_canvas->model || !g_canvas->model->animManager) { wxMessageBox(_T("Unable to create animated GIF!"), _T("Error") ); wxLogMessage(_T( "Error: Unable to created animated GIF. A required objects pointer was null!") ); Show(false); return ; } CxImage **gifImages = NULL; // Our pointer array of images // Reset the state of our GUI objects btnStart->Enable(false); btnCancel->Enable(false); cbGrey->Enable(false); cbTrans->Enable(false); cbDither->Enable(false); cbShrink->Enable(false); txtFrames->Enable(false); txtSizeX->Enable(false); txtSizeY->Enable(false); txtDelay->Enable(false); // Pause our rendering to screen so we can focus on making the animated image g_videoSetting.render = false; m_fAnimSpeed = g_canvas->model->animManager->GetSpeed(); // Save the old animation speed g_canvas->model->animManager->SetSpeed(1.0f); // Set it to the normal speed. m_iTotalAnimFrames = g_canvas->model->animManager->GetFrameCount(); wxString(txtFrames->GetValue() ).ToLong( (long*) &m_iTotalFrames); wxString(txtDelay->GetValue() ).ToLong( (long*) &m_iDelay); // will crash program - prevent this from happening if(m_iTotalFrames > m_iTotalAnimFrames) { wxMessageBox(_T( "Impossible to make a gif with more frames than the model animation.\nClosing gif exporter."), _T("Error") ); wxLogMessage(_T( "Error: Unable to make a gif with more frames than the model animation.") ); this->Show(false); return ; } if(m_iDelay < 1) { m_iDelay = 1; } if(m_iDelay > 100) { m_iDelay = 100; } m_iTimeStep = int(m_iTotalAnimFrames / m_iTotalFrames); // Total number of frames in the animation / total frames going into our exported animation image if(m_bShrink) { wxString(txtSizeX->GetValue() ).ToLong( (long*) &m_iNewWidth); wxString(txtSizeY->GetValue() ).ToLong( (long*) &m_iNewHeight); // Just a minor check, final image size can not be smaller than 32x32 pixels. if(m_iNewWidth < 32 || m_iNewHeight < 32) { m_iNewWidth = 32; m_iNewHeight = 32; } } // CREATE OUR RENDERTOTEXTURE OBJECT // ------------------------------------------- // if either are supported use our 'RenderTexture' object. if(g_videoSetting.supportPBO || g_videoSetting.supportVBO) { g_canvas->rt = new RenderTexture(); if(!g_canvas->rt) { wxLogMessage(_T("Error: RenderToTexture object is null!") ); this->Show(false); return ; } g_canvas->rt->Init( (HWND)g_canvas->GetHandle(), 0, 0, g_videoSetting.supportFBO) ; m_iWidth = g_canvas->rt->nWidth; m_iHeight = g_canvas->rt->nHeight; g_canvas->rt->BeginRender(); } else { glReadBuffer(GL_BACK); int screenSize[4]; glGetIntegerv(GL_VIEWPORT, screenSize); // get the width/height of the canvas m_iWidth = screenSize[2]; m_iHeight = screenSize[3]; return ; } // Stop our animation g_canvas->model->animManager->Pause(true); g_canvas->model->animManager->Stop(); g_canvas->model->animManager->AnimateParticles(); // Size of our buffer to hold the pixel data m_iSize = m_iWidth * m_iHeight * 4; // (width*height*bytesPerPixel) // Create one frame to make our optimal colour palette from. unsigned char *buffer = new unsigned char[m_iSize]; gifImages = new CxImage *[m_iTotalFrames]; for(unsigned int i = 0; i < m_iTotalFrames; i++) { lblCurFrame->SetLabel(wxString::Format(_T("Current Frame: %i"), i) ); this->Refresh(); this->Update(); CxImage *newImage = new CxImage(0); g_canvas->RenderToBuffer(); glReadPixels(0, 0, m_iWidth, m_iHeight, GL_BGRA_EXT, GL_UNSIGNED_BYTE, buffer); newImage->CreateFromArray(buffer, m_iWidth, m_iHeight, 32, (m_iWidth *4) , false); // not needed due to the code just below, which fixes the issue with particles //g_canvas->model->animManager->SetTimeDiff(m_iTimeStep); //g_canvas->model->animManager->Tick(m_iTimeStep); if(g_canvas->root) { g_canvas->root->tick( (float)m_iTimeStep); } if(g_canvas->sky) { g_canvas->sky->tick( (float)m_iTimeStep); } #ifdef _WIN32 if(m_bGreyscale) { newImage->GrayScale(); } #endif //_WIN32 if(m_bShrink && m_iNewWidth != m_iWidth && m_iNewHeight != m_iHeight) { newImage->Resample(m_iNewWidth, m_iNewHeight, 2); } // if (Optimise) { if(!m_pPal) { CQuantizer q(256, 8); q.ProcessImage( (HANDLE)newImage->GetDIB() ); m_pPal = (RGBQUAD*)calloc(256 *sizeof(RGBQUAD), 1); //This creates our gifs optimised global colour palette q.SetColorTable(m_pPal); } newImage->DecreaseBpp(8, m_bDiffuse, m_pPal, 256); newImage->SetCodecOption(2); // for LZW compression if(m_bTransparent) { newImage->SetTransIndex(newImage->GetPixelIndex(0, 0) ); } newImage->SetFrameDelay(m_iDelay); gifImages[i] = newImage; // All the memory that we allocate for newImage gets cleared at the end } wxDELETEA(buffer); if(g_videoSetting.supportPBO || g_videoSetting.supportVBO) { g_canvas->rt->EndRender(); // Clear RenderTexture object. g_canvas->rt->Shutdown(); wxDELETE(g_canvas->rt); } // CREATE THE ACTUAL MULTI-IMAGE GIF ANIMATION // ------------------------------------------------------ // Create the file and write all the data // Open/Create the file that were going to save to FILE *hFile = NULL; hFile = fopen(m_strFilename.fn_str(), "wb"); // Set gif options CxImageGIF multiImage; multiImage.SetComment("Exported from WoW Model Viewer"); if(m_bTransparent) { multiImage.SetDisposalMethod(2); } else { multiImage.SetDisposalMethod(0); } multiImage.SetFrameDelay(m_iDelay); multiImage.SetCodecOption(2); // LZW multiImage.SetLoops(0); // Set the animation to loop indefinately. // Create/Compose the animated gif multiImage.Encode(hFile, gifImages, m_iTotalFrames, false); // ALL DONE, START THE CLEAN UP // -------------------------------------------------------- // Close file fclose(hFile); // Free the memory used by all the images to create the GIF for(unsigned int i = 0; i < m_iTotalFrames; i++) { gifImages[i]->Destroy(); wxDELETE(gifImages[i]); } wxDELETEA(gifImages); // Free memory used by the colour palette if(m_pPal) { free(m_pPal); m_pPal = NULL; } wxLogMessage(_T("Info: GIF Animation successfully created.") ); g_canvas->model->animManager->SetSpeed(m_fAnimSpeed); // Return the animation speed back to whatever it was previously set as g_canvas->model->animManager->Play(); Show(false); g_videoSetting.render = true; g_canvas->InitView(); }
UINT CFrameGrabThread::GrabFrames(){ #define TIMEBETWEENFRAMES 50.0 // could be a param later, if needed for (int i = 0; i!= nFramesToGrab; i++) imgResults[i] = NULL; try{ HRESULT hr; CComPtr<IMediaDet> pDet; hr = pDet.CoCreateInstance(__uuidof(MediaDet)); if (!SUCCEEDED(hr)) return 0; // Convert the file name to a BSTR. CComBSTR bstrFilename(strFileName); hr = pDet->put_Filename(bstrFilename); long lStreams; bool bFound = false; hr = pDet->get_OutputStreams(&lStreams); for (long i = 0; i < lStreams; i++) { GUID major_type; hr = pDet->put_CurrentStream(i); hr = pDet->get_StreamType(&major_type); if (major_type == MEDIATYPE_Video) { bFound = true; break; } } if (!bFound) return 0; double dLength = 0; pDet->get_StreamLength(&dLength); if (dStartTime > dLength) dStartTime = 0; long width = 0, height = 0; AM_MEDIA_TYPE mt; hr = pDet->get_StreamMediaType(&mt); if (mt.formattype == FORMAT_VideoInfo) { VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)(mt.pbFormat); width = pVih->bmiHeader.biWidth; height = pVih->bmiHeader.biHeight; // We want the absolute height, don't care about orientation. if (height < 0) height *= -1; } else { return 0; // Should not happen, in theory. } /*FreeMediaType(mt); = */ if (mt.cbFormat != 0){ CoTaskMemFree((PVOID)mt.pbFormat); mt.cbFormat = 0; mt.pbFormat = NULL; } if (mt.pUnk != NULL){ mt.pUnk->Release(); mt.pUnk = NULL; } /**/ long size; uint32 nFramesGrabbed; for (nFramesGrabbed = 0; nFramesGrabbed != nFramesToGrab; nFramesGrabbed++){ hr = pDet->GetBitmapBits(dStartTime + (nFramesGrabbed*TIMEBETWEENFRAMES), &size, NULL, width, height); if (SUCCEEDED(hr)) { // we could also directly create a Bitmap in memory, however this caused problems/failed with *some* movie files // when I tried it for the MMPreview, while this method works always - so I'll continue to use this one long nFullBufferLen = sizeof( BITMAPFILEHEADER ) + size; char* buffer = new char[nFullBufferLen]; BITMAPFILEHEADER bfh; memset( &bfh, 0, sizeof( bfh ) ); bfh.bfType = 'MB'; bfh.bfSize = nFullBufferLen; bfh.bfOffBits = sizeof( BITMAPINFOHEADER ) + sizeof( BITMAPFILEHEADER ); memcpy(buffer,&bfh,sizeof( bfh ) ); try { hr = pDet->GetBitmapBits(dStartTime+ (nFramesGrabbed*TIMEBETWEENFRAMES), NULL, buffer + sizeof( bfh ), width, height); } catch (...) { ASSERT(0); hr = E_FAIL; } if (SUCCEEDED(hr)) { // decode CxImage* imgResult = new CxImage(); imgResult->Decode((BYTE*)buffer, nFullBufferLen, CXIMAGE_FORMAT_BMP); delete[] buffer; if (!imgResult->IsValid()){ delete imgResult; break; } // resize if needed if (nMaxWidth > 0 && nMaxWidth < width){ float scale = (float)nMaxWidth / imgResult->GetWidth(); int nMaxHeigth = (int)(imgResult->GetHeight() * scale); imgResult->Resample(nMaxWidth, nMaxHeigth, 0); } // decrease bpp if needed if (bReduceColor){ RGBQUAD* ppal=(RGBQUAD*)malloc(256*sizeof(RGBQUAD)); if (ppal) { CQuantizer q(256,8); q.ProcessImage(imgResult->GetDIB()); q.SetColorTable(ppal); imgResult->DecreaseBpp(8, true, ppal); free(ppal); } } //CString TestName; //TestName.Format("G:\\testframe%i.png",nFramesGrabbed); //imgResult->Save(TestName,CXIMAGE_FORMAT_PNG); // done imgResults[nFramesGrabbed] = imgResult; } else{ delete[] buffer; break; } } } return nFramesGrabbed; } catch(...){ ASSERT(0); return 0; } }
////////////////////////////////////////////////////////////////////////////// // CMainFrame message handlers void CMainFrame::OnEditPaste() { CDemoDoc *NewDoc=(CDemoDoc*)((CDemoApp*)AfxGetApp())->demoTemplate->OpenDocumentFile(NULL); if (NewDoc) { if (OpenClipboard()) { HANDLE hData=NULL; if (hData = GetClipboardData(((CDemoApp*)AfxGetApp())->GetCF())){ //custom CxImage object CxImage *newima = new CxImage(); DWORD dwSize = GlobalSize(hData); if (dwSize) { BYTE *lpVoid = (BYTE *)GlobalLock(hData); newima->UnDump(lpVoid); GlobalUnlock(lpVoid); } NewDoc->image = newima; } else if (hData = GetClipboardData(CF_DIB)){ // check if bitmap CxImage *newima = new CxImage(); newima->CreateFromHANDLE(hData); NewDoc->image = newima; } else { #if CXIMAGE_SUPPORT_WMF if (hData = GetClipboardData(CF_ENHMETAFILE)) //check if metafile { HENHMETAFILE hMeta = (HENHMETAFILE)hData; ENHMETAHEADER emh; GetEnhMetaFileHeader(hMeta, sizeof(emh), &emh); int cx,cy; cx = (int)((emh.rclBounds.right - emh.rclBounds.left)/2.54); cy = (int)((emh.rclBounds.bottom - emh.rclBounds.top)/2.54); HDC hDC0 = ::GetDC(0); // screen dc HBITMAP hBitmap = CreateCompatibleBitmap(hDC0, cx, cy); HDC hDC = CreateCompatibleDC(hDC0); // memory dc compatible with screen ::ReleaseDC(0, hDC0); // don't need anymore. get rid of it. if (hDC && hBitmap){ RECT rc = {0,0,cx,cy}; int bpp = ::GetDeviceCaps(hDC, BITSPIXEL); HBITMAP hBitmapOld = (HBITMAP)SelectObject(hDC, hBitmap); // paint the background DWORD dwBack = RGB(255, 255, 255); //GetSysColor(COLOR_WINDOW); DWORD OldColor = SetBkColor(hDC, dwBack); ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL); SetBkColor(hDC, OldColor); // Play the Metafile into Memory DC BOOL bRet = PlayEnhMetaFile(hDC, hMeta, &rc); SelectObject(hDC, hBitmapOld); CxImage *newima = new CxImage(); if(bRet && newima->Create(cx, cy, bpp, CXIMAGE_FORMAT_WMF)){ bRet = GetDIBits(hDC, hBitmap, 0, (UINT)cy, newima->GetBits(), (LPBITMAPINFO)newima->GetDIB(), DIB_RGB_COLORS); NewDoc->image = newima; } else { delete newima; } } if (hBitmap) DeleteObject(hBitmap); if (hDC) DeleteDC(hDC); } #endif } } CloseClipboard(); CString s; s.Format(_T("Clipboard Image %d"),((CDemoApp*)AfxGetApp())->m_nDocCount++); NewDoc->SetTitle(s); NewDoc->UpdateAllViews(0,WM_USER_NEWIMAGE); NewDoc->UpdateStatusBar(); } }
// return number of faces and score void detectFaces(const CxImage& img, std::list <Face>& lFaces, int nRot) { if (cascade_el == NULL || cascade_er == NULL || cascade_f == NULL || cascade_m == NULL || cascade_n == NULL) init(); CxImage imgRotated (img); imgRotated.Rotate180(); IplImage *pIplImage = cvCreateImageHeader (cvSize (img.GetWidth(), img.GetHeight()), 8, img.GetBpp() / 8); pIplImage->imageDataOrigin = (char*)imgRotated.GetDIB(); pIplImage->imageData = (char*)imgRotated.GetBits(); CvMemStorage *storage; /* setup memory storage, needed by the object detector */ storage = cvCreateMemStorage(0); assert(cascade_f && cascade_el && cascade_er && cascade_m && cascade_n && storage); /* haar detection for faces */ CvSeq *pFaces = cvHaarDetectObjects( pIplImage, cascade_f, storage, 1.2, 2, CV_HAAR_DO_CANNY_PRUNING, cvSize( 40, 40 ) ); if (pFaces->total == 0) return; CvSeq seqFaces (*pFaces); list <CvRect> lrFaces; for(int idxFace = 0; idxFace < seqFaces.total; idxFace++ ) { CvRect *r = (CvRect*)cvGetSeqElem(&seqFaces, idxFace); if (r) lrFaces.push_back (*r); } /* haar detection for eyes */ list<pair <RECT, RECT>> lpairEyes; detect_eyes (storage, pIplImage, lpairEyes); /* haar detection for mouths */ list<RECT> lMouths; detect_mouths (storage, pIplImage, lMouths); /* haar detection for noses */ list<RECT> lNoses; detect_noses (storage, pIplImage, lNoses); for(list <CvRect>::iterator itFace = lrFaces.begin(); itFace != lrFaces.end(); ++itFace) { CvRect r (*itFace); CvRect rFace (*itFace); rFace.x = img.GetWidth() - r.x - r.width; rFace.y = img.GetHeight() - r.y - r.height; RECT rcFace; rcFace.left = img.GetWidth() - r.x - r.width - 10; rcFace.right = img.GetWidth() - r.x + 10; rcFace.top = img.GetHeight() - r.y - r.height - 10; rcFace.bottom = img.GetHeight() - r.y + 10; /* detect current eyes */ pair <RECT, RECT> pairEyes; match_eyes_with_face (lpairEyes, rFace, pairEyes); /* detect current mouth */ RECT rcMouth; match_mouths_with_face (lMouths, rFace, pairEyes, rcMouth); /* detect current nose */ RECT rcNose; match_noses_with_face (lNoses, rFace, pairEyes, rcMouth, rcNose); lFaces.push_back (Face (rcFace, pairEyes, rcMouth, rcNose, nRot)); } Face::adjustRectFaces(lFaces); cvReleaseMemStorage (&storage); cvReleaseImageHeader (&pIplImage); }