void CxImage::CreateFromHICON(HICON hico) { Destroy(); if (hico) { ICONINFO iinfo; GetIconInfo(hico,&iinfo); CreateFromHBITMAP(iinfo.hbmColor); #if CXIMAGE_SUPPORT_ALPHA CxImage mask; mask.CreateFromHBITMAP(iinfo.hbmMask); mask.GrayScale(); mask.Negative(); AlphaSet(mask); #endif } }
std::string UserListModule_Impl::getGrayLocalPathFromFilename(std::string& finename) { CString csFileName = util::stringToCString(finename); CString csGrayAvatarPath = module::getMiscModule()->getDownloadDir() + PREFIX_GRAY_AVATAR + csFileName; //本地磁盘存在 if (util::isFileExist(csGrayAvatarPath)) { return util::cStringToString(csGrayAvatarPath); } else { //不存在则对图片做灰度处理并且保存到本地 CxImage cximage; CString csAvatarPath = module::getMiscModule()->getDownloadDir() + csFileName; bool bSucc = cximage.Load(csAvatarPath); if (bSucc) { cximage.GrayScale(); module::getCaptureModule()->saveToFile(cximage.MakeBitmap(), csAvatarPath); } } return ""; }
bool IGIPFilter::OnImageProcessing (CxImage& image, IGImageProcMessage& message) { IGIPFilterMessage *pIGThreadMessage = dynamic_cast <IGIPFilterMessage *> (&message); _ASSERTE (pIGThreadMessage && L"Wrong IGThread message, image processing aborted"); if (!pIGThreadMessage || !m_pFrame) return false; IGLayer *pLayer = m_pFrame->GetLayer (m_pFrame->GetLayerPos (image.GetWorkingLayer())); if (!pLayer) return false; switch (pIGThreadMessage->m_eFilterType) { case IGIPFILTER_BLUR: return pLayer->GaussianBlur (5.0f); case IGIPFILTER_GRADIENT: { long tKernel [9]; pLayer->GrayScale(); CxImage g1(*pLayer), g2(*pLayer), g3(*pLayer), g4(*pLayer); tKernel[0] = 0;tKernel[1] = 1;tKernel[2] = -1; tKernel[3] = 0;tKernel[4] = 1;tKernel[5] = -1; tKernel[6] = 0;tKernel[7] = 1;tKernel[8] = -1; g1.Filter (tKernel, 3, 4, 0); tKernel[0] = -1;tKernel[1] = 1;tKernel[2] = 0; tKernel[3] = -1;tKernel[4] = 1;tKernel[5] = 0; tKernel[6] = -1;tKernel[7] = 1;tKernel[8] = 0; g2.Filter (tKernel, 3, 4, 0); tKernel[0] = -1;tKernel[1] = -1;tKernel[2] = -1; tKernel[3] = 1;tKernel[4] = 1;tKernel[5] = 1; tKernel[6] = 0;tKernel[7] = 0;tKernel[8] = 0; g3.Filter (tKernel, 3, 4, 0); tKernel[0] = 0;tKernel[1] = 0;tKernel[2] = 0; tKernel[3] = 1;tKernel[4] = 1;tKernel[5] = 1; tKernel[6] = -1;tKernel[7] = -1;tKernel[8] = -1; g4.Filter (tKernel, 3, 4, 0); pLayer->Copy (g1, true, false, false, false); *pLayer += g2; *pLayer += g3; *pLayer += g4; return true; } case IGIPFILTER_GRADIENT_MORPHO: return pLayer->ComputeGradient (true); case IGIPFILTER_GRAY: return pLayer->GrayScale(); case IGIPFILTER_SKIN: return pLayer->FilterSkin(); case IGIPFILTER_SKIN_UNNOISED: return pLayer->FilterSkinUnnoised(); case IGIPFILTER_EYES: { RECT rcNo = {-1,-1,-1,-1}; return pLayer->RedEyeRemove (rcNo, rcNo, 0.5f); } case IGIPFILTER_EYES_COLOR: { RECT rcNo = {-1,-1,-1,-1}; RGBQUAD rgbq; IGTexture texture; if (!m_pFrame->GetProperty (IGProperties::IGPROPERTY_CURTEXTURE, texture)) return false; COLORREF col = (COLORREF)texture; rgbq.rgbRed = GetRValue (col); rgbq.rgbBlue = GetBValue (col); rgbq.rgbGreen = GetGValue (col); rgbq.rgbReserved = 0x00; rgbq = pLayer->RGBtoHSL (rgbq); return pLayer->ChangeEyeColor (rcNo, rcNo, rgbq.rgbRed, rgbq.rgbGreen, 50.0f); } case IGIPFILTER_FFT: { CxImage copy (*pLayer); copy.GrayScale(); CxImage res; if (!pLayer->FFT2 (©, NULL, &res, NULL)) return false; pLayer->Copy (res); return true; } case IGIPFILTER_FACE_EFFECT: { IGIPFaceEffectMessage *pIGIPFaceEffectMessage = dynamic_cast <IGIPFaceEffectMessage *> (pIGThreadMessage); _ASSERTE (pIGIPFaceEffectMessage && L"Wrong IGThread message, face effect image processing aborted"); if (!pIGIPFaceEffectMessage) return false; return pLayer->ProcessFaceEffect (pIGIPFaceEffectMessage); } case IGIPFILTER_COLORIZE: { RGBQUAD rgbq; IGTexture texture; if (!m_pFrame->GetProperty (IGProperties::IGPROPERTY_CURTEXTURE, texture)) return false; COLORREF col = (COLORREF)texture; rgbq.rgbRed = GetRValue (col); rgbq.rgbBlue = GetBValue (col); rgbq.rgbGreen = GetGValue (col); rgbq.rgbReserved = 0x00; rgbq = pLayer->RGBtoHSL (rgbq); return pLayer->Colorize (rgbq.rgbRed, rgbq.rgbGreen, rgbq.rgbBlue, (float)texture.GetTransparency() / 255.0f); } case IGIPFILTER_BRIGHTNESS: { int nStrength = -1; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_STRENGTH, nStrength) || (nStrength == -1)) return false; return pLayer->Light ((long)((float)nStrength * 2.55f)); } case IGIPFILTER_CONTRAST: { int nStrength = -1; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_STRENGTH, nStrength) || (nStrength == -1)) return false; return pLayer->Light (0, nStrength); } case IGIPFILTER_SATURATE: { int nStrength = -1; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_STRENGTH, nStrength) || (nStrength == -1)) return false; return pLayer->Saturate (nStrength); } case IGIPFILTER_VIBRANCE: { int nStrength = -1; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_STRENGTH, nStrength) || (nStrength == -1)) return false; return pLayer->Vibrance ((long)((float)nStrength * 2.55f)); } case IGIPFILTER_MORPHING: { int nRadius = -1, nType = -1, nPosX = -1, nPosY = -1, nDirectionX = 0, nDirectionY = 0; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_STRENGTH, nRadius) || (nRadius == -1)) return false; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_TYPE, nType) || (nType == -1)) return false; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_POSX, nPosX) || (nPosX == -1)) return false; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_POSY, nPosY) || (nPosY == -1)) return false; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_DIRECTIONX, nDirectionX)) return false; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_DIRECTIONY, nDirectionY)) return false; // convert DZ coords to IG double dSeadragonToPixelRatioX, dSeadragonToPixelRatioY; IGConvertible::FromDZtoIGRatios (image.GetWidth(), image.GetHeight(), dSeadragonToPixelRatioX, dSeadragonToPixelRatioY); POINT ptPos; ptPos.x = (int)((double)nPosX * dSeadragonToPixelRatioX); ptPos.y = (int)((double)nPosY * dSeadragonToPixelRatioY); POINT ptDir; ptDir.x = (int)((double)nDirectionX * dSeadragonToPixelRatioX); ptDir.y = (int)((double)nDirectionY * dSeadragonToPixelRatioY); // convert IG coords to CX IGConvertible::FromIGtoCxCoords(ptPos, image.GetHeight()); ptDir.y *= -1; // apply morphing return pLayer->Morphing (ptPos.x, ptPos.y, (float)ptDir.x, (float)ptDir.y, (float)nRadius, nType); } case IGIPFILTER_NEGATIVE: return pLayer->Negative(); case IGIPFILTER_TRANSPARENCY: { int nAlpha = 0; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_STRENGTH, nAlpha)) return false; pLayer->AlphaDelete(); return pLayer->AlphaCreate ((BYTE)((float)nAlpha * 2.55f)); } case IGIPFILTER_PAINT: { int nPosX = -1, nPosY = -1; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_POSX, nPosX) || (nPosX == -1)) return false; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_POSY, nPosY) || (nPosY == -1)) return false; int nTolerance = 0; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_TOLERANCE, nTolerance)) return false; RGBQUAD rgbq; IGTexture texture; if (!m_pFrame->GetProperty (IGProperties::IGPROPERTY_CURTEXTURE, texture)) return false; // convert DZ coords to IG double dSeadragonToPixelRatioX, dSeadragonToPixelRatioY; IGConvertible::FromDZtoIGRatios (image.GetWidth(), image.GetHeight(), dSeadragonToPixelRatioX, dSeadragonToPixelRatioY); POINT ptPos; ptPos.x = (int)((double)nPosX * dSeadragonToPixelRatioX); ptPos.y = (int)((double)nPosY * dSeadragonToPixelRatioY); // convert IG coords to CX IGConvertible::FromIGtoCxCoords(ptPos, image.GetHeight()); COLORREF col = (COLORREF)texture; rgbq.rgbRed = GetRValue (col); rgbq.rgbBlue = GetBValue (col); rgbq.rgbGreen = GetGValue (col); rgbq.rgbReserved = 0x00; return pLayer->FloodFill (ptPos.x, ptPos.y, rgbq, nTolerance); } case IGIPFILTER_PAINTGRADIENT: { int nPosX = -1, nPosY = -1, nDirectionX = 0, nDirectionY = 0; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_POSX, nPosX) || (nPosX == -1)) return false; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_POSY, nPosY) || (nPosY == -1)) return false; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_DIRECTIONX, nDirectionX)) return false; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_DIRECTIONY, nDirectionY)) return false; RGBQUAD rgbq, rgbqBkgnd; IGTexture texture, bkgndTexture; if (!m_pFrame->GetProperty (IGProperties::IGPROPERTY_CURTEXTURE, texture)) return false; COLORREF col = (COLORREF)texture; rgbq.rgbRed = GetRValue (col); rgbq.rgbBlue = GetBValue (col); rgbq.rgbGreen = GetGValue (col); rgbq.rgbReserved = 0x00; if (!m_pFrame->GetProperty (IGProperties::IGPROPERTY_BKGNDTEXTURE, bkgndTexture)) return false; // convert DZ coords to IG double dSeadragonToPixelRatioX, dSeadragonToPixelRatioY; IGConvertible::FromDZtoIGRatios (image.GetWidth(), image.GetHeight(), dSeadragonToPixelRatioX, dSeadragonToPixelRatioY); POINT ptPos; ptPos.x = (int)((double)nPosX * dSeadragonToPixelRatioX); ptPos.y = (int)((double)nPosY * dSeadragonToPixelRatioY); POINT ptDir; ptDir.x = (int)((double)nDirectionX * dSeadragonToPixelRatioX); ptDir.y = (int)((double)nDirectionY * dSeadragonToPixelRatioY); // convert IG coords to CX IGConvertible::FromIGtoCxCoords(ptPos, image.GetHeight()); ptDir.y *= -1; COLORREF colBkgnd = (COLORREF)bkgndTexture; rgbqBkgnd.rgbRed = GetRValue (colBkgnd); rgbqBkgnd.rgbBlue = GetBValue (colBkgnd); rgbqBkgnd.rgbGreen = GetGValue (colBkgnd); rgbqBkgnd.rgbReserved = 0x00; return pLayer->FillGradient (ptPos.x, ptPos.y, ptDir.x, ptDir.y, rgbq, rgbqBkgnd); } case IGIPFILTER_REPAIR: return pLayer->Repair (0.25f, 3, 0); case IGIPFILTER_SHARPEN: return pLayer->UnsharpMask (5.0f, 0.5f, 0); case IGIPFILTER_MATIFY: { COLORREF col = IGIPFACE_EFFECT_MATIFY_COLORCODE; RGBQUAD rgbq; rgbq.rgbRed = GetRValue (col); rgbq.rgbBlue = GetBValue (col); rgbq.rgbGreen = GetGValue (col); rgbq.rgbReserved = 0x00; rgbq = pLayer->RGBtoHSL (rgbq); return pLayer->Colorize (rgbq.rgbRed, rgbq.rgbGreen, rgbq.rgbBlue, 1.0f); } case IGIPFILTER_THRESHOLD: return pLayer->AdaptiveThreshold(0); case IGIPFILTER_AUTOROTATE: return pLayer->AutoRotate(); case IGIPFILTER_SKETCH: return pLayer->Sketch(); case IGIPFILTER_CARTOON: return pLayer->Cartoon(); case IGIPFILTER_OILPAINTING: return pLayer->OilPainting(); case IGIPFILTER_WATERPAINTING: return pLayer->WaterPainting(); case IGIPFILTER_SEPIA: { RGBQUAD rgbq; rgbq.rgbRed = 112; rgbq.rgbBlue = 20; rgbq.rgbGreen = 66; rgbq.rgbReserved = 0x00; rgbq = pLayer->RGBtoHSL (rgbq); return pLayer->Colorize (rgbq.rgbRed, rgbq.rgbGreen, rgbq.rgbBlue, 1.0f); } case IGIPFILTER_VINTAGE: { pLayer->UnsharpMask (5.0f, 0.5f, 0); pLayer->UnsharpMask (5.0f, 0.5f, 0); pLayer->UnsharpMask (5.0f, 0.5f, 0); RGBQUAD rgbq; rgbq.rgbRed = 112; rgbq.rgbBlue = 20; rgbq.rgbGreen = 66; rgbq.rgbReserved = 0x00; rgbq = pLayer->RGBtoHSL (rgbq); return pLayer->Colorize (rgbq.rgbRed, rgbq.rgbGreen, rgbq.rgbBlue, 0.25f); } case IGIPFILTER_DITHER: return pLayer->Dither(); case IGIPFILTER_CLAY: return pLayer->Clay(); case IGIPFILTER_PYTHON: { wstring wsPythonScript; if (!m_pFrame->GetRequestProperty(IGIPFILTER_PARAM_SCRIPT, wsPythonScript)) return false; return pLayer->ExecutePythonScript (wsPythonScript); } case IGIPFILTER_FILTER1: { CxImage *layer1 (*pLayer); CxImage *layer2 (*pLayer); CxImage *layer3 (*pLayer); int nAlpha = 0; // Contrast the image using the curve: out 116, in 139 long contrast_in = 139, contrast_out = 116; CxImage *contrast_IN (*pLayer); CxImage *contrast_OUT (*pLayer); contrast_IN->Mix(*contrast_OUT); contrast_IN->Light(0, contrast_in); contrast_OUT->Light(0, contrast_out); // Add contrast IN & OUT images // Apply layer 2 as screen with opacity 48 nAlpha = 48; layer2->AlphaDelete(); layer2->AlphaCreate ((BYTE)((float)nAlpha * 2.55f)); // Apply layer 3 as overlay with opacity 35 nAlpha = 35; layer3->AlphaDelete(); layer3->AlphaCreate ((BYTE)((float)nAlpha * 2.55f)); // Adding the three layers layer1->Mix(*layer2); layer1->Mix(*layer3); return true; } case IGIPFILTER_PAPER: return pLayer->Paper(); case IGIPFILTER_HALOSEPIA: return pLayer->Sepia(); case IGIPFILTER_BW: return pLayer->BlackAndWhite(); } return false; }
//============================================================================= // // The framework calls this member function when a child control is about to // be drawn. All the bitmaps are created here on the first call. Every thing // is done with a memory DC except the background, which get's it's information // from the parent. The background is needed for transparent portions of PNG // images. An always on top app (such as Task Manager) that is in the way can // cause it to get an incorrect background. To avoid this, the parent should // call the SetBkGnd function with a memory DC when it creates the background. // //============================================================================= HBRUSH CButtonBT::CtlColor(CDC* pScreenDC, UINT nCtlColor) { if(!m_bHaveBitmaps) { if(!m_imgStd.IsValid()) { return NULL; // Load the standard image with LoadStdImage() } CBitmap bmp, *pOldBitmap; CRect rect; GetClientRect(rect); // do everything with mem dc CMemDCEx memdc(pScreenDC, rect); //CGDIPMemDC pDC(pScreenDC, rect); //Gdiplus::Graphics graphics(pDC->m_hDC); // background if (m_dcBk.m_hDC == NULL) { CRect rect1; CClientDC clDC(GetParent()); GetWindowRect(rect1); GetParent()->ScreenToClient(rect1); m_dcBk.CreateCompatibleDC(&clDC); bmp.CreateCompatibleBitmap(&clDC, rect.Width(), rect.Height()); pOldBitmap = m_dcBk.SelectObject(&bmp); m_dcBk.BitBlt(0, 0, rect.Width(), rect.Height(), &clDC, rect1.left, rect1.top, SRCCOPY); bmp.DeleteObject(); } // standard image if (m_dcStd.m_hDC == NULL) { PaintBk(&memdc); //graphics.DrawImage(*m_pStdImage, 0, 0); m_imgStd.Draw(memdc.GetSafeHdc()); m_dcStd.CreateCompatibleDC(&memdc); bmp.CreateCompatibleBitmap(&memdc, rect.Width(), rect.Height()); pOldBitmap = m_dcStd.SelectObject(&bmp); m_dcStd.BitBlt(0, 0, rect.Width(), rect.Height(), &memdc, 0, 0, SRCCOPY); bmp.DeleteObject(); // standard image pressed if (m_dcStdP.m_hDC == NULL) { PaintBk(&memdc); if (m_bISMove) { //graphics.DrawImage(*m_pStdImage, 1, 1); m_imgStd.Draw(memdc.GetSafeHdc(), 1, 1); } else { //graphics.DrawImage(*m_pStdImage, 0, 0); m_imgStd.Draw(memdc.GetSafeHdc()); } m_dcStdP.CreateCompatibleDC(&memdc); bmp.CreateCompatibleBitmap(&memdc, rect.Width(), rect.Height()); pOldBitmap = m_dcStdP.SelectObject(&bmp); m_dcStdP.BitBlt(0, 0, rect.Width(), rect.Height(), &memdc, 0, 0, SRCCOPY); bmp.DeleteObject(); } // standard image hot if(m_dcStdH.m_hDC == NULL) { PaintBk(&memdc); CxImage imgtemp = m_imgStd; imgtemp.ShiftRGB(20,20,20); imgtemp.Draw(memdc.GetSafeHdc()); m_dcStdH.CreateCompatibleDC(&memdc); bmp.CreateCompatibleBitmap(&memdc, rect.Width(), rect.Height()); pOldBitmap = m_dcStdH.SelectObject(&bmp); m_dcStdH.BitBlt(0, 0, rect.Width(), rect.Height(), &memdc, 0, 0, SRCCOPY); bmp.DeleteObject(); } // grayscale image if(m_dcGS.m_hDC == NULL) { PaintBk(&memdc); CxImage imgtemp = m_imgStd; imgtemp.GrayScale(); imgtemp.Draw(memdc.GetSafeHdc()); m_dcGS.CreateCompatibleDC(&memdc); bmp.CreateCompatibleBitmap(&memdc, rect.Width(), rect.Height()); pOldBitmap = m_dcGS.SelectObject(&bmp); m_dcGS.BitBlt(0, 0, rect.Width(), rect.Height(), &memdc, 0, 0, SRCCOPY); bmp.DeleteObject(); } } // alternate image if( (m_dcAlt.m_hDC == NULL) && m_bHaveAltImage ) { PaintBk(&memdc); //graphics.DrawImage(*m_pAltImage, 0, 0); m_imgAlt.Draw(memdc.GetSafeHdc()); m_dcAlt.CreateCompatibleDC(&memdc); bmp.CreateCompatibleBitmap(&memdc, rect.Width(), rect.Height()); pOldBitmap = m_dcAlt.SelectObject(&bmp); m_dcAlt.BitBlt(0, 0, rect.Width(), rect.Height(), &memdc, 0, 0, SRCCOPY); bmp.DeleteObject(); // alternate image pressed if( (m_dcAltP.m_hDC == NULL) && m_bHaveAltImage ) { PaintBk(&memdc); if (m_bISMove) { //graphics.DrawImage(*m_pAltImage, 1, 1); m_imgAlt.Draw(memdc.GetSafeHdc(), 1, 1); } else { //graphics.DrawImage(*m_pAltImage, 0, 0); m_imgAlt.Draw(memdc.GetSafeHdc()); } m_dcAltP.CreateCompatibleDC(&memdc); bmp.CreateCompatibleBitmap(&memdc, rect.Width(), rect.Height()); pOldBitmap = m_dcAltP.SelectObject(&bmp); m_dcAltP.BitBlt(0, 0, rect.Width(), rect.Height(), &memdc, 0, 0, SRCCOPY); bmp.DeleteObject(); } // alternate image hot if(m_dcAltH.m_hDC == NULL) { PaintBk(&memdc); CxImage imgtemp = m_imgAlt; imgtemp.ShiftRGB(20,20,20); imgtemp.Draw(memdc.GetSafeHdc()); m_dcAltH.CreateCompatibleDC(&memdc); bmp.CreateCompatibleBitmap(&memdc, rect.Width(), rect.Height()); pOldBitmap = m_dcAltH.SelectObject(&bmp); m_dcAltH.BitBlt(0, 0, rect.Width(), rect.Height(), &memdc, 0, 0, SRCCOPY); bmp.DeleteObject(); } } if(m_pCurBtn == NULL) { m_pCurBtn = &m_dcStd; } m_bHaveBitmaps = TRUE; } return NULL; }
// 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(); }