Skip to content

Instantly share code, notes, and snippets.

@JSandusky
Created March 31, 2018 19:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JSandusky/c2276330cdd33c7a31430dcc65efb2f3 to your computer and use it in GitHub Desktop.
Save JSandusky/c2276330cdd33c7a31430dcc65efb2f3 to your computer and use it in GitHub Desktop.
#include <Urho3D/Resource/Image.h>
#include <vector>
#include <set>
#include <windows.h>
#include <shlobj.h>
#include <Urho3D/DebugNew.h>
std::set<std::string> os_ThumbnailTried;
std::vector<unsigned char> HBitmapToPixels(HBITMAP bitmapHandle, int& width, int& height)
{
BITMAP bmp = { 0 };
BITMAPINFO bmpInfo = { 0 };
HDC dc = CreateCompatibleDC(NULL);
std::memset(&bmpInfo, 0, sizeof(BITMAPINFO)); //not necessary really..
HBITMAP oldBitmap = (HBITMAP)SelectObject(dc, bitmapHandle);
GetObject(bitmapHandle, sizeof(BITMAP), &bmp);
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biWidth = width = bmp.bmWidth;
bmpInfo.bmiHeader.biHeight = height = bmp.bmHeight;
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 32;
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biSizeImage = ((width * bmp.bmBitsPixel + 31) / 32) * 4 * height;
std::vector<unsigned char> pixelData = std::vector<unsigned char>();
pixelData.resize(bmpInfo.bmiHeader.biSizeImage);
GetDIBits(dc, bitmapHandle, 0, height, pixelData.data(), &bmpInfo, DIB_RGB_COLORS);
SelectObject(dc, oldBitmap);
height = std::abs(height);
DeleteDC(dc);
for (size_t i = 0; i < pixelData.size(); i += 4)
std::swap(pixelData[i], pixelData[i + 2]);
return pixelData;
}
std::wstring MultiByteToWideString(const std::string &str)
{
if (str.empty()) return std::wstring();
int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
std::wstring wstrTo(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
return wstrTo;
}
Urho3D::SharedPtr<Urho3D::Texture2D> CreateThumbnail(Urho3D::Context* ctx, const Urho3D::String& path, unsigned size)
{
Urho3D::SharedPtr<Urho3D::Texture2D> ret;
// Check if this thumbnail has been attempted, if so then early ut
// issue: previews that invalidate with file changes
// issue: cache outside of here, not just in resource cache (GetResource is slow for constant calling)
// issue: do any recognition of 'singular' icon outside of here (ie. *.xml files all using the same icon)
if (os_ThumbnailTried.find(path.CString()) != os_ThumbnailTried.end())
return ret;
os_ThumbnailTried.insert(path.CString());
IShellItem *shellItem;
WCHAR wideStr[MAX_PATH];
memset(wideStr, 0, sizeof(WCHAR) * MAX_PATH);
MultiByteToWideChar(CP_UTF8, MB_COMPOSITE, path.CString(), path.Length(), wideStr, MAX_PATH);
auto wStr = MultiByteToWideString(path.CString());
HRESULT hr = SHCreateItemFromParsingName(wStr.c_str(), NULL, IID_PPV_ARGS(&shellItem));
if (SUCCEEDED(hr))
{
IShellItemImageFactory* imageFactory;
hr = SHCreateItemFromParsingName(wStr.c_str(), NULL, IID_PPV_ARGS(&imageFactory));
if (SUCCEEDED(hr))
{
SIZE iconSize = { size, size };
HBITMAP thumbnail;
hr = imageFactory->GetImage(iconSize, SIIGBF_BIGGERSIZEOK, &thumbnail);
if (SUCCEEDED(hr))
{
int w = size, h = size;
auto pixelData = HBitmapToPixels(thumbnail, w, h);
if (w > 0 && h > 0)
{
Urho3D::UniquePtr<Urho3D::Image> img(new Urho3D::Image(ctx));
img->SetSize(w, h, 4);
memcpy(img->GetData(), pixelData.data(), pixelData.size());
ret = new Urho3D::Texture2D(ctx);
ret->SetData(img.Get(), true);
}
DeleteObject(thumbnail);
}
imageFactory->Release();
}
}
return ret;
}
@JSandusky
Copy link
Author

Code snippet for loading windows thumbnails into an Urho3D texture/image.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment