1 |
mein Header
|
2 |
#ifndef __MYPNGDEC__
|
3 |
#define __MYPNGDEC__
|
4 |
|
5 |
|
6 |
#include <Arduino.h>
|
7 |
#include "FS.h"
|
8 |
#include "SD.h"
|
9 |
#include "SPI.h"
|
10 |
#include <TFT_eSPI.h>
|
11 |
#include <pngdec.h>
|
12 |
|
13 |
#define MAX_IMAGE_WIDTH 320 // Adjust for your images
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
class PngClass {
|
19 |
public:
|
20 |
void InitPngLib(TFT_eSPI tft );
|
21 |
void listDir(fs::FS &fs, const char * dirname, uint8_t levels);
|
22 |
void DrawPng(int x, int y,const String PngName);
|
23 |
|
24 |
private:
|
25 |
TFT_eSPI * _tft;
|
26 |
File pngfile;
|
27 |
PNG _png;
|
28 |
int xpos;
|
29 |
int ypos;
|
30 |
void * pngOpen(const char *filename, int32_t *size);
|
31 |
void pngClose(void *handle);
|
32 |
int32_t pngRead(PNGFILE *page, uint8_t *buffer, int32_t length);
|
33 |
int32_t pngSeek(PNGFILE *page, int32_t position);
|
34 |
String readFile(fs::FS &fs, const char * path);
|
35 |
void pngDraw(PNGDRAW *pDraw);
|
36 |
};
|
37 |
|
38 |
#endif
|
39 |
|
40 |
mein C++ File
|
41 |
#include "MyPngLib.h"
|
42 |
|
43 |
void PngClass::InitPngLib(TFT_eSPI tft )
|
44 |
{
|
45 |
_tft = tft;
|
46 |
//SPIClass spi = SPIClass(VSPI);
|
47 |
|
48 |
Serial.println("**********************************************************");
|
49 |
Serial.print("MOSI: ");
|
50 |
Serial.println(MOSI);
|
51 |
Serial.print("MISO: ");
|
52 |
Serial.println(MISO);
|
53 |
Serial.print("SCK: ");
|
54 |
Serial.println(SCK);
|
55 |
Serial.print("SS: ");
|
56 |
Serial.println(SS);
|
57 |
Serial.println("**********************************************************");
|
58 |
|
59 |
//if (!SD.begin(SS, spi, 80000000))
|
60 |
if (!SD.begin(SS))
|
61 |
{
|
62 |
Serial.println("initialization failed!");
|
63 |
}
|
64 |
|
65 |
Serial.println("initialization done.");
|
66 |
listDir(SD, "/", 0);
|
67 |
|
68 |
}
|
69 |
|
70 |
|
71 |
|
72 |
void PngClass::listDir(fs::FS &fs, const char * dirname, uint8_t levels)
|
73 |
{
|
74 |
Serial.printf("Listing directory: %s\n", dirname);
|
75 |
|
76 |
File root = fs.open(dirname);
|
77 |
if (!root) {
|
78 |
Serial.println("Failed to open directory");
|
79 |
return;
|
80 |
}
|
81 |
if (!root.isDirectory()) {
|
82 |
Serial.println("Not a directory");
|
83 |
return;
|
84 |
}
|
85 |
|
86 |
File file = root.openNextFile();
|
87 |
while (file) {
|
88 |
if (file.isDirectory()) {
|
89 |
Serial.print(" DIR : ");
|
90 |
Serial.println(file.name());
|
91 |
if (levels) {
|
92 |
listDir(fs, file.path(), levels - 1);
|
93 |
}
|
94 |
} else {
|
95 |
Serial.print(" FILE: ");
|
96 |
Serial.print(file.name());
|
97 |
Serial.print(" SIZE: ");
|
98 |
Serial.println(file.size());
|
99 |
}
|
100 |
file = root.openNextFile();
|
101 |
}
|
102 |
}
|
103 |
|
104 |
|
105 |
void * PngClass::pngOpen(const char *filename, int32_t *size)
|
106 |
{
|
107 |
Serial.printf("Attempting to open %s\n", filename);
|
108 |
File _pngfile = SD.open(filename, "r");
|
109 |
*size = _pngfile.size();
|
110 |
return &pngfile;
|
111 |
}
|
112 |
|
113 |
void PngClass::pngClose(void *handle)
|
114 |
{
|
115 |
File _pngfile = *((File*)handle);
|
116 |
if (_pngfile) _pngfile.close();
|
117 |
}
|
118 |
|
119 |
int32_t PngClass::pngRead(PNGFILE *page, uint8_t *buffer, int32_t length)
|
120 |
{
|
121 |
if (!pngfile) return 0;
|
122 |
page = page; // Avoid warning
|
123 |
return pngfile.read(buffer, length);
|
124 |
}
|
125 |
|
126 |
int32_t PngClass::pngSeek(PNGFILE *page, int32_t position)
|
127 |
{
|
128 |
if (!pngfile) return 0;
|
129 |
page = page; // Avoid warning
|
130 |
return pngfile.seek(position);
|
131 |
}
|
132 |
|
133 |
//=========================================v==========================================
|
134 |
// _pngDraw
|
135 |
//====================================================================================
|
136 |
// This next function will be called during decoding of the _png file to
|
137 |
// render each image line to the _tft. If you use a different _tft library
|
138 |
// you will need to adapt this function to suit.
|
139 |
// Callback function to draw pixels to the display
|
140 |
void PngClass::pngDraw(PNGDRAW *pDraw)
|
141 |
{
|
142 |
uint16_t lineBuffer[MAX_IMAGE_WIDTH];
|
143 |
static uint16_t dmaBuffer[MAX_IMAGE_WIDTH]; // static so buffer persists after fn exit
|
144 |
_png.getLineAsRGB565(pDraw, lineBuffer, PNG_RGB565_BIG_ENDIAN, 0xffffffff);
|
145 |
_tft->pushImageDMA(xpos, ypos + pDraw->y, pDraw->iWidth, 1, lineBuffer, dmaBuffer);
|
146 |
}
|
147 |
|
148 |
|
149 |
void PngClass::DrawPng(int x, int y,const String PngName)
|
150 |
{
|
151 |
xpos = x;
|
152 |
ypos = y;
|
153 |
|
154 |
int16_t rc = _png.open(PngName.c_str(), pngOpen, pngClose, pngRead, pngSeek, pngDraw);
|
155 |
if (rc == PNG_SUCCESS) {
|
156 |
_tft->startWrite();
|
157 |
Serial.printf("image specs: (%d x %d), %d bpp, pixel type: %d\n", _png.getWidth(), _png.getHeight(), _png.getBpp(), _png.getPixelType());
|
158 |
uint32_t dt = millis();
|
159 |
if (_png.getWidth() > MAX_IMAGE_WIDTH) {
|
160 |
Serial.println("Image too wide for allocated lin buffer!");
|
161 |
}
|
162 |
else {
|
163 |
rc = _png.decode(NULL, 0);
|
164 |
_png.close();
|
165 |
}
|
166 |
_tft->endWrite();
|
167 |
// How long did rendering take...
|
168 |
Serial.print(millis()-dt); Serial.println("ms");
|
169 |
}
|
170 |
}
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
String PngClass::readFile(fs::FS &fs, const char * path)
|
176 |
{
|
177 |
Serial.printf("Reading file: %s\r\n", path);
|
178 |
File file = fs.open(path, "r");
|
179 |
if(!file || file.isDirectory()){
|
180 |
Serial.println("- empty file or failed to open file");
|
181 |
return String();
|
182 |
}
|
183 |
Serial.println("- read from file:");
|
184 |
String fileContent;
|
185 |
while(file.available()){
|
186 |
fileContent+=String((char)file.read());
|
187 |
}
|
188 |
Serial.println(fileContent);
|
189 |
return fileContent;
|
190 |
}
|