diff options
author | crupest <crupest@outlook.com> | 2022-05-09 22:53:44 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2022-05-09 22:53:44 +0800 |
commit | 3a60174667d7ff741ec4a90c3b5cfcc6fd2fd024 (patch) | |
tree | 567084b778fa2bd49b38491c3a513c08e25d08b8 /src | |
parent | 195007d4f00dd2c04a0f2859a8bfff7632a45530 (diff) | |
download | cru-3a60174667d7ff741ec4a90c3b5cfcc6fd2fd024.tar.gz cru-3a60174667d7ff741ec4a90c3b5cfcc6fd2fd024.tar.bz2 cru-3a60174667d7ff741ec4a90c3b5cfcc6fd2fd024.zip |
...
Diffstat (limited to 'src')
-rw-r--r-- | src/win/graphics/direct/ImageFactory.cpp | 116 |
1 files changed, 103 insertions, 13 deletions
diff --git a/src/win/graphics/direct/ImageFactory.cpp b/src/win/graphics/direct/ImageFactory.cpp index 49fc49e8..9a90bdca 100644 --- a/src/win/graphics/direct/ImageFactory.cpp +++ b/src/win/graphics/direct/ImageFactory.cpp @@ -1,11 +1,17 @@ #include "cru/win/graphics/direct/ImageFactory.h" #include "cru/common/platform/win/Exception.h" #include "cru/common/platform/win/StreamConvert.h" +#include "cru/platform/Check.h" #include "cru/win/graphics/direct/Exception.h" #include "cru/win/graphics/direct/Factory.h" #include "cru/win/graphics/direct/Image.h" +#include <d2d1_1.h> +#include <d2d1_1helper.h> +#include <d2d1helper.h> +#include <dcommon.h> #include <wincodec.h> +#include <wrl/client.h> namespace cru::platform::graphics::win::direct { WinImageFactory::WinImageFactory(DirectGraphicsFactory* graphics_factory) @@ -19,6 +25,8 @@ WinImageFactory::WinImageFactory(DirectGraphicsFactory* graphics_factory) WinImageFactory::~WinImageFactory() {} std::unique_ptr<IImage> WinImageFactory::DecodeFromStream(io::Stream* stream) { + auto graphics_factory = GetDirectFactory(); + HRESULT hr; Microsoft::WRL::ComPtr<IStream> com_stream( @@ -34,32 +42,114 @@ std::unique_ptr<IImage> WinImageFactory::DecodeFromStream(io::Stream* stream) { hr = wic_bitmap_decoder->GetFrame(0, &wic_bitmap_frame_decode); ThrowIfFailed(hr); - auto d2d_context = graphics_factory_->GetDefaultD2D1DeviceContext(); + auto d2d_context = graphics_factory->GetDefaultD2D1DeviceContext(); Microsoft::WRL::ComPtr<ID2D1Bitmap1> d2d_image; - d2d_context->CreateBitmapFromWicBitmap(wic_bitmap_frame_decode.Get(), NULL, - &d2d_image); + d2d_context->CreateBitmapFromWicBitmap( + wic_bitmap_frame_decode.Get(), + D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET, + D2D1::PixelFormat(DXGI_FORMAT_R8G8B8A8_UINT, + D2D1_ALPHA_MODE_PREMULTIPLIED)), + &d2d_image); - return std::make_unique<Direct2DImage>(graphics_factory_, + return std::make_unique<Direct2DImage>(graphics_factory, std::move(d2d_image)); } +GUID ConvertImageFormatToGUID(ImageFormat format) { + GUID format_guid; + switch (format) { + case ImageFormat::Png: + format_guid = GUID_ContainerFormatPng; + break; + case ImageFormat::Jpeg: + format_guid = GUID_ContainerFormatJpeg; + break; + case ImageFormat::Gif: + format_guid = GUID_ContainerFormatGif; + break; + default: + throw Exception(u"Unknown image format"); + } + return format_guid; +} + +void WinImageFactory::EncodeToStream(IImage* image, io::Stream* stream, + ImageFormat format, float quality) { + auto direct_image = CheckPlatform<Direct2DImage>(image, GetPlatformId()); + + Microsoft::WRL::ComPtr<IStream> com_stream( + platform::win::ConvertStreamToComStream(stream)); + + Microsoft::WRL::ComPtr<IWICBitmapEncoder> wic_bitmap_encoder; + + ThrowIfFailed(wic_imaging_factory_->CreateEncoder( + ConvertImageFormatToGUID(format), nullptr, &wic_bitmap_encoder)); + + ThrowIfFailed(wic_bitmap_encoder->Initialize(com_stream.Get(), + WICBitmapEncoderNoCache)); + + Microsoft::WRL::ComPtr<IWICBitmapFrameEncode> wic_bitmap_frame_encode; + Microsoft::WRL::ComPtr<IPropertyBag2> property_bag; + ThrowIfFailed(wic_bitmap_encoder->CreateNewFrame(&wic_bitmap_frame_encode, + &property_bag)); + + if (format == ImageFormat::Jpeg) { + PROPBAG2 option = {0}; + option.pstrName = const_cast<wchar_t*>(L"ImageQuality"); + VARIANT varValue; + VariantInit(&varValue); + varValue.vt = VT_R4; + varValue.fltVal = quality; + ThrowIfFailed(property_bag->Write(1, &option, &varValue)); + } + + ThrowIfFailed(wic_bitmap_frame_encode->Initialize(property_bag.Get())); + + auto d2d_bitmap = direct_image->GetD2DBitmap(); + auto size = d2d_bitmap->GetSize(); + FLOAT dpi_x, dpi_y; + d2d_bitmap->GetDpi(&dpi_x, &dpi_y); + auto pixel_format = d2d_bitmap->GetPixelFormat(); + Ensures(pixel_format.format == DXGI_FORMAT_R8G8B8A8_UINT); + Ensures(pixel_format.alphaMode == D2D1_ALPHA_MODE_PREMULTIPLIED); + + ThrowIfFailed(wic_bitmap_frame_encode->SetSize(size.width, size.height)); + ThrowIfFailed(wic_bitmap_frame_encode->SetResolution(dpi_x, dpi_y)); + + GUID wic_pixel_format = GUID_WICPixelFormat32bppPRGBA; + ThrowIfFailed(wic_bitmap_frame_encode->SetPixelFormat(&wic_pixel_format)); + + D2D1_MAPPED_RECT mapped_rect; + ThrowIfFailed(d2d_bitmap->Map(D2D1_MAP_OPTIONS_READ, &mapped_rect)); + + ThrowIfFailed(wic_bitmap_frame_encode->WritePixels( + size.height, mapped_rect.pitch, size.height * mapped_rect.pitch, + mapped_rect.bits)); + + ThrowIfFailed(d2d_bitmap->Unmap()); + + ThrowIfFailed(wic_bitmap_frame_encode->Commit()); + + ThrowIfFailed(wic_bitmap_encoder->Commit()); +} + std::unique_ptr<IImage> WinImageFactory::CreateBitmap(int width, int height) { if (width <= 0) throw Exception(u"Bitmap width must be greater than 0."); if (height <= 0) throw Exception(u"Bitmap height must be greater than 0."); - Microsoft::WRL::ComPtr<ID2D1Bitmap> bitmap; + auto graphics_factory = GetDirectFactory(); + + Microsoft::WRL::ComPtr<ID2D1Bitmap1> bitmap; - auto d2d_context = graphics_factory_->GetDefaultD2D1DeviceContext(); + auto d2d_context = graphics_factory->GetDefaultD2D1DeviceContext(); d2d_context->CreateBitmap( - D2D1::SizeU(width, height), - D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_R8G8B8A8_UINT, - D2D1_ALPHA_MODE_STRAIGHT)), + D2D1::SizeU(width, height), nullptr, 0, + D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET, + D2D1::PixelFormat(DXGI_FORMAT_R8G8B8A8_UINT, + D2D1_ALPHA_MODE_PREMULTIPLIED)), &bitmap); - Microsoft::WRL::ComPtr<ID2D1Bitmap1> bitmap1; - ThrowIfFailed(bitmap.As(&bitmap1), "Failed to convert bitmap to bitmap1."); - - return std::make_unique<Direct2DImage>(graphics_factory_, std::move(bitmap1)); + return std::make_unique<Direct2DImage>(graphics_factory, std::move(bitmap)); } } // namespace cru::platform::graphics::win::direct |