Reputation: 1267
I am trying to adapt the Direct 2D SVG sample at https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/D2DSvgImage to draw SVG string instead of from file. All I did was replacing the code to open a stream from an Assets file. Here is the relevant excerpt:
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
)
);
});
}
But I am always getting the inexplicable The parameter is incorrect exception and there is no way to debug as to why it is the case. (DirectX does NOT come with any way to debug or provide any hint why and which parameter is incorrect!?)
My educated guess is that the API never tell us the hidden fact that using InMemoryRandomAccessStream
in CreateSvgDocument
is strictly prohibited. How can I fix this?
Upvotes: 0
Views: 1205
Reputation: 37488
Before throwing exception this code emits the following diagnostic:
D2D DEBUG ERROR - An error was encountered while parsing an SVG document.
When I tried to read stream content I've figured out that it is closed (by calling stream->Position;
in the next lambda), that is the content is actually not there. Then I've looked into docs. From 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.
So in your example writer
will Close
stream
when it goes out of scope and SVG parser won't be able to read anything. So your code should look like this:
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 They should've written that remark for the constructor...
Upvotes: 1