bitmapのフォーマットをdump表示。
TFカードからビットマップを読み出すときの内容をダンプしました。
<参考>
bitmapフォーマットの解説を参考にさせてもらいました。
https://www.marutsu.co.jp/pc/static/large_order/capture_220812
main.cpp
#include <M5Core2.h>
uint16_t s_read16(fs::File &f);
uint32_t s_read32(fs::File &f);
void readSD(fs::FS &fs, const char *path);
void setup()
{
M5.begin();
M5.Lcd.fillScreen(WHITE);
M5.Lcd.setTextSize(2);
M5.Lcd.print("SD TEST");
readSD(SD,"/tyrrell019mini.bmp");
}
void loop()
{
delay(1);
}
// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.
uint16_t s_read16(fs::File &f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read(); // MSB
return result;
}
uint32_t s_read32(fs::File &f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // MSB
return result;
}
void readSD(fs::FS &fs, const char *path)
{
//SDカードオープン
File bmpFS = fs.open(path, "r", false);
if(!bmpFS)
{
Serial.print("File not found");
return;
}
//経過時間の計測
uint32_t startTime = millis();
//BMPフォーマット
uint32_t seekOffset;
uint16_t w,h;
uint16_t row, col;
uint16_t ch;
ch = s_read16(bmpFS);
if(((uint8_t *)&ch)[1] =='M' && ((uint8_t *)&ch)[0] == 'B')//0000:M(0x4D) 0001:B(0x42)
{
//BMPファイルヘッダ
uint32_t bfSize = s_read32(bmpFS);//0002h:ファイルサイズ
uint32_t bfReserved1 = s_read16(bmpFS);//0006h:リザーブ0x0000
uint32_t bfReserved2 = s_read16(bmpFS);//0008h:リザーブ0x0000
seekOffset = s_read32(bmpFS);//000Ahファイル先頭からイメージデータまでの総バイト数
Serial.printf("0002:FileSize:%d(bytes)\r", bfSize);
Serial.printf("0006:Reserve:%04x\r",bfReserved1);
Serial.printf("0008:Reserve:%04x\r",bfReserved2);
Serial.printf("000A:Offset:%d(bytes)\r",seekOffset);
//BMPファイル情報ヘッダ
uint32_t hsize = s_read32(bmpFS);//000Eh:ヘッダーサイズ(40byte)
w=s_read32(bmpFS);//0012h:イメージ幅
h=s_read32(bmpFS);//0016h:イメージ高さ
uint16_t biPlanes = s_read16(bmpFS);//001Ah:プレーン数(常に1)
uint16_t biBitCount = s_read16(bmpFS);//001Ch:ビット数/pixel
uint32_t biCompression = s_read32(bmpFS);//001Eh:圧縮方式:0
Serial.printf("000E:HeaderSize:%d(bytes)\r",hsize);
Serial.printf("0012:Width:%d(pix)\r",w);
Serial.printf("0016:Height:%d(pix)\r",h);
Serial.printf("001A:Plane:%d\r",biPlanes);
Serial.printf("001C:BitCount:%d(bit/pixel)\r",biBitCount);
Serial.printf("001E:Compression:%d\r",biCompression);
//BMP format check
if((biPlanes==1) && (biBitCount==24) && (biCompression == 0))
{
bmpFS.seek(seekOffset);//イメージデータへポインタジャンプ
//1行分のデータは4の倍数に合わせるpadding.
uint16_t padding = (4 - ((w*3)&3))&3;//&3は4で割った余り。
uint8_t lineBuffer[w * 3 + padding];//4の倍数の配列確保
//イメージデータの読み出し リトルエンディアン
for(row=0; row<h; row++)
{
bmpFS.read(lineBuffer,sizeof(lineBuffer));
uint8_t *bptr = lineBuffer;
//uint16_t *tptr = (uint16_t*)lineBuffer;
Serial.printf("ROW:%d ",row);
for(col=0; col<w; col++)
{
Serial.printf("%02X %02X %02X,",*bptr++, *bptr++, *bptr);
}
Serial.printf("\r");
}
Serial.print("elapsed time ");
Serial.print(millis()-startTime);
Serial.println(" ms");
}else
{
Serial.println("BMP format not recognized.");
}
}else
{
Serial.println("BM error");
}
bmpFS.close();
}
参考にしたコード。M5ライブラリ TFカードからBMPを読込む関数。
M5display.cpp
// Bodmers BMP image rendering function
void M5Display::drawBmpFile(fs::FS &fs, const char *path, uint16_t x,
uint16_t y) {
if ((x >= width()) || (y >= height())) return;
// Open requested file on SD card
File bmpFS = fs.open(path, "r");
if (!bmpFS) {
Serial.print("File not found");
return;
}
uint32_t seekOffset;
uint16_t w, h, row, col;
uint8_t r, g, b;
uint32_t startTime = millis();
if (read16(bmpFS) == 0x4D42) {
read32(bmpFS);
read32(bmpFS);
seekOffset = read32(bmpFS);
read32(bmpFS);
w = read32(bmpFS);
h = read32(bmpFS);
if ((read16(bmpFS) == 1) && (read16(bmpFS) == 24) && (read32(bmpFS) == 0)) {
y += h - 1;
setSwapBytes(true);
bmpFS.seek(seekOffset);
uint16_t padding = (4 - ((w * 3) & 3)) & 3;
uint8_t lineBuffer[w * 3 + padding];
for (row = 0; row < h; row++) {
bmpFS.read(lineBuffer, sizeof(lineBuffer));
uint8_t *bptr = lineBuffer;
uint16_t *tptr = (uint16_t *)lineBuffer;
// Convert 24 to 16 bit colours
for (col = 0; col < w; col++) {
b = *bptr++;
g = *bptr++;
r = *bptr++;
*tptr++ = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
// Push the pixel row to screen, pushImage will crop the line if needed
// y is decremented as the BMP image is drawn bottom up
pushImage(x, y--, w, 1, (uint16_t *)lineBuffer);
}
Serial.print("Loaded in ");
Serial.print(millis() - startTime);
Serial.println(" ms");
} else
Serial.println("BMP format not recognized.");
}
bmpFS.close();
}