155 lines
4.8 KiB
C++
155 lines
4.8 KiB
C++
#include "NativeRendererSupport.h"
|
|
|
|
namespace XCEngine::UI::Editor::Host {
|
|
|
|
using namespace NativeRendererSupport;
|
|
|
|
bool NativeRenderer::CaptureToPng(
|
|
const ::XCEngine::UI::UIDrawData& drawData,
|
|
UINT width,
|
|
UINT height,
|
|
const std::filesystem::path& outputPath,
|
|
std::string& outError) {
|
|
outError.clear();
|
|
if (width == 0 || height == 0) {
|
|
outError = "CaptureToPng rejected an empty render size.";
|
|
return false;
|
|
}
|
|
|
|
if (!m_d2dFactory || !m_dwriteFactory) {
|
|
outError = "CaptureToPng requires an initialized NativeRenderer.";
|
|
return false;
|
|
}
|
|
|
|
if (!EnsureWicFactory(outError)) {
|
|
return false;
|
|
}
|
|
|
|
std::error_code errorCode = {};
|
|
std::filesystem::create_directories(outputPath.parent_path(), errorCode);
|
|
if (errorCode) {
|
|
outError = "Failed to create screenshot directory: " + outputPath.parent_path().string();
|
|
return false;
|
|
}
|
|
|
|
Microsoft::WRL::ComPtr<IWICBitmap> bitmap;
|
|
HRESULT hr = m_wicFactory->CreateBitmap(
|
|
width,
|
|
height,
|
|
GUID_WICPixelFormat32bppPBGRA,
|
|
WICBitmapCacheOnLoad,
|
|
bitmap.ReleaseAndGetAddressOf());
|
|
if (FAILED(hr)) {
|
|
outError = HrToString("IWICImagingFactory::CreateBitmap", hr);
|
|
return false;
|
|
}
|
|
|
|
const D2D1_RENDER_TARGET_PROPERTIES renderTargetProperties = D2D1::RenderTargetProperties(
|
|
D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
|
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
|
|
kBaseDpi,
|
|
kBaseDpi);
|
|
|
|
Microsoft::WRL::ComPtr<ID2D1RenderTarget> offscreenRenderTarget;
|
|
hr = m_d2dFactory->CreateWicBitmapRenderTarget(
|
|
bitmap.Get(),
|
|
renderTargetProperties,
|
|
offscreenRenderTarget.ReleaseAndGetAddressOf());
|
|
if (FAILED(hr)) {
|
|
outError = HrToString("ID2D1Factory::CreateWicBitmapRenderTarget", hr);
|
|
return false;
|
|
}
|
|
|
|
Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> offscreenBrush;
|
|
hr = offscreenRenderTarget->CreateSolidColorBrush(
|
|
D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f),
|
|
offscreenBrush.ReleaseAndGetAddressOf());
|
|
if (FAILED(hr)) {
|
|
outError = HrToString("ID2D1RenderTarget::CreateSolidColorBrush", hr);
|
|
return false;
|
|
}
|
|
|
|
const bool rendered = RenderToTarget(*offscreenRenderTarget.Get(), *offscreenBrush.Get(), drawData);
|
|
hr = offscreenRenderTarget->EndDraw();
|
|
if (!rendered || FAILED(hr)) {
|
|
outError = HrToString("ID2D1RenderTarget::EndDraw", hr);
|
|
return false;
|
|
}
|
|
|
|
const std::wstring wideOutputPath = outputPath.wstring();
|
|
Microsoft::WRL::ComPtr<IWICStream> stream;
|
|
hr = m_wicFactory->CreateStream(stream.ReleaseAndGetAddressOf());
|
|
if (FAILED(hr)) {
|
|
outError = HrToString("IWICImagingFactory::CreateStream", hr);
|
|
return false;
|
|
}
|
|
|
|
hr = stream->InitializeFromFilename(wideOutputPath.c_str(), GENERIC_WRITE);
|
|
if (FAILED(hr)) {
|
|
outError = HrToString("IWICStream::InitializeFromFilename", hr);
|
|
return false;
|
|
}
|
|
|
|
Microsoft::WRL::ComPtr<IWICBitmapEncoder> encoder;
|
|
hr = m_wicFactory->CreateEncoder(GUID_ContainerFormatPng, nullptr, encoder.ReleaseAndGetAddressOf());
|
|
if (FAILED(hr)) {
|
|
outError = HrToString("IWICImagingFactory::CreateEncoder", hr);
|
|
return false;
|
|
}
|
|
|
|
hr = encoder->Initialize(stream.Get(), WICBitmapEncoderNoCache);
|
|
if (FAILED(hr)) {
|
|
outError = HrToString("IWICBitmapEncoder::Initialize", hr);
|
|
return false;
|
|
}
|
|
|
|
Microsoft::WRL::ComPtr<IWICBitmapFrameEncode> frame;
|
|
Microsoft::WRL::ComPtr<IPropertyBag2> propertyBag;
|
|
hr = encoder->CreateNewFrame(frame.ReleaseAndGetAddressOf(), propertyBag.ReleaseAndGetAddressOf());
|
|
if (FAILED(hr)) {
|
|
outError = HrToString("IWICBitmapEncoder::CreateNewFrame", hr);
|
|
return false;
|
|
}
|
|
|
|
hr = frame->Initialize(propertyBag.Get());
|
|
if (FAILED(hr)) {
|
|
outError = HrToString("IWICBitmapFrameEncode::Initialize", hr);
|
|
return false;
|
|
}
|
|
|
|
hr = frame->SetSize(width, height);
|
|
if (FAILED(hr)) {
|
|
outError = HrToString("IWICBitmapFrameEncode::SetSize", hr);
|
|
return false;
|
|
}
|
|
|
|
WICPixelFormatGUID pixelFormat = GUID_WICPixelFormat32bppPBGRA;
|
|
hr = frame->SetPixelFormat(&pixelFormat);
|
|
if (FAILED(hr)) {
|
|
outError = HrToString("IWICBitmapFrameEncode::SetPixelFormat", hr);
|
|
return false;
|
|
}
|
|
|
|
hr = frame->WriteSource(bitmap.Get(), nullptr);
|
|
if (FAILED(hr)) {
|
|
outError = HrToString("IWICBitmapFrameEncode::WriteSource", hr);
|
|
return false;
|
|
}
|
|
|
|
hr = frame->Commit();
|
|
if (FAILED(hr)) {
|
|
outError = HrToString("IWICBitmapFrameEncode::Commit", hr);
|
|
return false;
|
|
}
|
|
|
|
hr = encoder->Commit();
|
|
if (FAILED(hr)) {
|
|
outError = HrToString("IWICBitmapEncoder::Commit", hr);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace XCEngine::UI::Editor::Host
|