0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

M5Stack TFカード ビットマップフォーマットのダンプ表示

Posted at

bitmapのフォーマットをdump表示。

bitmapフォーマットダンプ.png
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();
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?