当前位置: 首页 > news >正文

giflib5.2.2 在Qt与VS C++中实现Gif缩放示例

giflib5.2.2 在Qt与VS C++中实现Gif缩放示例

giflib下载地址

# QT中的用法:
DEFINES += _CRT_SECURE_NO_WARNINGS
DEFINES += _CRT_NONSTDC_NO_WARNINGSINCLUDEPATH += $$PWD/giflib-5.2.2/SOURCES += \$$PWD/giflib-5.2.2/dgif_lib.c \$$PWD/giflib-5.2.2/egif_lib.c \$$PWD/giflib-5.2.2/gif_err.c \$$PWD/giflib-5.2.2/gif_hash.c \$$PWD/giflib-5.2.2/gifalloc.c \$$PWD/giflib-5.2.2/openbsd-reallocarray.c \

GifScaler.h

#pragma once#include <QByteArray>
#include <QBuffer>
#include <QMovie>
#include <QImage>
#include <QImageWriter>
#include <QPainter>
#include <QFile>
#include <QString>
#include <Windows.h>// GIF Disposal Method 定义 (来自 GIF89a 规范)
// 指定该帧显示完毕后,画布的处理方式
#define DISPOSAL_UNSPECIFIED 0  // 未指定,通常等同于 DISPOSAL_NONE
#define DISPOSAL_NONE        1  // 不清除,直接保留画布
#define DISPOSAL_BACKGROUND  2  // 恢复为背景色
#define DISPOSAL_PREVIOUS    3  // 恢复到上一帧的画布内容bool scaleGif(const QString& inputFile, const QString& outputFile, int newWidth, int newHeight);

GifScaler.cpp

#include "GifScaler.h"
#include <vector>
#include <iostream>
#include <cstring>
#include <cmath>
#include <fcntl.h>
#include <io.h>extern "C" {#include "gif_lib.h"
}// 最近邻缩放整幅图像
static std::vector<GifByteType> scaleFrame(const std::vector<GifByteType>& src,int width, int height,int newW, int newH)
{std::vector<GifByteType> dst(newW * newH);for (int y = 0; y < newH; y++) {int sy = y * height / newH;for (int x = 0; x < newW; x++) {int sx = x * width / newW;dst[y * newW + x] = src[sy * width + sx];}}return dst;
}// 将一帧合成到全局画布
static void blendFrame(std::vector<GifByteType>& canvas, int canvasW, int canvasH,const GifByteType* raster, int left, int top, int width, int height,int transparentIndex)
{for (int y = 0; y < height; y++) {int dstY = top + y;if (dstY < 0 || dstY >= canvasH) continue;for (int x = 0; x < width; x++) {int dstX = left + x;if (dstX < 0 || dstX >= canvasW) continue;GifByteType c = raster[y * width + x];if (c == transparentIndex) continue; // 跳过透明像素canvas[dstY * canvasW + dstX] = c;}}
}bool scaleGif(const QString& inputFile, const QString& outputFile, int newWidth, int newHeight)
{HANDLE hIn = CreateFileW(inputFile.toStdWString().c_str(), GENERIC_READ,FILE_SHARE_READ, nullptr, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, nullptr);if (hIn == INVALID_HANDLE_VALUE) return false;int fdIn = _open_osfhandle(reinterpret_cast<intptr_t>(hIn), _O_RDONLY | _O_BINARY);if (fdIn == -1) { CloseHandle(hIn); return false; }int err = 0;GifFileType* gifIn = DGifOpenFileHandle(fdIn, &err);if (!gifIn) { CloseHandle(hIn); return false; }if (DGifSlurp(gifIn) == GIF_ERROR) {DGifCloseFile(gifIn, &err);return false;}if (newWidth == gifIn->SWidth && newHeight == gifIn->SHeight) {DGifCloseFile(gifIn, &err);if (QFile::exists(outputFile)) QFile::remove(outputFile);return QFile::copy(inputFile, outputFile);}HANDLE hOut = CreateFileW(outputFile.toStdWString().c_str(), GENERIC_WRITE,0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);if (hOut == INVALID_HANDLE_VALUE) {DGifCloseFile(gifIn, &err);return false;}int fdOut = _open_osfhandle(reinterpret_cast<intptr_t>(hOut), _O_WRONLY | _O_BINARY);if (fdOut == -1) { DGifCloseFile(gifIn, &err); CloseHandle(hOut); return false; }GifFileType* gifOut = EGifOpenFileHandle(fdOut, &err);if (!gifOut) { DGifCloseFile(gifIn, &err); CloseHandle(hOut); return false; }ColorMapObject* colorMap = gifIn->SColorMap;if (!colorMap && gifIn->ImageCount > 0)colorMap = gifIn->SavedImages[0].ImageDesc.ColorMap;if (EGifPutScreenDesc(gifOut, newWidth, newHeight,colorMap ? colorMap->BitsPerPixel : 8, 0, colorMap) == GIF_ERROR) {DGifCloseFile(gifIn, &err);EGifCloseFile(gifOut, &err);return false;}// 全局画布(原始大小)std::vector<GifByteType> canvas(gifIn->SWidth * gifIn->SHeight, gifIn->SBackGroundColor);std::vector<GifByteType> canvasBackup; // 用于 disposal=3 的快照for (int i = 0; i < gifIn->ImageCount; i++) {SavedImage& frame = gifIn->SavedImages[i];int transparentIndex = -1;int disposalMethod = 0;// 解析 GCEfor (int j = 0; j < frame.ExtensionBlockCount; j++) {ExtensionBlock& ext = frame.ExtensionBlocks[j];if (ext.Function == GRAPHICS_EXT_FUNC_CODE && ext.ByteCount >= 4) {disposalMethod = (ext.Bytes[0] >> 2) & 7;if (ext.Bytes[0] & 0x01) {transparentIndex = (unsigned char)ext.Bytes[3];}EGifPutExtension(gifOut, ext.Function, ext.ByteCount, ext.Bytes);}}// 在合成前保存快照 (用于 disposal=3)canvasBackup = canvas;// 合成当前帧到画布blendFrame(canvas, gifIn->SWidth, gifIn->SHeight,frame.RasterBits,frame.ImageDesc.Left, frame.ImageDesc.Top,frame.ImageDesc.Width, frame.ImageDesc.Height,transparentIndex);// 缩放整个画布std::vector<GifByteType> scaled = scaleFrame(canvas, gifIn->SWidth, gifIn->SHeight, newWidth, newHeight);// 写出全屏帧if (EGifPutImageDesc(gifOut, 0, 0, newWidth, newHeight, false, frame.ImageDesc.ColorMap) == GIF_ERROR) {DGifCloseFile(gifIn, &err);EGifCloseFile(gifOut, &err);return false;}for (int y = 0; y < newHeight; y++) {if (EGifPutLine(gifOut, &scaled[y * newWidth], newWidth) == GIF_ERROR) {DGifCloseFile(gifIn, &err);EGifCloseFile(gifOut, &err);return false;}}// 处理处置方法if (disposalMethod == 2) {if (i < gifIn->ImageCount - 1) {std::fill(canvas.begin(), canvas.end(), gifIn->SBackGroundColor);}}else if (disposalMethod == 3) {// 恢复到上一帧前的画布canvas.swap(canvasBackup);}// disposal=0/1 表示保留画布,无需清除}DGifCloseFile(gifIn, &err);EGifCloseFile(gifOut, &err);return true;
}
http://www.dtcms.com/a/406330.html

相关文章:

  • 题解:AT_abc401_c [ABC401C] K-bonacci
  • 【OpenFeign】在 RuoYi 框架中优雅使用 OpenFeign:从原理到实践与踩坑总结
  • VMware虚拟机安装ubuntu
  • 因果推断落地:从CausalML到EconML,详解Uplift建模核心库
  • 备案个人网站做淘宝客wordpress能做企业站吗
  • 天玑与骁龙芯片:性能对决与选择指南
  • 【RustPython】 RustPython Cargo.toml 配置文件详解
  • 献县网站做映射后 内网无法通过域名访问网站
  • Go语言 对接全球股票K线API实战 - 以美股市场为例
  • Linux系统Nginx服务(四)
  • Linux to go Ubuntu 22.04 不匹配无线网卡 MT7925 的解决方法
  • Go语言在区块链开发中的应用场景详解
  • go的基础数据结构 slice源码阅读
  • 百度网盟推广 网站四川建设网有限责任公司官网
  • 破局渠道垄断:青蓝的流量入口变现路径
  • 【C++STL :string类 (二) 】从接口应用到内存模型的全面探索
  • 学做面包到什么网站网站点击按钮回到页面顶部怎么做
  • 领航 网站设计主机屋怎么做网站
  • 在VTK中实现相机自动绕轴旋转
  • 关于解决switch开关属性中active-value=“1“为数值形失败的问题
  • Seata 深度解析:微服务分布式事务管理的实践指南
  • LeetCode:53.课程表
  • 中国县域经济韧性(2006-2021)
  • MySQL零基础学习Day3——函数和约束
  • Bililive-go+cpolar:跨平台直播录制的远程管理方案
  • 飞马无人机正射/倾斜影像数据预处理
  • 2025 AI 技术跃迁与产业融合:从实验室到价值场
  • 济源网站建设价格蓝色系网站
  • MySQL InnoDB缓冲池优化全指南
  • Redis 内存淘汰策略 LRU 和传统 LRU 差异