|
24 | 24 | #include "WProgram.h" |
25 | 25 | #endif |
26 | 26 |
|
27 | | -// The PImage class represents an image stored in the SD card. |
28 | | -// If the SD library is not in the include path, including it will cause |
29 | | -// a compilation error. |
30 | | -#include <SD.h> // will raise a warning if not in the include search path |
31 | | - |
32 | 27 | #if defined(__SD_H__) // Sparkfun's SD library |
33 | 28 | # include "PImage.h" |
34 | 29 | #else |
@@ -192,6 +187,150 @@ class Adafruit_GFX : public Print { |
192 | 187 | bool useFill; |
193 | 188 | }; |
194 | 189 |
|
| 190 | +#if defined(__SD_H__) // Sparkfun's SD library |
| 191 | + |
| 192 | +#define BUFFPIXEL 20 |
| 193 | + |
| 194 | +void Adafruit_GFX::image(PImage & img, uint16_t x, uint16_t y) { |
| 195 | + int w, h, row, col; |
| 196 | + uint8_t r, g, b; |
| 197 | + uint32_t pos = 0; |
| 198 | + uint8_t sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel) |
| 199 | + uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer |
| 200 | + |
| 201 | + // Crop area to be loaded |
| 202 | + w = img._bmpWidth; |
| 203 | + h = img._bmpHeight; |
| 204 | + if((x+w-1) >= width()) w = width() - x; |
| 205 | + if((y+h-1) >= height()) h = height() - y; |
| 206 | + |
| 207 | + /* |
| 208 | + // Set TFT address window to clipped image bounds |
| 209 | + setAddrWindow(x, y, x+w-1, y+h-1); |
| 210 | + */ |
| 211 | + |
| 212 | + for (row=0; row<h; row++) { // For each scanline... |
| 213 | + // Seek to start of scan line. It might seem labor- |
| 214 | + // intensive to be doing this on every line, but this |
| 215 | + // method covers a lot of gritty details like cropping |
| 216 | + // and scanline padding. Also, the seek only takes |
| 217 | + // place if the file position actually needs to change |
| 218 | + // (avoids a lot of cluster math in SD library). |
| 219 | + if(img._flip) // Bitmap is stored bottom-to-top order (normal BMP) |
| 220 | + pos = img._bmpImageoffset + (img._bmpHeight - 1 - row) * img._rowSize; |
| 221 | + else // Bitmap is stored top-to-bottom |
| 222 | + pos = img._bmpImageoffset + row * img._rowSize; |
| 223 | + if(img._bmpFile.position() != pos) { // Need seek? |
| 224 | + img._bmpFile.seek(pos); |
| 225 | + buffidx = sizeof(sdbuffer); // Force buffer reload |
| 226 | + } |
| 227 | + |
| 228 | + for (col=0; col<w; col++) { // For each pixel... |
| 229 | + // Time to read more pixel data? |
| 230 | + if (buffidx >= sizeof(sdbuffer)) { // Indeed |
| 231 | + img._bmpFile.read(sdbuffer, sizeof(sdbuffer)); |
| 232 | + buffidx = 0; // Set index to beginning |
| 233 | + } |
| 234 | + |
| 235 | + // Convert pixel from BMP to TFT format, push to display |
| 236 | + b = sdbuffer[buffidx++]; |
| 237 | + g = sdbuffer[buffidx++]; |
| 238 | + r = sdbuffer[buffidx++]; |
| 239 | + //pushColor(tft.Color565(r,g,b)); |
| 240 | + drawPixel(x + col, y + row, newColor(r, g, b)); |
| 241 | + |
| 242 | + } // end pixel |
| 243 | + } // end scanline |
| 244 | + |
| 245 | +} |
| 246 | + |
| 247 | + |
| 248 | + |
| 249 | + |
| 250 | +// These read 16- and 32-bit types from the SD card file. |
| 251 | +// BMP data is stored little-endian, Arduino is little-endian too. |
| 252 | +// May need to reverse subscript order if porting elsewhere. |
| 253 | + |
| 254 | +uint16_t read16(File f) { |
| 255 | + uint16_t result; |
| 256 | + ((uint8_t *)&result)[0] = f.read(); // LSB |
| 257 | + ((uint8_t *)&result)[1] = f.read(); // MSB |
| 258 | + return result; |
| 259 | +} |
| 260 | + |
| 261 | +uint32_t read32(File f) { |
| 262 | + uint32_t result; |
| 263 | + ((uint8_t *)&result)[0] = f.read(); // LSB |
| 264 | + ((uint8_t *)&result)[1] = f.read(); |
| 265 | + ((uint8_t *)&result)[2] = f.read(); |
| 266 | + ((uint8_t *)&result)[3] = f.read(); // MSB |
| 267 | + return result; |
| 268 | +} |
| 269 | + |
| 270 | + |
| 271 | +PImage PImage::loadImage(const char * fileName) { |
| 272 | + File bmpFile; |
| 273 | + int bmpWidth, bmpHeight; // W+H in pixels |
| 274 | + uint8_t bmpDepth; // Bit depth (currently must be 24) |
| 275 | + uint32_t bmpImageoffset; // Start of image data in file |
| 276 | + uint32_t rowSize; // Not always = bmpWidth; may have padding |
| 277 | + bool flip = true; // BMP is stored bottom-to-top |
| 278 | + |
| 279 | + |
| 280 | + // Open requested file on SD card |
| 281 | + if ((bmpFile = SD.open(fileName)) == NULL) { |
| 282 | + Serial.print("loadImage: file not found: "); |
| 283 | + Serial.println(fileName); |
| 284 | + return PImage(); // load error |
| 285 | + } |
| 286 | + |
| 287 | + |
| 288 | + |
| 289 | + // Parse BMP header |
| 290 | + if(read16(bmpFile) != 0x4D42) { // BMP signature |
| 291 | + Serial.println("loadImage: file doesn't look like a BMP"); |
| 292 | + return PImage(); |
| 293 | + } |
| 294 | + |
| 295 | + Serial.print("File size: "); Serial.println(read32(bmpFile)); |
| 296 | + (void)read32(bmpFile); // Read & ignore creator bytes |
| 297 | + bmpImageoffset = read32(bmpFile); // Start of image data |
| 298 | + Serial.print("Image Offset: "); Serial.println(bmpImageoffset, DEC); |
| 299 | + // Read DIB header |
| 300 | + Serial.print("Header size: "); Serial.println(read32(bmpFile)); |
| 301 | + bmpWidth = read32(bmpFile); |
| 302 | + bmpHeight = read32(bmpFile); |
| 303 | + if(read16(bmpFile) != 1) { // # planes -- must be '1' |
| 304 | + Serial.println("loadImage: invalid n. of planes"); |
| 305 | + return PImage(); |
| 306 | + } |
| 307 | + |
| 308 | + bmpDepth = read16(bmpFile); // bits per pixel |
| 309 | + Serial.print("Bit Depth: "); Serial.println(bmpDepth); |
| 310 | + if((bmpDepth != 24) || (read32(bmpFile) != 0)) { // 0 = uncompressed { |
| 311 | + Serial.println("loadImage: invalid pixel format"); |
| 312 | + return PImage(); |
| 313 | + } |
| 314 | + |
| 315 | + Serial.print("Image size: "); |
| 316 | + Serial.print(bmpWidth); |
| 317 | + Serial.print('x'); |
| 318 | + Serial.println(bmpHeight); |
| 319 | + |
| 320 | + // BMP rows are padded (if needed) to 4-byte boundary |
| 321 | + rowSize = (bmpWidth * 3 + 3) & ~3; |
| 322 | + |
| 323 | + // If bmpHeight is negative, image is in top-down order. |
| 324 | + // This is not canon but has been observed in the wild. |
| 325 | + if(bmpHeight < 0) { |
| 326 | + bmpHeight = -bmpHeight; |
| 327 | + flip = false; |
| 328 | + } |
| 329 | + |
| 330 | + return PImage(bmpFile, bmpWidth, bmpHeight, bmpDepth, bmpImageoffset, rowSize, flip); |
| 331 | +} |
| 332 | + |
| 333 | +#endif |
195 | 334 |
|
196 | 335 |
|
197 | 336 |
|
|
0 commit comments