aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2022-05-09 22:53:44 +0800
committercrupest <crupest@outlook.com>2022-05-09 22:53:44 +0800
commit3a60174667d7ff741ec4a90c3b5cfcc6fd2fd024 (patch)
tree567084b778fa2bd49b38491c3a513c08e25d08b8 /src
parent195007d4f00dd2c04a0f2859a8bfff7632a45530 (diff)
downloadcru-3a60174667d7ff741ec4a90c3b5cfcc6fd2fd024.tar.gz
cru-3a60174667d7ff741ec4a90c3b5cfcc6fd2fd024.tar.bz2
cru-3a60174667d7ff741ec4a90c3b5cfcc6fd2fd024.zip
...
Diffstat (limited to 'src')
-rw-r--r--src/win/graphics/direct/ImageFactory.cpp116
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