和SharpDX坑爹的Variant刚正面
细心的网友也注意到了这个问题:
……但后来他备注说“已解决”,我当时也不知道该怎么解决的,所以我追问了一下,但他一直没有回复。但思路肯定是有的,再不济,也可以将保存为字节数组的数据,用其它的库进行重新解析,然后指定循环次数即可,当然这个方法肯定很搓,想象中较好的办法应该是调用SharpDX
内置的API
来完成。
踩坑之路
就此我开始了SharpDX
的踩坑之路,我找到了许多资料,找到不少示例代码,最后不断实验,最终成功。
C++示例
首先我在网上找到了SharpDX
生成循环gif
文件的C++
开源代码示例,代码源自于https://github.com/GarethRichards/GifSaver/blob/master/GifSaver.cpp:
PROPVARIANT propValue; PropVariantInit(&propValue); propValue.vt = VT_UI1 | VT_VECTOR; propValue.caub.cElems = 11; DX::ThrowIfFailed(m_imagingFactory->CreateEncoder(GUID_ContainerFormatGif, &GUID_VendorMicrosoft, &m_wicBitmapEncoder)); DX::ThrowIfFailed(m_wicBitmapEncoder->Initialize(m_stream.Get(), WICBitmapEncoderNoCache)); ComPtr<IWICMetadataQueryWriter> pEncoderMetadataQueryWriter; DX::ThrowIfFailed(m_wicBitmapEncoder->GetMetadataQueryWriter(&pEncoderMetadataQueryWriter)); string elms = "NETSCAPE2.0"; propValue.caub.pElems = const_cast<UCHAR *>(reinterpret_cast<const UCHAR *>(elms.c_str())); DX::ThrowIfFailed(pEncoderMetadataQueryWriter->SetMetadataByName(L"/appext/Application", &propValue)); // Set animated GIF format propValue.vt = VT_UI1 | VT_VECTOR; propValue.caub.cElems = 5; UCHAR buf[5]; propValue.caub.pElems = &buf[0]; *(propValue.caub.pElems) = 3; // must be > 1, *(propValue.caub.pElems + 1) = 1; // defines animated GIF *(propValue.caub.pElems + 2) = 0; // LSB 0 = infinite loop. *(propValue.caub.pElems + 3) = 0; // MSB of iteration count value *(propValue.caub.pElems + 4) = 0; // NULL == end of data DX::ThrowIfFailed(pEncoderMetadataQueryWriter->SetMetadataByName(L"/appext/Data", &propValue)); // ...
注意其中/appext/Data
实际本质是一个字节数组,其内容为3 1 0 0 0
,代表无限循环gif
(注释中说得很清楚),这就应该是循环gif
的关键所在。
可见,首先需要创建一个PROPVARIANT
对象,然后调用IWICBitmapEncoder
中的GetMetadataQueryWriter
方法,获取IWICMetadataQueryWriter
,然后通过该方法中的SetMetadataByName
,将/appext/Application
以及/appext/Data
按照指定的格式传入即可,还能有问题什么呢?
问题可大咯!
坑人的Variant
刚好