Skip to content

Header writing to a separate function #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 100 additions & 54 deletions src/OpenStreetMap-esp32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ bool OpenStreetMap::downloadAndDecodeTile(CachedTile &tile, uint32_t x, uint32_t
if (!readTileDataToBuffer(stream, buffer, contentSize, result))
{
http.end();
log_e("%s", result);
log_e("%s", result.c_str());
return false;
}

Expand Down Expand Up @@ -412,37 +412,8 @@ bool OpenStreetMap::downloadAndDecodeTile(CachedTile &tile, uint32_t x, uint32_t
return true;
}

bool OpenStreetMap::saveMap(const char *filename, LGFX_Sprite &map, String &result, uint8_t sdPin, uint32_t frequency)
bool OpenStreetMap::writeHeader(const LGFX_Sprite &map, File &file)
{
log_i("Saving map as %s", filename);

if (!map.getBuffer())
{
result = "No data in map";
return false;
}

MemoryBuffer rowBuffer(map.width() * 3);
if (!rowBuffer.isAllocated())
{
result = "Row buffer allocation failed";
return false;
}

if (!SD.begin(sdPin, SPI, frequency))
{
result = "SD Card mount failed";
return false;
}

File file = SD.open(filename, FILE_WRITE);
if (!file)
{
result = "Failed to open file";
SD.end();
return false;
}

// BMP Header (54 bytes)
uint16_t bfType = 0x4D42; // "BM"
uint32_t biSizeImage = map.width() * map.height() * 3; // 3 bytes per pixel (RGB888)
Expand All @@ -460,32 +431,57 @@ bool OpenStreetMap::saveMap(const char *filename, LGFX_Sprite &map, String &resu
uint32_t biClrUsed = 0;
uint32_t biClrImportant = 0;

// Write BMP header (Ensuring little-endian format)
auto writeLE = [&](uint32_t value, uint8_t size)
auto writeLE = [&](uint32_t value, uint8_t size) -> bool
{
for (uint8_t i = 0; i < size; i++)
file.write(static_cast<uint8_t>(value >> (8 * i)));
if (file.write(static_cast<uint8_t>(value >> (8 * i))) != 1)
return false;

return true;
};

writeLE(bfType, 2);
writeLE(bfSize, 4);
writeLE(0, 2); // bfReserved
writeLE(0, 2);
writeLE(bfOffBits, 4);

writeLE(biSize, 4);
writeLE(biWidth, 4);
writeLE(biHeight, 4);
writeLE(biPlanes, 2);
writeLE(biBitCount, 2);
writeLE(biCompression, 4);
writeLE(biSizeImage, 4);
writeLE(biXPelsPerMeter, 4);
writeLE(biYPelsPerMeter, 4);
writeLE(biClrUsed, 4);
writeLE(biClrImportant, 4);

uint8_t *buf = rowBuffer.get();
bool success = true;

if (!(success &= writeLE(bfType, 2)))
return false;
if (!(success &= writeLE(bfSize, 4)))
return false;
if (!(success &= writeLE(0, 2)))
return false;
if (!(success &= writeLE(0, 2)))
return false;
if (!(success &= writeLE(bfOffBits, 4)))
return false;
if (!(success &= writeLE(biSize, 4)))
return false;
if (!(success &= writeLE(biWidth, 4)))
return false;
if (!(success &= writeLE(biHeight, 4)))
return false;
if (!(success &= writeLE(biPlanes, 2)))
return false;
if (!(success &= writeLE(biBitCount, 2)))
return false;
if (!(success &= writeLE(biCompression, 4)))
return false;
if (!(success &= writeLE(biSizeImage, 4)))
return false;
if (!(success &= writeLE(biXPelsPerMeter, 4)))
return false;
if (!(success &= writeLE(biYPelsPerMeter, 4)))
return false;
if (!(success &= writeLE(biClrUsed, 4)))
return false;
if (!(success &= writeLE(biClrImportant, 4)))
return false;

return success;
}

bool OpenStreetMap::writeMap(LGFX_Sprite &map, File &file, MemoryBuffer &buffer)
{
uint8_t *buf = buffer.get();
const size_t size = buffer.size();
for (uint16_t y = 0; y < map.height(); y++)
{
for (uint16_t x = 0; x < map.width(); x++)
Expand All @@ -499,7 +495,57 @@ bool OpenStreetMap::saveMap(const char *filename, LGFX_Sprite &map, String &resu
buf[x * 3 + 1] = green8;
buf[x * 3 + 2] = red8;
}
file.write(buf, rowBuffer.size());
if (file.write(buf, size) != size)
return false;
}
return true;
}

bool OpenStreetMap::saveMap(const char *filename, LGFX_Sprite &map, String &result, uint8_t sdPin, uint32_t frequency)
{
log_i("Saving map as %s", filename);

if (!map.getBuffer())
{
result = "No data in map";
return false;
}

MemoryBuffer rowBuffer(map.width() * 3);
if (!rowBuffer.isAllocated())
{
result = "Row buffer allocation failed";
return false;
}

if (!SD.begin(sdPin, SPI, frequency))
{
result = "SD Card mount failed";
return false;
}

File file = SD.open(filename, FILE_WRITE);
if (!file)
{
result = "Failed to open file";
SD.end();
return false;
}

if (!writeHeader(map, file))
{
result = "Failed to write bmp header";
file.close();
SD.end();
return false;
}

if (!writeMap(map, file, rowBuffer))
{
result = "Failed to write map data";
file.close();
SD.end();
return false;
}

file.close();
Expand Down
4 changes: 3 additions & 1 deletion src/OpenStreetMap-esp32.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ class OpenStreetMap
bool downloadAndDecodeTile(CachedTile &tile, uint32_t x, uint32_t y, uint8_t zoom, String &result);
bool readTileDataToBuffer(WiFiClient *stream, MemoryBuffer &buffer, size_t contentSize, String &result);
bool composeMap(LGFX_Sprite &mapSprite, const tileList &requiredTiles, uint8_t zoom);
bool writeHeader(const LGFX_Sprite &map, File &file);
bool writeMap(LGFX_Sprite &map, File &file, MemoryBuffer &buffer);

std::vector<CachedTile> tilesCache;
uint16_t *currentTileBuffer = nullptr;
Expand All @@ -84,7 +86,7 @@ class OpenStreetMap
int32_t startTileIndexX = 0;
int32_t startTileIndexY = 0;

uint16_t numberOfColums = 0;
uint16_t numberOfColums = 0;
};

#endif