Yes, I tried your example and replied this on #1979:
"Fantastic!!! Thats just the solution for what I've been trying to do in the last days! It worked well, but slower then when loading bmp with showBMP. Now I'm trying to build a similar sketch for bmp files, but no success yet. Next step will be for jpeg files.
Many Thanks David!!!"
I learn more and more each time I read your posts.
Here's the last and cleanest version of the adapted "show_BMP" that I could build:
// MCUFRIEND UNO shields have microSD on pins 10, 11, 12, 13
// The official <SD.h> library only works on the hardware SPI pins
// e.g. 11, 12, 13 on a Uno
// e.g. 50, 51, 52 on a Mega2560
// e.g. 74, 75, 76 on a Due
//
// if you are not using a UNO, you must use Software SPI:
//
// install v1.0.1 of the <SdFat.h> library with the Arduino Library Manager.
// edit the src/SdFatConfig.h file to #define ENABLE_SOFTWARE_SPI_CLASS 1
//
// copy all your BMP files to the root directory on the microSD with your PC
// (or another directory)
// * Adapted from "Show_BMP_not_Uno.ino" (One of the examples from "MCUFRIEND_kbv Library
// for Uno 2.4, 2.8, 3.5, 3.6, 3.95 inch mcufriend Shields" by PRENTICE, DAVID).
// https://github.com/prenticedavid/MCUFRIEND_kbv
// PURPOSE: A simpler possible function to Load/Show only one BMP at a time from SD card.
// RESTRICTED CONDITIONS: - Image Files: 16 or 24bitBMP (w<=320, h<=240).
// - Uno tft Shield: mcufriend 2.8" Blue (HX8347D; ID=0x4747).
// - Shield plugged on Mega 2560 R3.
// Still under construction.
// VERY GRATEFUL TO DAVID FOR THE VALUABLE LESSONS AND KINDLY "PATIENCE" WITH A NEWBIE.
#include <SPI.h> // f.k. for Arduino-1.5.2
#include <SdFat.h> // Use the SdFat library
#include <Adafruit_GFX.h> // Hardware-specific library
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;
SdFatSoftSpi<12, 11, 13> SD; //Bit-Bang on the Shield pins
#define BMPIMAGEOFFSET 54
#define BUFFPIXEL 20
void setup()
{ tft.begin(0x4747);
SD.begin(10);
tft.setRotation(3);
}
void loop() { //FOR TESTS
char *imagefile = "/test/MOTO_CORRIDA_16bit.bmp"; //var imagefile MUST BE ASSIGNED ON THE MAIN SKECTH
tft.fillScreen(0);
showBMP(imagefile, 0, 0);
delay(1000);
imagefile = "tiger_24bit.bmp"; //var imagefile MUST BE ASSIGNED ON THE MAIN SKECTH
tft.fillScreen(0);
showBMP(imagefile, 0, 0);
delay(1000);
}
uint16_t read16(File& f) {
uint16_t result; // read little-endian
f.read(&result, sizeof(result));
return result;
}
uint32_t read32(File& f) {
uint32_t result;
f.read(&result, sizeof(result));
return result;
}
uint8_t showBMP(char *imagefile, int x, int y)
{
File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8_t bmpDepth; // Bit depth (currently must be 24, 16, 8, 4, 1)
uint32_t bmpImageoffset; // Start of image data in file
uint32_t rowSize; // Not always = bmpWidth; may have padding
uint8_t sdbuffer[3 * BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
uint16_t lcdbuffer[1 + BUFFPIXEL];
uint8_t bitmask, bitshift;
boolean flip = true; // BMP is stored bottom-to-top
int w, h, row, col, lcdbufsiz = 1 + BUFFPIXEL, buffidx;
uint32_t pos; // seek position
boolean is565 = false; //
uint8_t ret;
bmpFile = SD.open(imagefile); // Parse BMP header
(void) read16(bmpFile);
(void) read32(bmpFile); // Read & ignore file size
(void) read32(bmpFile); // Read & ignore creator bytes
bmpImageoffset = read32(bmpFile); // Start of image data
(void) read32(bmpFile); // Read & ignore DIB header size
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
(void)read16(bmpFile);
bmpDepth = read16(bmpFile); // bits per pixel
pos = read32(bmpFile); // format
bool first = true;
is565 = (pos == 3); // ?already in 16-bit format
// BMP rows are padded (if needed) to 4-byte boundary
rowSize = (bmpWidth * bmpDepth / 8 + 3) & ~3;
if (bmpHeight < 0) { // If negative, image is in top-down order.
bmpHeight = -bmpHeight;
flip = false;
}
w = bmpWidth;
h = bmpHeight;
// Set TFT address window to clipped image bounds
tft.setAddrWindow(x, y, x + w - 1, y + h - 1);
for (row = 0; row < h; row++) { // For each scanline...
// Seek to start of scan line. It might seem labor-
// intensive to be doing this on every line, but this
// method covers a lot of gritty details like cropping
// and scanline padding. Also, the seek only takes
// place if the file position actually needs to change
// (avoids a lot of cluster math in SD library).
uint8_t r, g, b, *sdptr;
int lcdidx, lcdleft;
if (flip) // Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize;
if (bmpFile.position() != pos) { // Need seek?
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // Force buffer reload
}
for (col = 0; col < w; ) { //pixels in row
lcdleft = w - col;
if (lcdleft > lcdbufsiz) lcdleft = lcdbufsiz;
for (lcdidx = 0; lcdidx < lcdleft; lcdidx++) { // buffer at a time
uint16_t color;
// Time to read more pixel data?
if (buffidx >= sizeof(sdbuffer)) { // Indeed
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
r = 0;
}
switch (bmpDepth) { // Convert pixel from BMP to TFT format
case 24:
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
color = tft.color565(r, g, b);
break;
case 16:
b = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
if (is565)
color = (r << 8) | (b);
else
color = (r << 9) | ((b & 0xE0) << 1) | (b & 0x1F);
break;
}
lcdbuffer[lcdidx] = color;
}
tft.pushColors(lcdbuffer, lcdidx, first);
first = false;
col += lcdidx;
} // end cols
} // end rows
tft.setAddrWindow(0, 0, tft.width() - 1, tft.height() - 1); //restore full screen
bmpFile.close();
}
Many Thanks David!!!