两个gif图片处理库使用

  1. giflib
  2. gif.h

giflib

giflib是一个gif图片的处理库,可用于gif格式图片的生成与解码,这里有详细的介绍。
下载已经编译好的giflib库文件。下面是使用giflib生成gif图片过程.

  • 两张jpg原图

    现在要将这两个图片合成一张可以gif动画图片。图片尺寸:340 x 240。

  • 生成gif代码
    【1】读取原图信息,这里使用FreeImage库来读取jpg图片数据

      // 首先是gif图片的基参数:由2张图片生成一张x.gif动画图片,尺寸为240*240,动画时间参数40*0.01s。
      // inputPics为二级指针,用于读取并保存两个jpg原图的RGB数据
      char        *outputFile = "x.gif";
      int32_t     gNum = 2;
      int32_t     gDelay = 40;
      int32_t     gWidth = 340;
      int32_t     gHeight = 240;
      uint8_t     **inputPics;
      inputPics = new uint8_t*[gNum];
    
      // 使用FreeImage库读取jpg原图数据
      FreeImage_Initialise(0);
      for (n = 0; n < gNum; ++n)
      {
          char str[20];
          sprintf(str, "olr%d.jpg", n + 1);
    
          FIBITMAP *pfImg = FreeImage_Load(FIF_JPEG, str);
          if (pfImg)
          {
              gWidth = FreeImage_GetWidth(pfImg);
              gHeight = FreeImage_GetHeight(pfImg);
    
              // GetLine: 图像宽,字节
              // GetWidth: 图像宽,像素
              int byteStep = FreeImage_GetLine(pfImg) / FreeImage_GetWidth(pfImg);
    
              // save color to inputPics in RGB-format
              *(inputPics + n) = new uint8_t[gWidth * gHeight * 3];
              for (i = 0; i < gHeight; ++i)
              {
                  // !!!attention: FreeImage倒置了
                  BYTE *bytes = FreeImage_GetScanLine(pfImg, i);
                  int pos = 0;
                  for (j = 0; j < gWidth; ++j)
                  {
                      pos = 3 * ((gHeight - i - 1)*gWidth + j);
                      *(*(inputPics + n) + pos + 0) = bytes[FI_RGBA_RED];
                      *(*(inputPics + n) + pos + 1) = bytes[FI_RGBA_GREEN];
                      *(*(inputPics + n) + pos + 2) = bytes[FI_RGBA_BLUE];
                      bytes += byteStep;
                  }
              }
              FreeImage_Unload(pfImg);
          }
      }
      FreeImage_DeInitialise();
    

    【2】使用giflib生成不过图片

      // giflib基本参数
      GifFileType*            pGifFile;           // gif file struct
      int                     errorStatus;        // 返回状态值
      static const uint8_t    cr = 8;             // color位数, 0~8
      static const int        cc = 1 << cr;       // color数量,这里使用256
      ColorMapObject*         pColorMap;          // 全局颜色表
      ColorMapObject**        ppColorMap;         // 局部颜色表
      // 全局颜色表和局部颜色表一般只选用一种即可,颜色表即gif总共能使用的颜色,这里有256种
      // 全局颜色表:即gif动画中的每张图片均用同一个颜色表,这样图片占用空间小,但画面就差点
      // 局部颜色表:即gif动画中的每张图片有各自的颜色表,这样图片占用空间大,但画面好
    

下面是生成gif图片的过程,最好先在这里看下gif图片的格式
gif基本格内容如下:

    // (1)打开gif图片
    pGifFile = EGifOpenFileName(outputFile, false, &errorStatus);
    if (pGifFile == nullptr)
        return 0;
    EGifSetGifVersion(pGifFile, true);

    //(2)写入logical screen descriptor块,这里使用全局颜色表
    pColorMap = GifMakeMapObject(cc, nullptr);
    // 创建颜色表
    PalGenP pGen = CreatePalGen(nullptr);
    for (n = 0; n < gNum; ++n)
    {
        for (k = 0; k < gWidth*gHeight; k++)
        {
            ColorVal R = *(*(inputPics + n) + k * 3 + 0);
            ColorVal G = *(*(inputPics + n) + k * 3 + 1);
            ColorVal B = *(*(inputPics + n) + k * 3 + 2);
            AddColor(pGen, R, G, B);

            while (pGen->NbLeaf > cc)
            {
                ReduceColor(pGen);
            }
        }
    }
    pColorMap->ColorCount = 0;
    GenPalette(pGen,
        [](ColorVal R, ColorVal G, ColorVal B, void *pUserData)->void{
        ColorMapObject *pCm = (ColorMapObject*)pUserData;
        pCm->Colors[pCm->ColorCount].Red = R;
        pCm->Colors[pCm->ColorCount].Green = G;
        pCm->Colors[pCm->ColorCount++].Blue = B;        // lambda expression
    },
        pColorMap);
    DestroyPalGen(pGen);

    // write logical screen
    EGifPutScreenDesc(pGifFile, gWidth, gHeight, cr, 0, pColorMap);

上面生成颜色表的算法是使用这里的库

    // (3)写入graphic control extension块,此块可以设定动画速度和透明色
    static const GraphicsControlBlock gcb(DISPOSE_DO_NOT, false, gDelay, NO_TRANSPARENT_COLOR);
    static const GifByteType gcbLen = 4;
    static GifByteType gcbBytes[gcbLen];
    EGifGCBToExtension(&gcb, gcbBytes);
    EGifPutExtension(pGifFile, GRAPHICS_EXT_FUNC_CODE, gcbLen, gcbBytes);
    // [4].写入application extension块,此块可以设定gif动画循环次数
    // 注意,此块有 子块sub-block,写入调用的函数有所不同
    static const GifByteType aeLen = 11;
    static const char *aeBytes = { "NETSCAPE2.0" };
    static const GifByteType aeSubLen = 3;
    static GifByteType aeSubBytes[aeSubLen];
    aeSubBytes[0] = 0x01;
    aeSubBytes[1] = 0x00;   //byte[1]是低位,byte[2]是高位,组成一个无符号16位数,决定动画循环次数
    aeSubBytes[2] = 0x00;
    EGifPutExtensionLeader(pGifFile, APPLICATION_EXT_FUNC_CODE);
    EGifPutExtensionBlock(pGifFile, aeLen, aeBytes);
    EGifPutExtensionBlock(pGifFile, aeSubLen, aeSubBytes);
    EGifPutExtensionTrailer(pGifFile);
    // 接下来写入图片数据
    for (n = 0; n < gNum; ++n)
    {
        // (5)写入image descriptor块,因为不使用局部颜色表,传入nullptr,而不传pColorMap
        EGifPutImageDesc(pGifFile, 0, 0, gWidth, gHeight, false, nullptr);
        GifColorType *pCm = pColorMap->Colors;              // color map

        // (6)写入image data
        for (k = 0; k < gWidth*gHeight; ++k)
        {
            uint8_t index = 0;
            int mindis = 1 << 30;
            uint8_t rr = *(*(inputPics + n) + k * 3 + 0);
            uint8_t gg = *(*(inputPics + n) + k * 3 + 1);
            uint8_t bb = *(*(inputPics + n) + k * 3 + 2);

            // 将颜色匹配到颜色表的索引颜色
            for (i = 0; i < cc; i++)
            {
                int dis =
                    (rr - (*(pCm+i)).Red)*(rr - (*(pCm+i)).Red) +
                    (gg - (*(pCm+i)).Green)*(gg - (*(pCm+i)).Green) +
                    (bb - (*(pCm+i)).Blue)*(bb - (*(pCm+i)).Blue);
                if (dis < mindis)
                {
                    mindis = dis;
                    index = i;
                }
                if (dis == 0)
                {
                    index = i;
                    break;
                }
            }
            EGifPutPixel(pGifFile, (uint8_t)index);
        }

    }

    // (7)数据写入完毕,关闭gif文件
    GifFreeMapObject(pColorMap);
    EGifCloseFile(pGifFile, &errorStatus);

生成gif图片如下:

下面是使用局部颜色表生成的gif图片,画面质量好些



gif.h

gif.h是一个小巧的gif图片生成库,不能解码gif图片,使用简单,不需要了解gif格式就能使用,先下载库。
还是使用上面的jpg原图来生成一张gif图片,代码如下:

    GifWriter   gw;
    GifBegin(&gw,outputFile, gWidth, gHeight, gDelay);
    for (n = 0; n < gNum; ++n)
    {
        // 写入gw的图片数据为rgba8888格式
        uint8_t *imgFrame = new uint8_t[4 * gWidth*gHeight];
        for (k = 0; k < gWidth*gHeight; k++)
        {
            *(imgFrame + k*4 + 0) = *(*(inputPics + n) + k*3 + 0);
            *(imgFrame + k*4 + 1) = *(*(inputPics + n) + k*3 + 1);
            *(imgFrame + k*4 + 2) = *(*(inputPics + n) + k*3 + 2);
            //*(imgFrame + k * 4 + 3) = 0xff;
            // rgba中的a不起作用,赋不赋值不影响
        }
        GifWriteFrame(&gw, imgFrame, gWidth, gHeight, gDelay);
        delete imgFrame;
    }
    GifEnd(&gw);

用gif.h生成gif图片如下:


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 [ yehuohan@gmail.com ]

文章标题:两个gif图片处理库使用

本文作者:Yehuohanxing

发布时间:2017-06-09, 18:00:52

最后更新:2018-04-03, 23:26:42

原始链接:http://yehuohan.github.io/2017/06/09/笔记/两个gif图片处理库使用/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录