UWP 中的直接 2D SVG 渲染
Direct 2D SVG Rendering in UWP
我正在尝试调整 https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/D2DSvgImage 处的 Direct 2D SVG 示例以绘制 SVG 字符串而不是从文件中绘制。我所做的只是替换代码以从 Assets 文件打开流。以下是相关摘录:
void D2DSvgImageRenderer::CreateDeviceDependentResources()
{
auto d2dContext = m_deviceResources->GetD2DDeviceContext();
StorageFolder^ packageFolder = Windows::ApplicationModel::Package::Current->InstalledLocation;
// Retrieve the SVG file from the app package.
// ORIGINAL create_task(packageFolder->GetFileAsync("Assets\drawing.svg")).then([=](StorageFile^ file)
create_task([]()
{
// Open the SVG file for reading.
// ORIGINAL return file->OpenAsync(FileAccessMode::Read);
char *svg = "<svg><circle r=\"300\" cy=\"509\" cx=\"370\" style=\"fill:#ffff00;stroke:#000000;stroke-width:5\"/></svg>";
auto stream = ref new Windows::Storage::Streams::InMemoryRandomAccessStream();
auto writer = ref new Windows::Storage::Streams::DataWriter(stream);
auto p = svg;
while (*p != '[=10=]')
{
writer->WriteByte((unsigned char)*p);
p++;
}
create_task(writer->StoreAsync()).get();
create_task(writer->FlushAsync()).get();
return stream;
}).then([=](IRandomAccessStream^ stream)
{
// Wrap the WinRT stream with a COM stream.
ComPtr<IStream> iStream;
DX::ThrowIfFailed(
CreateStreamOverRandomAccessStream(
stream,
IID_PPV_ARGS(&iStream)
)
);
// Parse the file stream into an SVG document.
DX::ThrowIfFailed(
d2dContext->CreateSvgDocument(
iStream.Get(),
D2D1::SizeF(sc_svgSize, sc_svgSize), // Create the document at a size of 500x500 DIPs.
&m_svgDocument
)
);
});
}
但我总是得到莫名其妙的参数不正确异常,并且无法调试为什么会这样。 (DirectX 不提供任何调试方法或提供任何提示为什么以及哪个参数不正确!?)
我有根据的猜测是 API 从未告诉我们在 CreateSvgDocument
中使用 InMemoryRandomAccessStream
是 严格禁止 的隐藏事实。我该如何解决这个问题?
在抛出异常之前,此代码发出以下诊断信息:
D2D DEBUG ERROR - An error was encountered while parsing an SVG document.
当我尝试读取流内容时,我发现它已关闭(通过在下一个 lambda 中调用 stream->Position;
),也就是说 内容实际上不存在。然后我查看了文档。来自 DataWriter::Close
method reference:
Remarks
DataWriter
takes ownership of the stream that is passed to its constructor. Calling this method also calls on the associated stream. After calling this method, calls to most other DataWriter
methods will fail.
If you do not want the associated stream to be closed when the reader closes, call DataWriter.DetachStream
before calling this method.
因此在您的示例中,writer
将在超出范围时 Close
stream
并且 SVG 解析器将无法读取任何内容。所以你的代码应该是这样的:
auto stream{ref new Windows::Storage::Streams::InMemoryRandomAccessStream{}};
auto writer{ref new Windows::Storage::Streams::DataWriter{stream}}; // takes ownership of stream
const auto & sz_svg{"<svg><circle r=\"300\" cy=\"509\" cx=\"370\" style=\"fill:#ffff00;stroke:#000000;stroke-width:5\"/></svg>"};
for(const char * p{sz_svg}; '[=10=]' != *p; ++p)
{
writer->WriteByte(static_cast< unsigned char >(*p));
}
create_task(writer->StoreAsync()).get(); // mandatory
//create_task(writer->FlushAsync()).get(); // not necessary since underlaying memory stream does not require flushing
writer->DetachStream(); // release ownership of stream, the value returned is not used since we already have stream variable
PS 他们应该为构造函数写下那句话...
我正在尝试调整 https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/D2DSvgImage 处的 Direct 2D SVG 示例以绘制 SVG 字符串而不是从文件中绘制。我所做的只是替换代码以从 Assets 文件打开流。以下是相关摘录:
void D2DSvgImageRenderer::CreateDeviceDependentResources()
{
auto d2dContext = m_deviceResources->GetD2DDeviceContext();
StorageFolder^ packageFolder = Windows::ApplicationModel::Package::Current->InstalledLocation;
// Retrieve the SVG file from the app package.
// ORIGINAL create_task(packageFolder->GetFileAsync("Assets\drawing.svg")).then([=](StorageFile^ file)
create_task([]()
{
// Open the SVG file for reading.
// ORIGINAL return file->OpenAsync(FileAccessMode::Read);
char *svg = "<svg><circle r=\"300\" cy=\"509\" cx=\"370\" style=\"fill:#ffff00;stroke:#000000;stroke-width:5\"/></svg>";
auto stream = ref new Windows::Storage::Streams::InMemoryRandomAccessStream();
auto writer = ref new Windows::Storage::Streams::DataWriter(stream);
auto p = svg;
while (*p != '[=10=]')
{
writer->WriteByte((unsigned char)*p);
p++;
}
create_task(writer->StoreAsync()).get();
create_task(writer->FlushAsync()).get();
return stream;
}).then([=](IRandomAccessStream^ stream)
{
// Wrap the WinRT stream with a COM stream.
ComPtr<IStream> iStream;
DX::ThrowIfFailed(
CreateStreamOverRandomAccessStream(
stream,
IID_PPV_ARGS(&iStream)
)
);
// Parse the file stream into an SVG document.
DX::ThrowIfFailed(
d2dContext->CreateSvgDocument(
iStream.Get(),
D2D1::SizeF(sc_svgSize, sc_svgSize), // Create the document at a size of 500x500 DIPs.
&m_svgDocument
)
);
});
}
但我总是得到莫名其妙的参数不正确异常,并且无法调试为什么会这样。 (DirectX 不提供任何调试方法或提供任何提示为什么以及哪个参数不正确!?)
我有根据的猜测是 API 从未告诉我们在 CreateSvgDocument
中使用 InMemoryRandomAccessStream
是 严格禁止 的隐藏事实。我该如何解决这个问题?
在抛出异常之前,此代码发出以下诊断信息:
D2D DEBUG ERROR - An error was encountered while parsing an SVG document.
当我尝试读取流内容时,我发现它已关闭(通过在下一个 lambda 中调用 stream->Position;
),也就是说 内容实际上不存在。然后我查看了文档。来自 DataWriter::Close
method reference:
Remarks
DataWriter
takes ownership of the stream that is passed to its constructor. Calling this method also calls on the associated stream. After calling this method, calls to most otherDataWriter
methods will fail. If you do not want the associated stream to be closed when the reader closes, callDataWriter.DetachStream
before calling this method.
因此在您的示例中,writer
将在超出范围时 Close
stream
并且 SVG 解析器将无法读取任何内容。所以你的代码应该是这样的:
auto stream{ref new Windows::Storage::Streams::InMemoryRandomAccessStream{}};
auto writer{ref new Windows::Storage::Streams::DataWriter{stream}}; // takes ownership of stream
const auto & sz_svg{"<svg><circle r=\"300\" cy=\"509\" cx=\"370\" style=\"fill:#ffff00;stroke:#000000;stroke-width:5\"/></svg>"};
for(const char * p{sz_svg}; '[=10=]' != *p; ++p)
{
writer->WriteByte(static_cast< unsigned char >(*p));
}
create_task(writer->StoreAsync()).get(); // mandatory
//create_task(writer->FlushAsync()).get(); // not necessary since underlaying memory stream does not require flushing
writer->DetachStream(); // release ownership of stream, the value returned is not used since we already have stream variable
PS 他们应该为构造函数写下那句话...