【Arduino】TFT LCD显示屏显示gif小电视太空人动图(基于Arduino框架ESP8266/ESP32、TFT_eSPI库、使用python脚本GIF转十六进制文件)

前言

​ 之前使用ESP32 来控制TFT屏幕显示动图时,找到现有的工具,需要先将动图gif格式一帧帧转为jpg格式,再将一帧帧的jgp转为hex十六进制格式,整个过程好麻烦。现用python写了脚本,将gif动图,一步生成hex16进制格式.h文件,过程时将gif动图获取到每一帧,然后将每一帧转成16进制hex文件可以直接使用,下面介绍脚本,和基于arduino框架使用TFT_eSPI库动图显示功能。

先看看单张动图效果
请添加图片描述

1. gif动图转十六进制文件(一步到位)

主函数中修改动图gif路径,运行即可

  • python脚本,处理gif动图函数如下

完整脚本源码可关注公众号【指针阿飞】 回复 【动图脚本】 免费获取
分享有三个文件,包含完整python脚本以及单张jpg图片转16进制hex的软件
在这里插入图片描述

'''
    参考链接
    https://stackoverflow.com/questions/10269099/pil-convert-gif-frames-to-jpg
'''
curdir = "./"
os.chdir(curdir)

def processImage(in_file, saveImg=True):
  
    im = Image.open(in_file)
    # 截取文件名
    filename = in_file.split('.')[0]

    i = 0
    mypalette = im.getpalette()

    arr_name_all = ''  # 存取数组
    arr_size_all = ''  # 存储数组容量

    try:
        with open(filename + '.h', 'w', encoding='utf-8') as f:  # 写入文件
            f.write('#include <pgmspace.h> \n\n')
            while 1:
                print('.', end="")
                im.putpalette(mypalette)
                new_im = Image.new("RGB", im.size)
                new_im.paste(im)

                # 缩放图像,
                width = new_im.size[0]  # 获取原始图像宽度
                height = new_im.size[1]  # 获取原始图像高度
                new_height = 82  # 等比例缩放后的图像高度,根据实际需要调整
                # print(width, " ", height)
                if height > new_height:
                    ratio = round(new_height / height, 3)  # 缩放系数
                    new_im = new_im.resize((int(width * ratio), int(height * ratio)), Image.ANTIALIAS)

                # 获取图像字节流,转16进制格式
                img_byte = BytesIO()  # 获取字节流
                new_im.save(img_byte, format='jpeg')
                # print(img_byte.getvalue())
                
                # 16进制字符串
                img_hex = binascii.hexlify(img_byte.getvalue()).decode('utf-8')  
                
                arr_name = filename + '_' + str(i)
                arr_size = 0  # 记录数组长度
                arr_name_all += arr_name + ','

                # 将ac --> 0xac
                f.write('const uint8_t ' + arr_name + '[] PROGMEM = { \n')  # 写前
                for index, x in zip(range(len(img_hex)), range(0, len(img_hex), 2)):
                    temp_hex = '0x' + img_hex[x:x + 2] + ', '
                    # 30个数据换行
                    if (index + 1) % 30 == 0:
                        temp_hex += '\n'

                    f.write(temp_hex)  # 写入文件
                    arr_size += 1
                f.write('\n};\n\n')  # 写结尾
                i += 1
                arr_size_all += str(arr_size) + ','

                # 保存一帧帧图像
                if saveImg:
                    if not os.path.exists('./out_img'):
                        os.mkdir('./out_img')
                    if not os.path.exists('./out_img/' + filename):
                        os.mkdir('./out_img/' + filename)
                    new_im.save('./out_img/' + filename + '/' + str(i) + '.jpg')

                try:
                    im.seek(im.tell() + 1)
                except EOFError:
                    # 动图读取结束
                    f.write('const uint8_t *' + filename + '[' + str(i) + '] PROGMEM { ' + arr_name_all + '};\n')
                    f.write('const uint32_t ' + filename + '_size[' + str(i) + '] PROGMEM { ' + arr_size_all + '};')
                    print("成功保存文件为:" + filename + '.h')
                    break

    except EOFError as e:
        print(e.args)
        print(traceback.format_exc())
        pass  # end of sequence


运行即可生成相应的.h文件

在这里插入图片描述
下面是对生成的文件内容格式说明
.h文件内容格式

-将一帧帧图像数据存放到数组,程序要用到

  • 数组名 sm1

  • 数组大小 sm1_size

2.如何使用

#include <TFT_eSPI.h>
#include <SPI.h>
#include <TJpg_Decoder.h>
#include <Arduino.h>

#include "sm1.h"  //引入gif生成的.h文件

typedef unsigned char uint8_t;
typedef unsigned int uint32_t;

// LCD屏幕相关设置,是什么屏幕,什么驱动,
// 引脚需配置tft_espi库中的 User_Setup.h文件
TFT_eSPI tft = TFT_eSPI(); 

//动画更新时间记录
int Amimate_reflash_Time = 0; 
int Animate_key = -1; //初始化图标显示帧数
//从动图数组里面获取一帧图像数据
void imgAnim(const uint8_t **Animate_value, uint32_t *Animate_size)
{
	 Animate_key++;
	//记得修改成你自定义的
    //sm1 是生成的文件中,数组名
    //sm1_size  数组容量名
    *Animate_value = sm1[Animate_key];
    *Animate_size = sm1_size[Animate_key];
    if (Animate_key >= (sizeof(sm1)/sizeof(sm1[0])-1))  //gif动图帧数  25-1
        Animate_key = -1;

}

// TFT屏幕输出函数
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap)
{
  if (y >= tft.height())
    return 0;
  tft.pushImage(x, y, w, h, bitmap);
  // Return 1 to decode next block
  return 1;
}


void setup()
{
  Serial.begin(115200);
  tft.begin();         
  tft.invertDisplay(1); //反转所有显示颜色:1反转,0正常
  tft.setRotation(0); 
  tft.fillScreen(0x0000);

  TJpgDec.setJpgScale(1);
  TJpgDec.setSwapBytes(true);
  TJpgDec.setCallback(tft_output);
    
  tft.fillScreen(TFT_BLACK); 
}

void loop()
{
    const uint8_t *Animate_value; //指向关键帧的指针
	uint32_t Animate_size;        //指向关键帧大小的指针
    
    if (millis() - Amimate_reflash_Time > 100) // 100 ms切换一次
    {
      Amimate_reflash_Time = millis();
      imgAnim(&Animate_value, &Animate_size);
      TJpgDec.drawJpg(0, 0, Animate_value, Animate_size);
    }
}

3.显示效果

多张动图的演示效果
请添加图片描述

🤵‍♂️ 个人主页阿飞AFlying
关注公众号【指针阿飞】获取更多学习资源~
如果文章对你有帮助的话,欢迎评论 💬点赞👍🏻 收藏 📂加关注

  • 6
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值