C++ 使用WIC成像组件编码动画gif->;无限循环

C++ 使用WIC成像组件编码动画gif->;无限循环,c++,winapi,wic,C++,Winapi,Wic,我有一个IWICBitmapSource的std::vector,并试图创建一个动画gif: void SaveGif() { CComPtr<IWICBitmapEncoder> wicBitmapEncoder; auto hr = fact->CreateEncoder( GUID_ContainerFormatGif, nullptr, // No preferred codec ve

我有一个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
}
void SaveGif()
{
CComPtr wicBitmapEncoder;
汽车人力资源=
事实->创建编码器(
GUID\u包含ATGIF,
nullptr,//没有首选编解码器供应商。
&wicBitmapEncoder
);
矢量流;
人力资源=
wicBitmapEncoder->初始化(
&溪流,
WICBitmapEncoderNoCache
);
用于(自动和gox:Gifs)
{
CComPtr WICFRAME编码;
人力资源=
wicBitmapEncoder->CreateNewFrame(
&wicFrameEncode,
0
);
人力资源=
WICFRAMENCODE->初始化(bag2);
自动g2=GUID_WICPixelFormat24bppRGB;
wicFrameEncode->SetPixelFormat(&g2);
wicorct wr={};
他说,;
gox.second->GetSize(&wi,&he);
宽度=wi;
wr.高度=he;
hr=wicFrameEncode->WriteSource(gox.second,&wr);
hr=wicFrameEncode->Commit();
}
//将流保存到gif文件
}
所有函数均成功,最终文件将设置动画,但不会循环。它在最后一帧停止

我如何告诉它无限循环

所有函数均成功,最终文件将设置动画,但不会循环。 它在最后一帧停止

我如何告诉它无限循环

默认情况下,循环计数为
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);
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");
其次,将创建的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);
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");
更多参考资料:“”

所有函数均成功,最终文件将设置动画,但不会循环。 它在最后一帧停止

我如何告诉它无限循环

默认情况下,循环计数为
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);
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");
其次,将创建的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);
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");

更多参考:“。

使用Simon Mourier评论中的链接,我想出了这个片段,它似乎可以工作(对于我的单个测试用例):

CComPtr meta;//找一个元数据编写器
wicBitmapEncoder->GetMetadataQueryWriter(&meta);
PROPVARIANT app={0};
PROPVARIANT数据={0};
const char*appext=“NETSCAPE2.0”//定义扩展的应用程序
struct LoopCount//扩展所需的数据(参见Simon的链接)
{
无符号字符块大小=3;
无符号字符块_id=1;
无符号短循环计数=0;
}b数据;
//设置PROPVARIANTS
普伐他汀(&app);
普伐他汀(和数据);
data.vt=vt_UI1 | vt_矢量;
app.vt=vt_UI1 | vt_矢量;
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);//编写元数据
meta->SetMetadataByName(L)/appext/data“,&data);

使用Simon Mourier评论中的链接,我想出了这个片段,它似乎可以工作(对于我的单个测试用例):

CComPtr meta;//找一个元数据编写器
wicBitmapEncoder->GetMetadataQueryWriter(&meta);
PROPVARIANT app={0};
PROPVARIANT数据={0};
const char*appext=“NETSCAPE2.0”//定义扩展的应用程序
struct LoopCount//扩展所需的数据(参见Simon的链接)
{
无符号字符块大小=3;
无符号字符块_id=1;
无符号短循环计数=0;
}b数据;
//设置PROPVARIANTS
普伐他汀(&app);
普伐他汀(和数据);
data.vt=vt_UI1 | vt_矢量;
app.vt=vt_UI1 | vt_矢量;
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);//编写元数据
meta->SetMetadataByName(L)/appext/data“,&data);

“但是没有动画发生,它只是显示一个静态图像。”-您使用了什么工具、应用程序或过程来验证这一点?Windows photo viewer,我也将其上载到facebook,我也在Photoshop中尝试过,但它甚至无法打开。@IInspectable现在它正在工作(我没有缓存WIC,而是将它们放在创建中)知道如何制作gif循环吗?(编辑q)据我所知,循环不是动画GIF的核心规范的一部分,尽管我不知道WIC是否支持这种非标准扩展。你必须在WIC中为GIF编写应用程序扩展。这意味着你要编写元数据,与此正好相反:“但是没有动画发生,它只显示静态图像。”-您使用了什么工具、应用程序或过程来验证这一点?Windows photo viewer,我也将其上载到facebook,我也在Photoshop中尝试了它,但它甚至无法打开。@IInspectable现在它正在工作(而不是缓存WIC,我将其置于创建状态)知道如何制作gif循环吗?(编辑了q)据我所知,循环不是核心特定功能的一部分