总第50篇
平时我们在工作和学习的过程中,有时需要将桌面的某些动作截图生成gif
动图,以更生动地呈现出来。目前有很多这样的软件,并且方便易使用,比如我经常使用的GifCam
,软件小巧,生成的图片文件也比较小,非常优秀。它的界面如下图所示(这里绝不是打广告呀)。
那么,这种截图后生成gif
文件是如何用软件实现的呢?
本文将详细说明一下这种功能的实现思路,作为软件设计的一种参考,也方便在以后的工程项目中借鉴与参照。
1.多张image
图片处理成gif
图片的实现
这个可以借助gif
开源的类来实现,直接调用其中的方法,可以实现将多张图片合并到一张gif
图片中去,并且这个类还是跨平台的,方便在多平台上实现。这里列举几个要用到的接口的实现,详细的接口实现请查看完整的开源类文件(若找不到,可以联系我,问我要)。
struct GifWriter { //这个是写gif的结构体定义FILE *f;uint8_t *oldImage;bool firstFrame;};
//开始生成gif文件的接口bool GifBegin( GifWriter *writer, const char *filename,uint32_t width, uint32_t height,uint32_t delay, int32_t bitDepth = 8,bool dither = false ){(void)bitDepth;(void)dither; // Mute "Unused argument" warnings
#if defined(_MSC_VER) && (_MSC_VER >= 1400)writer->f = 0;fopen_s(&writer->f, filename, "wb");
#elsewriter->f = fopen(filename, "wb");
#endifif(!writer->f) {return false;}writer->firstFrame = true;// allocatewriter->oldImage = (uint8_t *)GIF_MALLOC(width * height * 4);fputs("GIF89a", writer->f);// screen descriptorfputc(width & 0xff, writer->f);fputc((width >> 8) & 0xff, writer->f);fputc(height & 0xff, writer->f);fputc((height >> 8) & 0xff, writer->f);fputc(0xf0, writer->f); // there is an unsorted global color table of 2 entriesfputc(0, writer->f); // background colorfputc(0, writer->f); // pixels are square (we need to specify this because it's 1989)// now the "global" palette (really just a dummy palette)// color 0: blackfputc(0, writer->f);fputc(0, writer->f);fputc(0, writer->f);// color 1: also blackfputc(0, writer->f);fputc(0, writer->f);fputc(0, writer->f);if( delay != 0 ) {// animation headerfputc(0x21, writer->f); // extensionfputc(0xff, writer->f); // application specificfputc(11, writer->f); // length 11fputs("NETSCAPE2.0", writer->f); // yes, reallyfputc(3, writer->f); // 3 bytes of NETSCAPE2.0 datafputc(1, writer->f); // JUST BECAUSEfputc(0, writer->f); // loop infinitely (byte 0)fputc(0, writer->f); // loop infinitely (byte 1)fputc(0, writer->f); // block terminator}return true;}//向gif文件生成过程中写入一帧数据的接口bool GifWriteFrame( GifWriter *writer, const uint8_t *image,uint32_t width, uint32_t height,uint32_t delay, int bitDepth = 8, bool dither = false ){if(!writer->f) {return false;}const uint8_t *oldImage = writer->firstFrame ? NULL : writer->oldImage;writer->firstFrame = false;GifPalette pal;GifMakePalette((dither ? NULL : oldImage), image, width, height, bitDepth, dither, &pal);if(dither) {GifDitherImage(oldImage, image, writer->oldImage, width, height, &pal);} else {GifThresholdImage(oldImage, image, writer->oldImage, width, height, &pal);}GifWriteLzwImage(writer->f, writer->oldImage, 0, 0, width, height, delay, &pal);return true;}
2.定时生成图片并记录图片
用定时器的singleShot()
定时截取桌面的的一帧帧图片,将图片保存处理后送入到gif
的GifWriteFrame()
接口,生成相应的动图。这里关键在于从桌面上获取截图,要用到grabWindow()
这个接口函数。
对于Qt5
以前和版本, 这个接口函数是放在QPixmap
中,获取的图片也是QPixmap
格式的。对于Qt5
以上的版本,这个接口是单独放进了一个类,这个类叫QScreen
,获取的图片也是QPixmap
格式的。
其关键的两个函数代码示例如下:
//从桌面截图并帧写入到gif中
void GifWidget::saveImage()
{if (!gifWriter) {return;}QScreen *screen = QApplication::primaryScreen();QPixmap pix = screen->grabWindow(0, x() + rectGif.x(), y() + rectGif.y(), rectGif.width(), rectGif.height());QImage image = pix.toImage().convertToFormat(QImage::Format_RGBA8888);gif.GifWriteFrame(gifWriter, image.bits(), rectGif.width(), rectGif.height(), fps);
} //点击开始录制时,打开定时器触发槽函数,
void GifWidget::record()
{if (btnStart->text() == "开始") {if (0 != gifWriter) {delete gifWriter;gifWriter = 0;}//确定gif文件的保存位置fileName = QFileDialog::getSaveFileName(this, "选择保存位置", qApp->applicationDirPath() + "/", "gif图片(*.gif)");if (fileName.isEmpty()) {return;}int width = txtWidth->text().toInt();int height = txtHeight->text().toInt();fps = txtFps->text().toInt();gifWriter = new Gif::GifWriter;bool bOk = gif.GifBegin(gifWriter, fileName.toLocal8Bit().data(), width, height, fps);if (!bOk) {delete gifWriter;gifWriter = 0;return;}count = 0;labStatus->setText("开始录制...");btnStart->setText("停止");//延时启动timer->setInterval(1000 / fps);QTimer::singleShot(1000, timer, SLOT(start()));} else {timer->stop();gif.GifEnd(gifWriter);delete gifWriter;gifWriter = 0;labStatus->setText(QString("录制完成 共 %1 帧").arg(count));btnStart->setText("开始");QDesktopServices::openUrl(QUrl(fileName));}
}
其程序运行的结果如下图所示:
总起来说,整个功能的实现分为两步,第一是定时从桌面获取截图图片,第二是将这些图片按帧组合成gif
文件。 程序的实现只是一种参考,希望对你有参考意义。
本文到此结束!
如果对你有帮助,请随手 点赞 或 点喜欢!关注本专栏,更多干货与你分享。
=======================================================
欢迎【关注、私信 @武三郎】。我们一起交流一起进步。