音視訊入門-19-使用giflib處理GIF圖片
阿新 • • 發佈:2021-01-11
GIFLIB
上一篇 【手動生成一張GIF圖片】, 自己生成了一張 GIF 動態圖 rainbow.gif
。
下面,使用 GIFLIB 分離出 GIF 每一幀的 RGB ,然後將分離出的 RGB 再合成 GIF。
GIF to RGB
GIFLIB 專案裡的 gif2rgb.c
已經實現瞭解碼 GIF -> RGB。不過 gif2rgb.c
只儲存了最後一幀圖片的 RGB,這裡需要改造。
gif2rgb.c
gif2rgb.c
在 GIF2RGB 方法最後才呼叫 DumpScreen2RGB 儲存 RGB。
...... static void DumpScreen2RGB(char *FileName, ColorMapObject *ColorMap, GifRowType *ScreenBuffer, int ScreenWidth, int ScreenHeight) { ...... } static void GIF2RGB(int NumFiles, char *FileName, bool OneFileFlag, char *OutFileName) { ...... /* Scan the content of the GIF file and load the image(s) in: */ do { ...... } while (RecordType != TERMINATE_RECORD_TYPE); /* Lets dump it - set the global variables required and do it: */ ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap); if (ColorMap == NULL) { fprintf(stderr, "Gif Image does not have a colormap\n"); exit(EXIT_FAILURE); } /* check that the background color isn't garbage (SF bug #87) */ if (GifFile->SBackGroundColor < 0 || GifFile->SBackGroundColor >= ColorMap->ColorCount) { fprintf(stderr, "Background color out of range for colormap\n"); exit(EXIT_FAILURE); } DumpScreen2RGB(OutFileName, OneFileFlag, ColorMap, ScreenBuffer, GifFile->SWidth, GifFile->SHeight); (void)free(ScreenBuffer); if (DGifCloseFile(GifFile, &Error) == GIF_ERROR) { PrintGifError(Error); exit(EXIT_FAILURE); } }
gif-to-rgb-library.c
需要把呼叫 DumpScreen2RGB 的位置移到迴圈體內 case IMAGE_DESC_RECORD_TYPE:
位置。
...... static void DumpScreen2RGB(char *FileName, ColorMapObject *ColorMap, GifRowType *ScreenBuffer, int ScreenWidth, int ScreenHeight) { ...... } static void GIF2RGB( char *FileName, char *OutFileNamePattern) { ...... do { ...... switch (RecordType) { case IMAGE_DESC_RECORD_TYPE: ...... ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap); if (ColorMap == NULL) { fprintf(stderr, "Gif Image does not have a colormap\n"); exit(EXIT_FAILURE); } /* check that the background color isn't garbage (SF bug #87) */ if (GifFile->SBackGroundColor < 0 || GifFile->SBackGroundColor >= ColorMap->ColorCount) { fprintf(stderr, "Background color out of range for colormap\n"); exit(EXIT_FAILURE); } char *name = malloc(255*sizeof(char)); sprintf(name, OutFileNamePattern, screenIndex++); printf("Final File Name: %s\n", name); DumpScreen2RGB(name, ColorMap, ScreenBuffer, GifFile->SWidth, GifFile->SHeight); break; case EXTENSION_RECORD_TYPE: ...... } } while (RecordType != TERMINATE_RECORD_TYPE); ...... } int main(int argc, char **argv) { GIF2RGB( "/Users/staff/Desktop/rainbow.gif", "/Users/staff/Desktop/rainbow-%d.rgb"); return 0; }
檢視 GIF -> RGB 結果
根據 【手動生成一張GIF圖片】 生成的 GIF rainbow.gif
含有 7 個影象,所以會得到 7 個 .RGB
檔案。
ffplay 檢視 RGB 檔案:
ffplay -f rawvideo -pixel_format rgb24 -s 700x700 rainbow-0.rgb ffplay -f rawvideo -pixel_format rgb24 -s 700x700 rainbow-1.rgb ffplay -f rawvideo -pixel_format rgb24 -s 700x700 rainbow-2.rgb ffplay -f rawvideo -pixel_format rgb24 -s 700x700 rainbow-3.rgb ffplay -f rawvideo -pixel_format rgb24 -s 700x700 rainbow-4.rgb ffplay -f rawvideo -pixel_format rgb24 -s 700x700 rainbow-5.rgb ffplay -f rawvideo -pixel_format rgb24 -s 700x700 rainbow-6.rgb
RGB to GIF
上面,從 rainbow.gif
中提取出了 7 個 RGB 檔案。
下面,讀取這 7 個 RGB 檔案,使用 GIFLIB 編碼成 GIF 動態圖。
// LoadRGB 是 gif2rgb.c 檔案中的方法
static void LoadRGB(char *FileName,
GifByteType **RedBuffer,
GifByteType **GreenBuffer,
GifByteType **BlueBuffer,
int Width, int Height)
{
......
}
// gif2rgb.c 檔案中 RGB2GIF 只實現了 RGB to GIF 靜態圖功能
// 這裡做了修改,可以生成動態 GIF
static void RGB2GIF(char **RGBFileNames, int NumOfRGBFile, char *GIFFileName,
int ExpNumOfColors, int Width, int Height)
{
int ColorMapSize;
GifByteType *RedBuffer = NULL, *GreenBuffer = NULL, *BlueBuffer = NULL, *OutputBuffer = NULL;
ColorMapObject *OutputColorMap = NULL;
// 開啟輸出的 GIF 檔案
int Error;
GifFileType *GifFile;
if ((GifFile = EGifOpenFileName(GIFFileName, false, &Error)) == NULL) {
PrintGifError(Error);
exit(EXIT_FAILURE);
}
GifFile->SWidth = Width;
GifFile->SHeight = Height;
GifFile->SColorResolution = 1;
GifFile->SBackGroundColor = 0;
GifFile->SColorMap = NULL;
for(int i = 0; i < NumOfRGBFile; i++) {
ColorMapSize = 1 << ExpNumOfColors;
printf("讀取 RGB 檔案:%d\n", i);
LoadRGB(RGBFileNames[i], &RedBuffer, &GreenBuffer, &BlueBuffer, Width, Height);
if ((OutputColorMap = GifMakeMapObject(ColorMapSize, NULL)) == NULL ||
(OutputBuffer = (GifByteType *) malloc(Width * Height *
sizeof(GifByteType))) == NULL)
GIF_EXIT("Failed to allocate memory required, aborted.");
if (GifQuantizeBuffer(Width, Height, &ColorMapSize,
RedBuffer, GreenBuffer, BlueBuffer,
OutputBuffer, OutputColorMap->Colors) == GIF_ERROR)
exit(EXIT_FAILURE);
free((char *) RedBuffer);
free((char *) GreenBuffer);
free((char *) BlueBuffer);
printf("MakeSavedImage:%d\n", i);
SavedImage *image = GifMakeSavedImage(GifFile, NULL);
GifImageDesc *imageDesc = (GifImageDesc *) malloc(sizeof(GifImageDesc));
imageDesc->Left = 0;
imageDesc->Top = 0;
imageDesc->Width = Width;
imageDesc->Height = Height;
imageDesc->Interlace = false;
imageDesc->ColorMap = OutputColorMap;
image->ImageDesc = *imageDesc;
image->RasterBits = OutputBuffer;
GraphicsControlBlock *GCB = (GraphicsControlBlock *) malloc(sizeof(GraphicsControlBlock));
GCB->DisposalMode = DISPOSAL_UNSPECIFIED;
GCB->DelayTime = 50;
GCB->UserInputFlag = false;
GCB->TransparentColor = NO_TRANSPARENT_COLOR;
printf("GCBToSaved:%d\n", i);
EGifGCBToSavedExtension(GCB, GifFile, i);
}
printf("輸出檔案。");
// 輸出檔案
EGifSpew(GifFile);
}
int main(int argc, char **argv) {
char *rgbFiles[] = {
"/Users/staff/Desktop/rainbow-0.rgb",
"/Users/staff/Desktop/rainbow-1.rgb",
"/Users/staff/Desktop/rainbow-2.rgb",
"/Users/staff/Desktop/rainbow-3.rgb",
"/Users/staff/Desktop/rainbow-4.rgb",
"/Users/staff/Desktop/rainbow-5.rgb",
"/Users/staff/Desktop/rainbow-6.rgb",
};
RGB2GIF(rgbFiles, 7, "/Users/staff/Desktop/rainbow0.gif", 3, 700, 700);
return 0;
}
檢視 RGB -> GIF 結果
成功實現了 GIF -> RGB(s) -> GIF。
參考資料:
How do I get the RGB colour data from a GIFLIB SavedImage structure