
JPEGDEC 在 M5Stack 系列设备上的 JPEG 解码显示实战从回调绘制到 EXIF 缩略图与缩放【免费下载链接】TasmotaAlternative firmware for ESP8266 and ESP32 based devices with easy configuration using webUI, OTA updates, automation using timers or rules, expandability and entirely local control over MQTT, HTTP, Serial or KNX. Full documentation at项目地址: https://gitcode.com/GitHub_Trending/ta/Tasmota本指南以 JPEGDEC 库的 M5Stack 示例 README 为主体完整讲解如何在 M5Stack、M5Fire、M5StickC、M5StickC Plus、M5Core2 五类设备上解码并显示 JPEG 图片涵盖 JPEGDraw 回调机制、EXIF 缩略图自动检测、1/2、1/4、1/8 缩放解码以及多图片切换技巧。读完本文你将掌握 JPEGDEC 在 M5Stack 生态中的移植要点能够直接复刻这套示例到自己的工程中。示例概览一套代码适配五款 M5 设备JPEGDEC 库在 examples/M5Stack 目录下提供了五个近乎相同的 Arduino 示例分别对应五款设备目录目标设备头文件屏幕分辨率宏定义值M5StackM5Stack Gray / BasicM5Stack.h320×240M5FireM5Stack FireM5Stack.h320×240M5StickCM5StickCM5StickC.h80×160M5StickCPlusM5StickC PlusM5StickCPlus.h135×240M5Core2M5Core2M5Core2.h320×240据 README 说明这些草图是 adafruit_gfx_demo 的微改版slightly modified versions核心改动集中在两点一是将 JPEGDraw 回调改写为适配 M5Stack 设备的M5.Lcd.drawBitmap调用二是增加缩略图检测在图片带 EXIF 缩略图时调用对应的解码例程。其余结构与上游示例保持一致因此迁移成本极低。每个设备目录下都包含同一组素材头文件thumb_test.h含 EXIF 缩略图的测试图、ncc1701.h星舰企业号 NCC-1701、batman.h蝙蝠侠以及对应的.ino主程序。核心机制JPEGDraw 回调与 drawBitmap 像素搬运JPEGDEC 是典型的解码核心 回调输出架构纯 C 的解码核心不关心你的屏幕是什么每当解码出一个像素块MCU时就通过回调函数把像素交给你由你负责搬运到显示设备上。这正是它能够轻易适配 M5Stack 的原因。以 M5Stack.ino 为例回调实现极其简洁int JPEGDraw(JPEGDRAW *pDraw) { M5.Lcd.drawBitmap((int16_t)pDraw-x, (int16_t)pDraw-y, (int16_t)pDraw-iWidth, (int16_t)pDraw-iHeight, pDraw-pPixels); return 1; }这里的JPEGDRAW结构体由库定义见 src/JPEGDEC.h解码器每完成一个 MCU 块就填充一次并回调x、y当前像素块在屏幕上的左上角坐标iWidth、iHeight该像素块的宽高pPixels指向 16 位像素数据的指针默认 RGB565 小端序。回调返回 1 表示继续解码。M5.Lcd 底层基于 Adafruit GFXdrawBitmap直接按坐标把pPixels拷到显存完成显示。从源码结构看库的JPEGFILE与JPEGDRAW分离设计让解码逻辑与显示逻辑彻底解耦这也是示例只需改一个回调函数即可跨设备运行的底层原因。调用链为jpeg.openFLASH(...)打开图片 →jpeg.decode(x, y, option)触发解码 → 解码核心逐块回调JPEGDraw→drawBitmap上屏。关键改动一EXIF 缩略图检测与解码示例的第二个改动是缩略图判断。测试图thumb_test是一张被截断处理、内含 320×240 EXIF 缩略图的 JPEG。README 与代码M5Stack.ino给出了统一处理逻辑if (jpeg.hasThumb()) { jpeg.decode(iCenterX[i], iCenterY[i], JPEG_EXIF_THUMBNAIL | iOption[i]); } else { jpeg.decode(iCenterX[i], iCenterY[i], iOption[i]); }hasThumb()查询解码器是否在 JPEG 文件头APP1/EXIF 段中发现了内嵌缩略图JPEG_EXIF_THUMBNAIL值为 32定义于 src/JPEGDEC.h指示解码器直接解码 EXIF 缩略图而不是主图。这个特性对相册类应用非常实用很多数码相机、手机拍的 JPEG 都内嵌小尺寸 EXIF 缩略图解码缩略图比解码全尺寸主图快得多非常适合内存紧张的 MCU 设备做快速预览。库内部还维护了iThumbWidth、iThumbHeight、iThumbData等字段见 JPEGIMAGE 结构体配合getThumbWidth()、getThumbHeight()可以预先获知缩略图尺寸。关键改动二四种解码档位与缩放定位主循环用四个档位演示了 JPEGDEC 的硬件无关快速降采样能力M5Stack.inoint iOption[4] {0, JPEG_SCALE_HALF, JPEG_SCALE_QUARTER, JPEG_SCALE_EIGHTH}; int iCenterX[4] {0, 80, 120, 140}; // M5StickC/CPlus 中全部为 0 int iCenterY[4] {0, 60, 90, 105}; // M5StickC/CPlus 中全部为 0四个档位对应 JPEGDEC.h 中的解码选项选项宏值含义无0原始分辨率解码JPEG_SCALE_HALF2输出缩至 1/2JPEG_SCALE_QUARTER4输出缩至 1/4JPEG_SCALE_EIGHTH8输出缩至 1/8缩放是在 IDCT 阶段直接丢弃高频分量完成的比全尺寸解码后再软件缩放快得多对无浮点、无硬件加速的 ESP32 尤其重要。循环中每档解码后示例通过Serial.printf输出实际解码耗时与当前档位下的图片尺寸lTime micros() - lTime; Serial.printf(%d x %d image, decode time %d us\n, jpeg.getWidth() i, jpeg.getHeight() i, (int)lTime);jpeg.getWidth() i巧妙地用右移计算缩放后的宽1/2→1、1/4→2、1/8→3可以在串口监视器115200 波特率上直观对比各档位耗时是评估解码性能的最小可行方案。注意 M5StickC / M5StickC Plus 的示例中iCenterX、iCenterY全部为 0见 M5StickC.ino因为小屏幕无需多位置演示统一从原点显示即可。切换显示图片取消注释即换图每个示例默认只解码thumb_test其余两张图以注释形式保留M5Stack.inoif (jpeg.openFLASH((uint8_t *)thumb_test, sizeof(thumb_test), JPEGDraw)) //if (jpeg.openFLASH((uint8_t *)ncc1701, sizeof(ncc1701), JPEGDraw)) //if (jpeg.openFLASH((uint8_t *)batman, sizeof(batman), JPEGDraw))按 README 的指引切换图片只需两步把想显示的#include取消注释、把另外两个注释掉同时把openFLASH中对应的图片符号取消注释并注释其他两个。例如想显示蝙蝠侠//#include thumb_test.h //#include ncc1701.h #include batman.h ... if (jpeg.openFLASH((uint8_t *)batman, sizeof(batman), JPEGDraw))openFLASH与openRAM的区别要特别注意ESP32 属于哈佛架构代码与数据存储于 FlashopenFLASH接受const uint8_t *并保证从 Flash 直接读取如果图片数组放在 RAM 中则应使用openRAM两个方法均声明于 src/JPEGDEC.h。对于 ARM Cortex-M 系列两者可互换但 ESP32 上选错会导致读取异常。各设备差异详解README 明确指出五个示例几乎相同差异只在屏幕初始化和头文件M5Stack 与 M5StickC/CPlus使用M5.begin()如 M5Stack.inoM5Fire使用M5.Lcd.begin()见 M5Fire.ino因为 Fire 的屏幕初始化方式与其他型号不同M5Core2使用带参数的M5.begin(true, true, true, true)见 M5Core2.ino依次启用电源、LCD、触摸等外设M5StickC / M5StickC Plus头文件分别为M5StickC.h和M5StickCPlus.h屏幕分辨率宏也不同80×160 与 135×240。所有示例统一执行M5.Lcd.startWrite()后再解码如 M5Stack.ino。这是 Adafruit GFX 的事务机制一次startWrite到endWrite之间的绘制调用会复用同一组 SPI 片选与总线设置避免每块像素都重复切换 CS从而显著提升连续drawBitmap的吞吐。素材准备JPEG 转 C 数组thumb_test.h、ncc1701.h、batman.h本质上是把 JPEG 二进制字节转成了 C 数组每字节写作0xAB形式并加PROGMEM修饰符见 thumb_test.h 的声明const uint8_t thumb_test[] PROGMEM {...}确保数据被链接器放入 Flash 而非 RAM——这对仅数百 KB RAM 的 ESP32 至关重要。配套的原始素材图片位于 examples/M5Stack 目录下ncc1701.jpg240×77星舰企业号 NCC-1701 剪影与batman.jpg240×240蝙蝠侠图。把任意 JPEG 转成这种头文件后即可用同样的openFLASH方式显示自己的图片。兼容性清单已测试与预期可用的设备README 提供了明确的验证状态已实测通过M5Stack Gray、M5Stack Fire、M5StickC、M5StickC Plus、M5Core2未实测、预期可用M5Stack Basic、M5Go Lite、M5Go——作者说明这些设备应与 M5Stack 兼容但因手头无实物未能验证。示例背后JPEGDEC 库的移植要点把示例逻辑推广到自己的 M5Stack 工程时可直接复用 src/JPEGDEC.h 暴露的完整 API 面数据源内存图用openRAM/openFLASH文件流可用open(File file, ...)需包含 FS.h或自定义 open/close/read/seek 四回调的通用open解码decode(x, y, iOptions)支持与JPEG_AUTO_ROTATE自动旋转依据 EXIF 方向、JPEG_LE_PIXELS、JPEG_LUMA_ONLY灰度输出、JPEG_USES_DMA等按位或组合信息查询getWidth()、getHeight()、getBpp()、getOrientation()、getLastError()等用于解码前后获取元数据与错误码进阶setCropArea()支持裁剪解码decodeDither()可做 1/2/4-bit Floyd-Steinberg 抖动灰度输出适合墨水屏。结合 Tasmota 仓库中该库作为 ESP32 音频与显示相关功能依赖被引入的背景位于 lib/libesp32/JPEGDEC这套 M5Stack 示例展示了它在小型彩屏设备上的典型落地方式无需浮点运算、内存占用低、通过回调与屏幕解耦是 ESP32 系列 MCU 上显示 JPEG 的高性价比方案。【免费下载链接】TasmotaAlternative firmware for ESP8266 and ESP32 based devices with easy configuration using webUI, OTA updates, automation using timers or rules, expandability and entirely local control over MQTT, HTTP, Serial or KNX. Full documentation at项目地址: https://gitcode.com/GitHub_Trending/ta/Tasmota创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考