HBITMAP ImageDecoder::convertFrameToBitmap(IWICBitmapFrameDecode *frame) { IWICBitmapSource *bitmapSource = frame; if (FAILED(WICConvertBitmapSource(GUID_WICPixelFormat32bppPBGRA, frame, &bitmapSource))) { throw Exception("could not convert bitmap"); } UINT width = 0; UINT height = 0; if (FAILED(bitmapSource->GetSize(&width, &height)) || width == 0 || height == 0) { throw Exception("could not get image size"); } std::vector<BYTE> buffer(width * height * 4); if (FAILED(bitmapSource->CopyPixels(NULL, width * 4, buffer.size(), &buffer[0]))) { throw Exception("could not get image size"); } bitmapSource->Release(); return CreateBitmap(width, height, 1, 32, &buffer[0]); }
//---------------------------------------------------------------------------- Texture2* WICFileIO::Load(std::string const& filename, bool wantMipmaps) { // Start COM and create WIC. ComInitializer comInitializer; if (!comInitializer.IsInitialized()) { LogError("Unable to initialize COM for WIC."); return nullptr; } // Create a WIC imaging factory. ComObject<IWICImagingFactory> wicFactory; HRESULT hr = ::CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, reinterpret_cast<LPVOID*>(&wicFactory)); if (FAILED(hr)) { LogError("Unable to create WIC imaging factory."); return nullptr; } // Create a decoder based on the file name. std::wstring wfilename = Environment::Convert(filename); ComObject<IWICBitmapDecoder> wicDecoder; hr = wicFactory->CreateDecoderFromFilename(wfilename.c_str(), nullptr, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &wicDecoder); if (FAILED(hr)) { LogError("wicFactory->CreateDecoderFromFilename failed (" + filename + ")."); return nullptr; } // Create a WIC decoder. ComObject<IWICBitmapFrameDecode> wicFrameDecode; hr = wicDecoder->GetFrame(0, &wicFrameDecode); if (FAILED(hr)) { LogError("wicDecoder->GetFrame failed."); return nullptr; } // Get the pixel format of the image. WICPixelFormatGUID wicSourceGUID; hr = wicFrameDecode->GetPixelFormat(&wicSourceGUID); if (FAILED(hr)) { LogError("wicFrameDecode->GetPixelFormat failed."); return nullptr; } // Find the supported WIC input pixel format that matches a Texture2 // format. If a matching format is not found, the returned texture // is an R8G8B8A8 format with texels converted from the source format. WICPixelFormatGUID wicConvertGUID = GUID_WICPixelFormat32bppRGBA; DFType gtformat = DF_R8G8B8A8_UNORM; for (int i = 0; i < NUM_LOAD_FORMATS; ++i) { if (IsEqualGUID(wicSourceGUID, *msLoadFormatMap[i].wicInputGUID)) { // Determine whether there is a conversion format. if (msLoadFormatMap[i].wicConvertGUID) { wicConvertGUID = *msLoadFormatMap[i].wicConvertGUID; } else { wicConvertGUID = *msLoadFormatMap[i].wicInputGUID; } gtformat = msLoadFormatMap[i].gtFormat; break; } } // The wicFrameDecode value is used for no conversion. If the decoder // does not support the format in the texture, then a conversion is // required. IWICBitmapSource* wicBitmapSource = wicFrameDecode; ComObject<IWICFormatConverter> wicFormatConverter; if (!IsEqualGUID(wicSourceGUID, wicConvertGUID)) { // Create a WIC format converter. hr = wicFactory->CreateFormatConverter(&wicFormatConverter); if (FAILED(hr)) { LogError("wicFactory->CreateFormatConverter failed."); return false; } // Initialize format converter to convert the input texture format // to the nearest format supported by the decoder. hr = wicFormatConverter->Initialize(wicFrameDecode, wicConvertGUID, WICBitmapDitherTypeNone, nullptr, 0.0, WICBitmapPaletteTypeCustom); if (FAILED(hr)) { LogError("wicFormatConverter->Initialize failed."); return false; } // Use the format converter. wicBitmapSource = wicFormatConverter; } // Get the image dimensions. UINT width, height; hr = wicBitmapSource->GetSize(&width, &height); if (FAILED(hr)) { LogError("wicBitmapSource->GetSize failed."); return nullptr; } // Create the 2D texture and compute the stride and image size. std::unique_ptr<Texture2> texture(new Texture2(gtformat, width, height, wantMipmaps)); UINT const stride = width * texture->GetElementSize(); UINT const imageSize = stride * height; // Copy the pixels from the decoder to the texture. hr = wicBitmapSource->CopyPixels(nullptr, stride, imageSize, texture->Get<BYTE>()); if (FAILED(hr)) { LogError("wicBitmapSource->CopyPixels failed."); return nullptr; } return texture.release(); }
HBITMAP ImageUtil::LoadImage(string path) { size_t pathFileExtDot = path.find_last_of('.'); if (pathFileExtDot == string::npos || pathFileExtDot + 1 >= path.length()) throw INETRException("[imgLoadFailed]"); string ext = path.substr(pathFileExtDot + 1); const GUID *decoderCLSID = nullptr; if (ext == "png") decoderCLSID = &CLSID_WICPngDecoder; else if (ext == "bmp") decoderCLSID = &CLSID_WICBmpDecoder; else if (ext == "gif") decoderCLSID = &CLSID_WICGifDecoder; else if (ext == "jpg" || ext == "jpeg") decoderCLSID = &CLSID_WICJpegDecoder; if (decoderCLSID == nullptr) throw INETRException("[unsupportedImg]: " + ext); IStream *pngFileStream; if (FAILED(SHCreateStreamOnFile(path.c_str(), STGM_READ, &pngFileStream))) throw INETRException("[imgLoadFailed]:\n" + path); IWICBitmapDecoder *bmpDecoder = nullptr; if (FAILED(CoCreateInstance(*decoderCLSID, nullptr, CLSCTX_INPROC_SERVER, __uuidof(bmpDecoder), reinterpret_cast<void**>(&bmpDecoder)))) throw INETRException("[imgDecFailed]"); if (FAILED(bmpDecoder->Initialize(pngFileStream, WICDecodeMetadataCacheOnLoad))) { bmpDecoder->Release(); throw INETRException("[imgDecFailed]"); } UINT bmpFrameCount = 0; if (FAILED(bmpDecoder->GetFrameCount(&bmpFrameCount)) && bmpFrameCount != 1) { bmpDecoder->Release(); throw INETRException("[imgDecFailed]"); } IWICBitmapFrameDecode *bmpFrame = nullptr; if (FAILED(bmpDecoder->GetFrame(0, &bmpFrame))) { bmpDecoder->Release(); throw INETRException("[imgDecFailed]"); } IWICBitmapSource *bmpSource = nullptr; WICConvertBitmapSource(GUID_WICPixelFormat32bppPBGRA, bmpFrame, &bmpSource); bmpFrame->Release(); bmpDecoder->Release(); UINT width = 0, height = 0; if (FAILED(bmpSource->GetSize(&width, &height)) || width == 0 || height == 0) throw INETRException("[imgDecFailed]"); BITMAPINFO bmInfo; ZeroMemory(&bmInfo, sizeof(bmInfo)); bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmInfo.bmiHeader.biWidth = width; bmInfo.bmiHeader.biHeight = -((LONG)height); bmInfo.bmiHeader.biPlanes = 1; bmInfo.bmiHeader.biBitCount = 32; bmInfo.bmiHeader.biCompression = BI_RGB; HBITMAP hbmp = nullptr; void *imageBits = nullptr; HDC screenDC = GetDC(nullptr); hbmp = CreateDIBSection(screenDC, &bmInfo, DIB_RGB_COLORS, &imageBits, nullptr, 0); ReleaseDC(nullptr, screenDC); if (hbmp == nullptr) throw INETRException("[imgDecFailed]"); const UINT bmpStride = width * 4; const UINT bmpSize = bmpStride * height; if (FAILED(bmpSource->CopyPixels(nullptr, bmpStride, bmpSize, static_cast<BYTE*>(imageBits)))) { DeleteObject(hbmp); hbmp = nullptr; throw INETRException("[imgDecFailed]"); } bmpSource->Release(); return hbmp; }