【问题标题】:Encoding animated gif with WIC Imaging Component -> Infinite loop使用 WIC 成像组件编码动画 gif -> 无限循环
【发布时间】:2020-07-17 14:31:25
【问题描述】:

我有一个 IWICBitmapSource 的 std::vector 并试图创建一个动画 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
}

所有功能都成功,最终文件正在动画,但没有循环。它在最后一帧停止。

如何让它无限循环?

【问题讨论】:

  • “但是没有动画,它只是显示一个静态图像。” - 您使用什么工具、应用程序或程序来验证这一点?
  • Windows照片查看器,我也上传到了facebook,我也在Photoshop里试过,甚至打不开。
  • @IInspectable 现在它正在工作(而不是缓存 Wics,我将它们放在创建中)知道如何制作 gif 循环吗? (编辑了 q)
  • 据我所知,循环不是动画 GIF 核心规范的一部分,但我不知道 WIC 是否支持这种非标准扩展。
  • 您必须在 WIC 中为 GIF vurdalakov.net/misc/gif/netscape-looping-application-extension 编写应用程序扩展,这意味着您要编写元数据,正好与此相反:github.com/pauldotknopf/WindowsSDK7-Samples/blob/master/…

标签: c++ winapi wic


【解决方案1】:

使用 Simon Mourier 评论中的链接,我想出了这个 sn-p,它似乎正在工作(对于我的单个测试用例):

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);

【讨论】:

  • 它有效。是否有类似的元数据来设置每个帧的持续时间?
  • 找到了。 /grctlext/Delay 具有 10 毫秒的延迟单元。
【解决方案2】:

所有功能都成功,最终文件正在动画,但没有循环。 它在最后一帧停止。

如何让它无限循环?

默认情况下,循环计数为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 = &parameterValue;

// 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");

更多参考:“Creating and Saving a Multiple-Frame Image”。

【讨论】:

  • 我问的是 WIC,而不是 GDI+。
  • @MichaelChourdakis 根据 WIC 的GIF Metadata 文档,没有定义这样的循环计数。并且 loop count 在 GIF 标准中没有定义。因此,一种解决方法可能是使用其他有效工具来设置此值或使用 GDI+。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多