【问题标题】:Direct 2D SVG Rendering in UWPUWP 中的直接 2D SVG 渲染
【发布时间】:2018-03-23 21:33:08
【问题描述】:

我正在尝试调整 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 != '\0')
        {
            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严格禁止的隐藏事实。我该如何解决这个问题?

【问题讨论】:

  • 你在什么时候得到这个异常?
  • 第二个 ThrowIfFailed 即对 CreateSvgDocument 的调用。我可以确认之前通话中的 iStream 内容正确。
  • 看来你还没写完呢。您可能需要调用writer.StoreAsync(),然后调用writer.FlushAsync(),如InMemoryRandomAccessStream Class usage example 中所述。
  • @VTT 正如前面评论中提到的,我可以完美地回读在CreateSvgDocument 之前创建的iStream内容确实存在。可以肯定的是,我刚刚测试过,即使使用 StoreAsyncFlushAsync,它仍然会崩溃。

标签: c++ uwp directx


【解决方案1】:

在抛出异常之前,此代码会发出以下诊断信息:

D2D 调试错误 - 解析 SVG 文档时遇到错误。

当我尝试读取流内容时,我发现它已关闭(通过在下一个 lambda 中调用 stream-&gt;Position;),即内容实际上不存在。然后我查看了文档。来自DataWriter::Close method reference

备注

DataWriter 获得传递给其构造函数的流的所有权。调用此方法还会调用关联的流。调用此方法后,对大多数其他DataWriter 方法的调用将失败。 如果您不想在阅读器关闭时关闭关联的流,请在调用此方法之前调用DataWriter.DetachStream

因此,在您的示例中,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}; '\0' != *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 他们应该已经为构造函数写了那句话......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-10
    • 2010-11-05
    • 2020-05-28
    • 1970-01-01
    • 1970-01-01
    • 2019-11-10
    • 2013-11-04
    • 2017-10-20
    相关资源
    最近更新 更多