Handle cursor files as icons when diffing
[TortoiseGit.git] / src / Utils / MiscUI / Picture.cpp
blob6fc9a73941397ae34554579bcc690c2770ca1f41
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2014 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "stdafx.h"
20 #include <olectl.h>
21 #include <Shlwapi.h>
22 #include <locale>
23 #include <algorithm>
24 #include "Picture.h"
25 #include "SmartHandle.h"
26 #include <atlbase.h>
27 #include <Wincodec.h>
29 #pragma comment(lib, "shlwapi.lib")
30 #pragma comment(lib, "gdiplus.lib")
31 // note: linking with Windowscodecs.lib does not make the exe require the dll
32 // which means it still runs on XP even if the WIC isn't installed - WIC won't work
33 // but the exe still runs
34 #pragma comment(lib, "Windowscodecs.lib")
36 #define HIMETRIC_INCH 2540
38 CPicture::CPicture()
39 : m_IPicture(NULL)
40 , m_Height(0)
41 , m_Weight(0)
42 , m_Width(0)
43 , pBitmap(NULL)
44 , bHaveGDIPlus(false)
45 , m_ip(InterpolationModeDefault)
46 , hIcons(NULL)
47 , lpIcons(NULL)
48 , nCurrentIcon(0)
49 , bIsIcon(false)
50 , bIsTiff(false)
51 , m_nSize(0)
52 , m_ColorDepth(0)
53 , hGlobal(NULL)
54 , gdiplusToken(NULL)
58 CPicture::~CPicture()
60 FreePictureData(); // Important - Avoid Leaks...
61 delete pBitmap;
62 if (bHaveGDIPlus)
63 GdiplusShutdown(gdiplusToken);
67 void CPicture::FreePictureData()
69 if (m_IPicture != NULL)
71 m_IPicture->Release();
72 m_IPicture = NULL;
73 m_Height = 0;
74 m_Weight = 0;
75 m_Width = 0;
76 m_nSize = 0;
78 if (hIcons)
80 LPICONDIR lpIconDir = (LPICONDIR)lpIcons;
81 if (lpIconDir)
83 for (int i=0; i<lpIconDir->idCount; ++i)
85 DestroyIcon(hIcons[i]);
88 delete [] hIcons;
89 hIcons = NULL;
91 delete [] lpIcons;
94 // Util function to ease loading of FreeImage library
95 static FARPROC s_GetProcAddressEx(HMODULE hDll, const char* procName, bool& valid)
97 FARPROC proc = NULL;
99 if (valid)
101 proc = GetProcAddress(hDll, procName);
103 if (!proc)
104 valid = false;
107 return proc;
110 tstring CPicture::GetFileSizeAsText(bool bAbbrev /* = true */)
112 TCHAR buf[100] = {0};
113 if (bAbbrev)
114 StrFormatByteSize(m_nSize, buf, _countof(buf));
115 else
116 _stprintf_s(buf, _T("%ld Bytes"), m_nSize);
118 return tstring(buf);
121 bool CPicture::Load(tstring sFilePathName)
123 bool bResult = false;
124 bIsIcon = false;
125 lpIcons = NULL;
126 //CFile PictureFile;
127 //CFileException e;
128 FreePictureData(); // Important - Avoid Leaks...
130 // No-op if no file specified
131 if (sFilePathName.empty())
132 return true;
134 // Load & initialize the GDI+ library if available
135 HMODULE hGdiPlusLib = AtlLoadSystemLibraryUsingFullPath(_T("gdiplus.dll"));
136 if (hGdiPlusLib && GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL) == Ok)
138 bHaveGDIPlus = true;
140 // Since we loaded the gdiplus.dll only to check if it's available, we
141 // can safely free the library here again - GdiplusStartup() loaded it too
142 // and reference counting will make sure that it stays loaded until GdiplusShutdown()
143 // is called.
144 FreeLibrary(hGdiPlusLib);
146 // Attempt to load using GDI+ if available
147 if (bHaveGDIPlus)
149 pBitmap = new Bitmap(sFilePathName.c_str(), FALSE);
150 GUID guid;
151 pBitmap->GetRawFormat(&guid);
153 if (pBitmap->GetLastStatus() != Ok)
155 delete pBitmap;
156 pBitmap = NULL;
159 // gdiplus only loads the first icon found in an icon file
160 // so we have to handle icon files ourselves :(
162 // Even though gdiplus can load icons, it can't load the new
163 // icons from Vista - in Vista, the icon format changed slightly.
164 // But the LoadIcon/LoadImage API still can load those icons,
165 // at least those dimensions which are also used on pre-Vista
166 // systems.
167 // For that reason, we don't rely on gdiplus telling us if
168 // the image format is "icon" or not, we also check the
169 // file extension for ".ico".
170 std::transform(sFilePathName.begin(), sFilePathName.end(), sFilePathName.begin(), ::tolower);
171 bIsIcon = (guid == ImageFormatIcon) || (wcsstr(sFilePathName.c_str(), L".ico") != NULL) || (wcsstr(sFilePathName.c_str(), L".cur") != NULL);
172 bIsTiff = (guid == ImageFormatTIFF) || (_tcsstr(sFilePathName.c_str(), _T(".tiff")) != NULL);
173 m_Name = sFilePathName;
175 if (bIsIcon)
177 // Icon file, get special treatment...
178 if (pBitmap)
180 // Cleanup first...
181 delete (pBitmap);
182 pBitmap = NULL;
183 bIsIcon = true;
186 CAutoFile hFile = CreateFile(sFilePathName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
187 if (hFile)
189 BY_HANDLE_FILE_INFORMATION fileinfo;
190 if (GetFileInformationByHandle(hFile, &fileinfo))
192 lpIcons = new BYTE[fileinfo.nFileSizeLow];
193 DWORD readbytes;
194 if (ReadFile(hFile, lpIcons, fileinfo.nFileSizeLow, &readbytes, NULL))
196 // we have the icon. Now gather the information we need later
197 if (readbytes >= sizeof(ICONDIR))
199 // we are going to open same file second time so we have to close the file now
200 hFile.CloseHandle();
202 LPICONDIR lpIconDir = (LPICONDIR)lpIcons;
203 if ((lpIconDir->idCount) && ((lpIconDir->idCount * sizeof(ICONDIR)) <= fileinfo.nFileSizeLow))
207 bResult = false;
208 nCurrentIcon = 0;
209 hIcons = new HICON[lpIconDir->idCount];
210 // check that the pointers point to data that we just loaded
211 if (((BYTE*)lpIconDir->idEntries > (BYTE*)lpIconDir) &&
212 (((BYTE*)lpIconDir->idEntries) + (lpIconDir->idCount * sizeof(ICONDIRENTRY)) < ((BYTE*)lpIconDir) + fileinfo.nFileSizeLow))
214 m_Width = lpIconDir->idEntries[0].bWidth;
215 m_Height = lpIconDir->idEntries[0].bHeight;
216 bResult = true;
217 for (int i=0; i<lpIconDir->idCount; ++i)
219 hIcons[i] = (HICON)LoadImage(NULL, sFilePathName.c_str(), IMAGE_ICON,
220 lpIconDir->idEntries[i].bWidth,
221 lpIconDir->idEntries[i].bHeight,
222 LR_LOADFROMFILE);
223 if (hIcons[i] == NULL)
225 // if the icon couldn't be loaded, the data is most likely corrupt
226 delete [] lpIcons;
227 lpIcons = NULL;
228 bResult = false;
229 break;
234 catch (...)
236 delete [] lpIcons;
237 lpIcons = NULL;
238 bResult = false;
241 else
243 delete [] lpIcons;
244 lpIcons = NULL;
245 bResult = false;
248 else
250 delete [] lpIcons;
251 lpIcons = NULL;
252 bResult = false;
255 else
257 delete [] lpIcons;
258 lpIcons = NULL;
263 else if (pBitmap) // Image loaded successfully with GDI+
265 m_Height = pBitmap->GetHeight();
266 m_Width = pBitmap->GetWidth();
267 bResult = true;
270 // If still failed to load the file...
271 if (!bResult)
273 // Attempt to load the FreeImage library as an optional DLL to support additional formats
275 // NOTE: Currently just loading via FreeImage & using GDI+ for drawing.
276 // It might be nice to remove this dependency in the future.
277 HMODULE hFreeImageLib = LoadLibrary(_T("FreeImage.dll"));
279 // FreeImage DLL functions
280 typedef const char* (__stdcall *FreeImage_GetVersion_t)(void);
281 typedef int (__stdcall *FreeImage_GetFileType_t)(const TCHAR *filename, int size);
282 typedef int (__stdcall *FreeImage_GetFIFFromFilename_t)(const TCHAR *filename);
283 typedef void* (__stdcall *FreeImage_Load_t)(int format, const TCHAR *filename, int flags);
284 typedef void (__stdcall *FreeImage_Unload_t)(void* dib);
285 typedef int (__stdcall *FreeImage_GetColorType_t)(void* dib);
286 typedef unsigned (__stdcall *FreeImage_GetWidth_t)(void* dib);
287 typedef unsigned (__stdcall *FreeImage_GetHeight_t)(void* dib);
288 typedef void (__stdcall *FreeImage_ConvertToRawBits_t)(BYTE *bits, void *dib, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown);
290 //FreeImage_GetVersion_t FreeImage_GetVersion = NULL;
291 FreeImage_GetFileType_t FreeImage_GetFileType = NULL;
292 FreeImage_GetFIFFromFilename_t FreeImage_GetFIFFromFilename = NULL;
293 FreeImage_Load_t FreeImage_Load = NULL;
294 FreeImage_Unload_t FreeImage_Unload = NULL;
295 //FreeImage_GetColorType_t FreeImage_GetColorType = NULL;
296 FreeImage_GetWidth_t FreeImage_GetWidth = NULL;
297 FreeImage_GetHeight_t FreeImage_GetHeight = NULL;
298 FreeImage_ConvertToRawBits_t FreeImage_ConvertToRawBits = NULL;
300 if (hFreeImageLib)
302 bool exportsValid = true;
304 //FreeImage_GetVersion = (FreeImage_GetVersion_t)s_GetProcAddressEx(hFreeImageLib, "_FreeImage_GetVersion@0", valid);
305 FreeImage_GetWidth = (FreeImage_GetWidth_t)s_GetProcAddressEx(hFreeImageLib, "_FreeImage_GetWidth@4", exportsValid);
306 FreeImage_GetHeight = (FreeImage_GetHeight_t)s_GetProcAddressEx(hFreeImageLib, "_FreeImage_GetHeight@4", exportsValid);
307 FreeImage_Unload = (FreeImage_Unload_t)s_GetProcAddressEx(hFreeImageLib, "_FreeImage_Unload@4", exportsValid);
308 FreeImage_ConvertToRawBits = (FreeImage_ConvertToRawBits_t)s_GetProcAddressEx(hFreeImageLib, "_FreeImage_ConvertToRawBits@32", exportsValid);
310 #ifdef UNICODE
311 FreeImage_GetFileType = (FreeImage_GetFileType_t)s_GetProcAddressEx(hFreeImageLib, "_FreeImage_GetFileTypeU@8", exportsValid);
312 FreeImage_GetFIFFromFilename = (FreeImage_GetFIFFromFilename_t)s_GetProcAddressEx(hFreeImageLib, "_FreeImage_GetFIFFromFilenameU@4", exportsValid);
313 FreeImage_Load = (FreeImage_Load_t)s_GetProcAddressEx(hFreeImageLib, "_FreeImage_LoadU@12", exportsValid);
314 #else
315 FreeImage_GetFileType = (FreeImage_GetFileType_t)s_GetProcAddressEx(hFreeImageLib, "_FreeImage_GetFileType@8", exportsValid);
316 FreeImage_GetFIFFromFilename = (FreeImage_GetFIFFromFilename_t)s_GetProcAddressEx(hFreeImageLib, "_FreeImage_GetFIFFromFilename@4", exportsValid);
317 FreeImage_Load = (FreeImage_Load_t)s_GetProcAddressEx(hFreeImageLib, "_FreeImage_Load@12", exportsValid);
318 #endif
320 //const char* version = FreeImage_GetVersion();
322 // Check the DLL is using compatible exports
323 if (exportsValid)
325 // Derive file type from file header.
326 int fileType = FreeImage_GetFileType(sFilePathName.c_str(), 0);
327 if (fileType < 0)
329 // No file header available, attempt to parse file name for extension.
330 fileType = FreeImage_GetFIFFromFilename(sFilePathName.c_str());
333 // If we have a valid file type
334 if (fileType >= 0)
336 void* dib = FreeImage_Load(fileType, sFilePathName.c_str(), 0);
338 if (dib)
340 unsigned width = FreeImage_GetWidth(dib);
341 unsigned height = FreeImage_GetHeight(dib);
343 // Create a GDI+ bitmap to load into...
344 pBitmap = new Bitmap(width, height, PixelFormat32bppARGB);
346 if (pBitmap && pBitmap->GetLastStatus() == Ok)
348 // Write & convert the loaded data into the GDI+ Bitmap
349 Rect rect(0, 0, width, height);
350 BitmapData bitmapData;
351 if (pBitmap->LockBits(&rect, ImageLockModeWrite, PixelFormat32bppARGB, &bitmapData) == Ok)
353 FreeImage_ConvertToRawBits((BYTE*)bitmapData.Scan0, dib, bitmapData.Stride, 32, 0xff << RED_SHIFT, 0xff << GREEN_SHIFT, 0xff << BLUE_SHIFT, FALSE);
355 pBitmap->UnlockBits(&bitmapData);
357 m_Width = width;
358 m_Height = height;
359 bResult = true;
361 else // Failed to lock the destination Bitmap
363 delete pBitmap;
364 pBitmap = NULL;
367 else // Bitmap allocation failed
369 delete pBitmap;
370 pBitmap = NULL;
373 FreeImage_Unload(dib);
374 dib = NULL;
379 FreeLibrary(hFreeImageLib);
380 hFreeImageLib = NULL;
384 else // GDI+ Unavailable...
386 int nSize = 0;
387 pBitmap = NULL;
388 CAutoFile hFile = CreateFile(sFilePathName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_HIDDEN, NULL);
389 if (hFile)
391 BY_HANDLE_FILE_INFORMATION fileinfo;
392 if (GetFileInformationByHandle(hFile, &fileinfo))
394 BYTE * buffer = new BYTE[fileinfo.nFileSizeLow];
395 DWORD readbytes;
396 if (ReadFile(hFile, buffer, fileinfo.nFileSizeLow, &readbytes, NULL))
398 if (LoadPictureData(buffer, readbytes))
400 m_nSize = fileinfo.nFileSizeLow;
401 bResult = true;
404 delete [] buffer;
407 else
408 return bResult;
410 m_Name = sFilePathName;
411 m_Weight = nSize; // Update Picture Size Info...
413 if(m_IPicture != NULL) // Do Not Try To Read From Memory That Does Not Exist...
415 m_IPicture->get_Height(&m_Height);
416 m_IPicture->get_Width(&m_Width);
417 // Calculate Its Size On a "Standard" (96 DPI) Device Context
418 m_Height = MulDiv(m_Height, 96, HIMETRIC_INCH);
419 m_Width = MulDiv(m_Width, 96, HIMETRIC_INCH);
421 else // Picture Data Is Not a Known Picture Type
423 m_Height = 0;
424 m_Width = 0;
425 bResult = false;
429 if ((bResult)&&(m_nSize == 0))
431 CAutoFile hFile = CreateFile(sFilePathName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_HIDDEN, NULL);
432 if (hFile)
434 BY_HANDLE_FILE_INFORMATION fileinfo;
435 if (GetFileInformationByHandle(hFile, &fileinfo))
437 m_nSize = fileinfo.nFileSizeLow;
442 m_ColorDepth = GetColorDepth();
444 return(bResult);
447 bool CPicture::LoadPictureData(BYTE *pBuffer, int nSize)
449 bool bResult = false;
451 HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, nSize);
453 if(hGlobal == NULL)
455 return(false);
458 void* pData = GlobalLock(hGlobal);
459 if (pData == NULL)
460 return false;
461 memcpy(pData, pBuffer, nSize);
462 GlobalUnlock(hGlobal);
464 IStream* pStream = NULL;
466 if ((CreateStreamOnHGlobal(hGlobal, true, &pStream) == S_OK)&&(pStream))
468 HRESULT hr = OleLoadPicture(pStream, nSize, false, IID_IPicture, (LPVOID *)&m_IPicture);
469 pStream->Release();
470 pStream = NULL;
472 bResult = hr == S_OK;
475 FreeResource(hGlobal); // 16Bit Windows Needs This (32Bit - Automatic Release)
477 return(bResult);
480 bool CPicture::Show(HDC hDC, RECT DrawRect)
482 if (hDC == NULL)
483 return false;
484 if (bIsIcon && lpIcons)
486 ::DrawIconEx(hDC, DrawRect.left, DrawRect.top, hIcons[nCurrentIcon], DrawRect.right-DrawRect.left, DrawRect.bottom-DrawRect.top, 0, NULL, DI_NORMAL);
487 return true;
489 if ((m_IPicture == NULL)&&(pBitmap == NULL))
490 return false;
492 if (m_IPicture)
494 long Width = 0;
495 long Height = 0;
496 m_IPicture->get_Width(&Width);
497 m_IPicture->get_Height(&Height);
499 HRESULT hr = m_IPicture->Render(hDC,
500 DrawRect.left, // Left
501 DrawRect.top, // Top
502 DrawRect.right - DrawRect.left, // Right
503 DrawRect.bottom - DrawRect.top, // Bottom
505 Height,
506 Width,
507 -Height,
508 &DrawRect);
510 if (SUCCEEDED(hr))
511 return(true);
513 else if (pBitmap)
515 Graphics graphics(hDC);
516 graphics.SetInterpolationMode(m_ip);
517 graphics.SetPixelOffsetMode(PixelOffsetModeHighQuality);
518 graphics.SetPixelOffsetMode(PixelOffsetModeHalf);
519 ImageAttributes attr;
520 attr.SetWrapMode(WrapModeTileFlipXY);
521 Rect rect(DrawRect.left, DrawRect.top, DrawRect.right-DrawRect.left, DrawRect.bottom-DrawRect.top);
522 graphics.DrawImage(pBitmap, rect, 0, 0, m_Width, m_Height, UnitPixel, &attr);
523 return true;
526 return(false);
529 bool CPicture::UpdateSizeOnDC(HDC hDC)
531 if(hDC == NULL || m_IPicture == NULL) { m_Height = 0; m_Width = 0; return(false); };
533 m_IPicture->get_Height(&m_Height);
534 m_IPicture->get_Width(&m_Width);
536 // Get Current DPI - Dot Per Inch
537 int CurrentDPI_X = GetDeviceCaps(hDC, LOGPIXELSX);
538 int CurrentDPI_Y = GetDeviceCaps(hDC, LOGPIXELSY);
540 m_Height = MulDiv(m_Height, CurrentDPI_Y, HIMETRIC_INCH);
541 m_Width = MulDiv(m_Width, CurrentDPI_X, HIMETRIC_INCH);
543 return(true);
546 UINT CPicture::GetColorDepth() const
548 if (bIsIcon && lpIcons)
550 LPICONDIR lpIconDir = (LPICONDIR)lpIcons;
551 return lpIconDir->idEntries[nCurrentIcon].wBitCount;
554 // try first with WIC to get the pixel format since GDI+ often returns 32-bit even if it's not
555 // Create the image factory.
556 UINT bpp = 0;
557 IWICImagingFactory * pFactory = NULL;
558 HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory,
559 NULL,
560 CLSCTX_INPROC_SERVER,
561 IID_IWICImagingFactory,
562 (LPVOID*) &pFactory);
564 // Create a decoder from the file.
565 if (SUCCEEDED(hr))
567 IWICBitmapDecoder * pDecoder = NULL;
568 hr = pFactory->CreateDecoderFromFilename(m_Name.c_str(),
569 NULL,
570 GENERIC_READ,
571 WICDecodeMetadataCacheOnDemand,
572 &pDecoder);
573 if (SUCCEEDED(hr))
575 IWICBitmapFrameDecode * pBitmapFrameDecode = NULL;
576 hr = pDecoder->GetFrame(0, &pBitmapFrameDecode);
577 if (SUCCEEDED(hr))
579 IWICBitmapSource * pSource = NULL;
580 pSource = pBitmapFrameDecode;
581 pSource->AddRef();
582 WICPixelFormatGUID pixelFormat;
583 hr = pSource->GetPixelFormat(&pixelFormat);
584 if (SUCCEEDED(hr))
586 IWICComponentInfo * piCompInfo = NULL;
587 hr = pFactory->CreateComponentInfo(pixelFormat, &piCompInfo);
588 if (SUCCEEDED(hr))
590 IWICPixelFormatInfo * piPixelFormatInfo = NULL;
591 hr = piCompInfo->QueryInterface(IID_IWICPixelFormatInfo,(LPVOID *) &piPixelFormatInfo);
592 if (SUCCEEDED(hr))
594 hr = piPixelFormatInfo->GetBitsPerPixel(&bpp);
595 piPixelFormatInfo->Release();
597 piCompInfo->Release();
599 pSource->Release();
601 pBitmapFrameDecode->Release();
603 pDecoder->Release();
605 pFactory->Release();
607 if (bpp)
608 return bpp;
610 switch (GetPixelFormat())
612 case PixelFormat1bppIndexed:
613 return 1;
614 case PixelFormat4bppIndexed:
615 return 4;
616 case PixelFormat8bppIndexed:
617 return 8;
618 case PixelFormat16bppARGB1555:
619 case PixelFormat16bppGrayScale:
620 case PixelFormat16bppRGB555:
621 case PixelFormat16bppRGB565:
622 return 16;
623 case PixelFormat24bppRGB:
624 return 24;
625 case PixelFormat32bppARGB:
626 case PixelFormat32bppPARGB:
627 case PixelFormat32bppRGB:
628 return 32;
629 case PixelFormat48bppRGB:
630 // note: GDI+ converts images with bit depths > 32 automatically
631 // on loading, so PixelFormat48bppRGB, PixelFormat64bppARGB and
632 // PixelFormat64bppPARGB will never be used here.
633 return 48;
634 case PixelFormat64bppARGB:
635 case PixelFormat64bppPARGB:
636 return 64;
638 return 0;
641 UINT CPicture::GetNumberOfFrames(int dimension)
643 if (bIsIcon && lpIcons)
645 return 1;
647 if (pBitmap == NULL)
648 return 0;
649 UINT count = pBitmap->GetFrameDimensionsCount();
650 GUID* pDimensionIDs = (GUID*)malloc(sizeof(GUID)*count);
652 pBitmap->GetFrameDimensionsList(pDimensionIDs, count);
654 UINT frameCount = pBitmap->GetFrameCount(&pDimensionIDs[dimension]);
656 free(pDimensionIDs);
657 return frameCount;
660 UINT CPicture::GetNumberOfDimensions()
662 if (bIsIcon && lpIcons)
664 LPICONDIR lpIconDir = (LPICONDIR)lpIcons;
665 return lpIconDir->idCount;
667 return pBitmap ? pBitmap->GetFrameDimensionsCount() : 0;
670 long CPicture::SetActiveFrame(UINT frame)
672 if (bIsIcon && lpIcons)
674 nCurrentIcon = frame-1;
675 m_Height = GetHeight();
676 m_Width = GetWidth();
677 return 0;
679 if (pBitmap == NULL)
680 return 0;
681 UINT count = 0;
682 count = pBitmap->GetFrameDimensionsCount();
683 GUID* pDimensionIDs = (GUID*)malloc(sizeof(GUID)*count);
685 pBitmap->GetFrameDimensionsList(pDimensionIDs, count);
687 UINT frameCount = pBitmap->GetFrameCount(&pDimensionIDs[0]);
689 free(pDimensionIDs);
691 if (frame > frameCount)
692 return 0;
694 GUID pageGuid = FrameDimensionTime;
695 if (bIsTiff)
696 pageGuid = FrameDimensionPage;
697 pBitmap->SelectActiveFrame(&pageGuid, frame);
699 // Assume that the image has a property item of type PropertyItemEquipMake.
700 // Get the size of that property item.
701 int nSize = pBitmap->GetPropertyItemSize(PropertyTagFrameDelay);
703 // Allocate a buffer to receive the property item.
704 PropertyItem* pPropertyItem = (PropertyItem*) malloc(nSize);
706 Status s = pBitmap->GetPropertyItem(PropertyTagFrameDelay, nSize, pPropertyItem);
708 UINT prevframe = frame;
709 if (prevframe > 0)
710 prevframe--;
711 long delay = 0;
712 if (s == Ok)
714 delay = ((long*)pPropertyItem->value)[prevframe] * 10;
716 free(pPropertyItem);
717 m_Height = GetHeight();
718 m_Width = GetWidth();
719 return delay;
722 UINT CPicture::GetHeight() const
724 if ((bIsIcon)&&(lpIcons))
726 LPICONDIR lpIconDir = (LPICONDIR)lpIcons;
727 return lpIconDir->idEntries[nCurrentIcon].bHeight;
729 return pBitmap ? pBitmap->GetHeight() : 0;
732 UINT CPicture::GetWidth() const
734 if ((bIsIcon)&&(lpIcons))
736 LPICONDIR lpIconDir = (LPICONDIR)lpIcons;
737 return lpIconDir->idEntries[nCurrentIcon].bWidth;
739 return pBitmap ? pBitmap->GetWidth() : 0;
742 PixelFormat CPicture::GetPixelFormat() const
744 if ((bIsIcon)&&(lpIcons))
746 LPICONDIR lpIconDir = (LPICONDIR)lpIcons;
747 if (lpIconDir->idEntries[nCurrentIcon].wPlanes == 1)
749 if (lpIconDir->idEntries[nCurrentIcon].wBitCount == 1)
750 return PixelFormat1bppIndexed;
751 if (lpIconDir->idEntries[nCurrentIcon].wBitCount == 4)
752 return PixelFormat4bppIndexed;
753 if (lpIconDir->idEntries[nCurrentIcon].wBitCount == 8)
754 return PixelFormat8bppIndexed;
756 if (lpIconDir->idEntries[nCurrentIcon].wBitCount == 32)
758 return PixelFormat32bppARGB;
761 return pBitmap ? pBitmap->GetPixelFormat() : 0;