使用 WIC 成像组件编码动画 gif -> 无限循环
Encoding animated gif with WIC Imaging Component -> Infinite loop
我有一个 std::vector<> 的 IWICBitmapSource 并试图创建一个动画 gif:
void SaveGif()
{
CComPtr<IWICBitmapEncoder> wicBitmapEncoder;
auto hr =
fact->CreateEncoder(
GUID_ContainerFormatGif,
nullptr, // No preferred codec vendor.
&wicBitmapEncoder
);
VectorStream stream;
hr =
wicBitmapEncoder->Initialize(
&stream,
WICBitmapEncoderNoCache
);
for (auto& gox : Gifs)
{
CComPtr<IWICBitmapFrameEncode> wicFrameEncode;
hr =
wicBitmapEncoder->CreateNewFrame(
&wicFrameEncode,
0
);
hr =
wicFrameEncode->Initialize(bag2);
auto g2 = GUID_WICPixelFormat24bppRGB;
wicFrameEncode->SetPixelFormat(&g2);
WICRect wr = {};
UINT wi, he;
gox.second->GetSize(&wi,&he);
wr.Width = wi;
wr.Height = he;
hr = wicFrameEncode->WriteSource(gox.second, &wr);
hr = wicFrameEncode->Commit();
}
// save stream to gif file
}
所有功能都成功,最终文件是动画,但不是循环。它停在最后一帧。
如何让它无限循环?
All functions succeed, the final file is animating, but not looping.
It stops at the last frame.
How can I tell it to loop indefinitely?
默认情况下,循环次数为1
。正如您已经发现的那样,它只显示从第一帧到最后一帧然后停止。
为了让它无限循环,你需要将循环计数设置为0
,它指定动画应该无限显示。
以下是使用GDI+分两步创建无限循环动画gif的例子,您可以参考。
首先,制作多张gif图片。每个 gif 图像都有一个框架。为每个 gif 图像设置循环计数。
// Get the CLSID of the GIF encoder.
CLSID encoderClsid;
GetEncoderClsid(L"image/gif", &encoderClsid);
Image* singleFrameGif = new Image(fileName);
// Set the loop count.
PropertyItem* propItemLoopCount = new PropertyItem;
SHORT loopCount = 0; //A value of 0 specifies that the animation should be displayed infinitely.
propItemLoopCount->id = PropertyTagLoopCount;
propItemLoopCount->length = sizeof(loopCount);
propItemLoopCount->type = PropertyTagTypeShort;
propItemLoopCount->value = &loopCount;
singleFrameGif->SetPropertyItem(propItemLoopCount);
//Save this image to a file.
singleFrameGif->Save(newName, &encoderClsid, NULL);
其次,将创建的gif图片添加到一个文件中,组成多帧gif图片。
EncoderParameters encoderParameters;
ULONG parameterValue;
Status stat;
// An EncoderParameters object has an array of
// EncoderParameter objects. In this case, there is only
// one EncoderParameter object in the array.
encoderParameters.Count = 1;
// Initialize the one EncoderParameter object.
encoderParameters.Parameter[0].Guid = EncoderSaveFlag;
encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParameters.Parameter[0].NumberOfValues = 1;
encoderParameters.Parameter[0].Value = ¶meterValue;
// Create two image objects.
Image* multi = new Image(L"1.gif");
// Save the first page (frame).
parameterValue = EncoderValueMultiFrame;
stat = multi->Save(L"MultiFrame.gif", &encoderClsid, &encoderParameters);
if (stat == Ok)
printf("Page 1 saved successfully.\n");
Image* page2 = new Image(L"2.gif");
// Save the second page (frame).
parameterValue = EncoderValueFrameDimensionTime;
stat = multi->SaveAdd(page2, &encoderParameters);
if (stat == Ok)
printf("Page 2 saved successfully.\n");
// Close the multiframe file.
parameterValue = EncoderValueFlush;
stat = multi->SaveAdd(&encoderParameters);
if (stat == Ok)
printf("File closed successfully.\n");
使用 Simon Mourier 评论中的链接,我想出了这个片段并且它似乎有效(对于我的单个测试用例):
CComPtr<IWICMetadataQueryWriter> meta; // Get a metadata writer
wicBitmapEncoder->GetMetadataQueryWriter(&meta);
PROPVARIANT app = { 0 };
PROPVARIANT data = { 0 };
const char *appext = "NETSCAPE2.0"; // application that defined the extension
struct LoopCount // the data that is needed for the extension (see Simon's links)
{
unsigned char block_size = 3;
unsigned char block_id = 1;
unsigned short loopcount = 0;
} bData;
// Setup the PROPVARIANTS
PropVariantInit(&app);
PropVariantInit(&data);
data.vt = VT_UI1|VT_VECTOR;
app.vt = VT_UI1|VT_VECTOR;
app.cac.cElems = strlen(appext);
app.cac.pElems = (char *)appext;
data.cac.cElems = sizeof(LoopCount);
data.cac.pElems = (char *)&bData;
meta->SetMetadataByName(L"/appext/application", &app); // Write the metadata
meta->SetMetadataByName(L"/appext/data", &data);
我有一个 std::vector<> 的 IWICBitmapSource 并试图创建一个动画 gif:
void SaveGif()
{
CComPtr<IWICBitmapEncoder> wicBitmapEncoder;
auto hr =
fact->CreateEncoder(
GUID_ContainerFormatGif,
nullptr, // No preferred codec vendor.
&wicBitmapEncoder
);
VectorStream stream;
hr =
wicBitmapEncoder->Initialize(
&stream,
WICBitmapEncoderNoCache
);
for (auto& gox : Gifs)
{
CComPtr<IWICBitmapFrameEncode> wicFrameEncode;
hr =
wicBitmapEncoder->CreateNewFrame(
&wicFrameEncode,
0
);
hr =
wicFrameEncode->Initialize(bag2);
auto g2 = GUID_WICPixelFormat24bppRGB;
wicFrameEncode->SetPixelFormat(&g2);
WICRect wr = {};
UINT wi, he;
gox.second->GetSize(&wi,&he);
wr.Width = wi;
wr.Height = he;
hr = wicFrameEncode->WriteSource(gox.second, &wr);
hr = wicFrameEncode->Commit();
}
// save stream to gif file
}
所有功能都成功,最终文件是动画,但不是循环。它停在最后一帧。
如何让它无限循环?
All functions succeed, the final file is animating, but not looping. It stops at the last frame.
How can I tell it to loop indefinitely?
默认情况下,循环次数为1
。正如您已经发现的那样,它只显示从第一帧到最后一帧然后停止。
为了让它无限循环,你需要将循环计数设置为0
,它指定动画应该无限显示。
以下是使用GDI+分两步创建无限循环动画gif的例子,您可以参考。
首先,制作多张gif图片。每个 gif 图像都有一个框架。为每个 gif 图像设置循环计数。
// Get the CLSID of the GIF encoder.
CLSID encoderClsid;
GetEncoderClsid(L"image/gif", &encoderClsid);
Image* singleFrameGif = new Image(fileName);
// Set the loop count.
PropertyItem* propItemLoopCount = new PropertyItem;
SHORT loopCount = 0; //A value of 0 specifies that the animation should be displayed infinitely.
propItemLoopCount->id = PropertyTagLoopCount;
propItemLoopCount->length = sizeof(loopCount);
propItemLoopCount->type = PropertyTagTypeShort;
propItemLoopCount->value = &loopCount;
singleFrameGif->SetPropertyItem(propItemLoopCount);
//Save this image to a file.
singleFrameGif->Save(newName, &encoderClsid, NULL);
其次,将创建的gif图片添加到一个文件中,组成多帧gif图片。
EncoderParameters encoderParameters;
ULONG parameterValue;
Status stat;
// An EncoderParameters object has an array of
// EncoderParameter objects. In this case, there is only
// one EncoderParameter object in the array.
encoderParameters.Count = 1;
// Initialize the one EncoderParameter object.
encoderParameters.Parameter[0].Guid = EncoderSaveFlag;
encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParameters.Parameter[0].NumberOfValues = 1;
encoderParameters.Parameter[0].Value = ¶meterValue;
// Create two image objects.
Image* multi = new Image(L"1.gif");
// Save the first page (frame).
parameterValue = EncoderValueMultiFrame;
stat = multi->Save(L"MultiFrame.gif", &encoderClsid, &encoderParameters);
if (stat == Ok)
printf("Page 1 saved successfully.\n");
Image* page2 = new Image(L"2.gif");
// Save the second page (frame).
parameterValue = EncoderValueFrameDimensionTime;
stat = multi->SaveAdd(page2, &encoderParameters);
if (stat == Ok)
printf("Page 2 saved successfully.\n");
// Close the multiframe file.
parameterValue = EncoderValueFlush;
stat = multi->SaveAdd(&encoderParameters);
if (stat == Ok)
printf("File closed successfully.\n");
使用 Simon Mourier 评论中的链接,我想出了这个片段并且它似乎有效(对于我的单个测试用例):
CComPtr<IWICMetadataQueryWriter> meta; // Get a metadata writer
wicBitmapEncoder->GetMetadataQueryWriter(&meta);
PROPVARIANT app = { 0 };
PROPVARIANT data = { 0 };
const char *appext = "NETSCAPE2.0"; // application that defined the extension
struct LoopCount // the data that is needed for the extension (see Simon's links)
{
unsigned char block_size = 3;
unsigned char block_id = 1;
unsigned short loopcount = 0;
} bData;
// Setup the PROPVARIANTS
PropVariantInit(&app);
PropVariantInit(&data);
data.vt = VT_UI1|VT_VECTOR;
app.vt = VT_UI1|VT_VECTOR;
app.cac.cElems = strlen(appext);
app.cac.pElems = (char *)appext;
data.cac.cElems = sizeof(LoopCount);
data.cac.pElems = (char *)&bData;
meta->SetMetadataByName(L"/appext/application", &app); // Write the metadata
meta->SetMetadataByName(L"/appext/data", &data);