Compare commits
3 Commits
crosspoint
...
feature/gl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
551e57295f | ||
|
|
c9cfedf3d6 | ||
|
|
cb3e08e73c |
@ -5,6 +5,7 @@
|
||||
#include <cstdint>
|
||||
|
||||
/// Font data stored PER GLYPH
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint8_t width; ///< Bitmap dimensions in pixels
|
||||
uint8_t height; ///< Bitmap dimensions in pixels
|
||||
@ -13,7 +14,9 @@ typedef struct {
|
||||
int16_t top; ///< Y dist from cursor pos to UL corner
|
||||
uint16_t dataLength; ///< Size of the font data.
|
||||
uint32_t dataOffset; ///< Pointer into EpdFont->bitmap
|
||||
bool compressed;
|
||||
} EpdGlyph;
|
||||
#pragma pack(pop)
|
||||
|
||||
/// Glyph interval structure
|
||||
typedef struct {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -17,7 +17,7 @@ parser.add_argument("--2bit", dest="is2Bit", action="store_true", help="generate
|
||||
parser.add_argument("--additional-intervals", dest="additional_intervals", action="append", help="Additional code point intervals to export as min,max. This argument can be repeated.")
|
||||
args = parser.parse_args()
|
||||
|
||||
GlyphProps = namedtuple("GlyphProps", ["width", "height", "advance_x", "left", "top", "data_length", "data_offset", "code_point"])
|
||||
GlyphProps = namedtuple("GlyphProps", ["width", "height", "advance_x", "left", "top", "data_length", "data_offset", "compressed", "code_point"])
|
||||
|
||||
font_stack = [freetype.Face(f) for f in args.fontstack]
|
||||
is2Bit = args.is2Bit
|
||||
@ -124,7 +124,6 @@ def load_glyph(code_point):
|
||||
face.load_glyph(glyph_index, freetype.FT_LOAD_RENDER)
|
||||
return face
|
||||
face_index += 1
|
||||
print(f"code point {code_point} ({hex(code_point)}) not found in font stack!", file=sys.stderr)
|
||||
return None
|
||||
|
||||
unmerged_intervals = sorted(intervals + add_ints)
|
||||
@ -242,6 +241,13 @@ for i_start, i_end in intervals:
|
||||
|
||||
# Build output data
|
||||
packed = bytes(pixels)
|
||||
# DEFLATE compressed data without zlib header/footer
|
||||
compressed = zlib.compress(packed, wbits=-15)
|
||||
is_compressed = len(compressed) < len(packed) * 0.9
|
||||
# Use compressed data only if it's at least 10% smaller
|
||||
if is_compressed:
|
||||
packed = compressed
|
||||
|
||||
glyph = GlyphProps(
|
||||
width = bitmap.width,
|
||||
height = bitmap.rows,
|
||||
@ -250,6 +256,7 @@ for i_start, i_end in intervals:
|
||||
top = face.glyph.bitmap_top,
|
||||
data_length = len(packed),
|
||||
data_offset = total_size,
|
||||
compressed = 'true' if is_compressed else 'false',
|
||||
code_point = code_point,
|
||||
)
|
||||
total_size += len(packed)
|
||||
|
||||
@ -1,6 +1,31 @@
|
||||
#include "GfxRenderer.h"
|
||||
|
||||
#include <Utf8.h>
|
||||
#include <miniz.h>
|
||||
|
||||
namespace {
|
||||
tinfl_decompressor* inflator = nullptr;
|
||||
|
||||
bool inflateOneShot(const uint8_t* inputBuf, const size_t deflatedSize, uint8_t* outputBuf, const size_t inflatedSize) {
|
||||
if (!inflator) {
|
||||
Serial.printf("[%lu] [GFX] Inflator not initialized\n", millis());
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t inBytes = deflatedSize;
|
||||
size_t outBytes = inflatedSize;
|
||||
tinfl_init(inflator);
|
||||
const tinfl_status status = tinfl_decompress(inflator, inputBuf, &inBytes, nullptr, outputBuf, &outBytes,
|
||||
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
|
||||
|
||||
if (status != TINFL_STATUS_DONE) {
|
||||
Serial.printf("[%lu] [GFX] tinfl_decompress() failed with status %d\n", millis(), status);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void GfxRenderer::insertFont(const int fontId, EpdFontFamily font) { fontMap.insert({fontId, font}); }
|
||||
|
||||
@ -104,10 +129,21 @@ void GfxRenderer::drawText(const int fontId, const int x, const int y, const cha
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup inflator
|
||||
inflator = static_cast<tinfl_decompressor*>(malloc(sizeof(tinfl_decompressor)));
|
||||
if (!inflator) {
|
||||
Serial.printf("[%lu] [GFX] Failed to allocate memory for inflator\n", millis());
|
||||
return;
|
||||
}
|
||||
memset(inflator, 0, sizeof(tinfl_decompressor));
|
||||
|
||||
uint32_t cp;
|
||||
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&text)))) {
|
||||
renderChar(font, cp, &xpos, &yPos, black, style);
|
||||
}
|
||||
|
||||
free(inflator);
|
||||
inflator = nullptr;
|
||||
}
|
||||
|
||||
void GfxRenderer::drawLine(int x1, int y1, int x2, int y2, const bool state) const {
|
||||
@ -616,15 +652,42 @@ void GfxRenderer::renderChar(const EpdFontFamily& fontFamily, const uint32_t cp,
|
||||
}
|
||||
|
||||
const int is2Bit = fontFamily.getData(style)->is2Bit;
|
||||
const uint32_t offset = glyph->dataOffset;
|
||||
// const uint32_t offset = glyph->dataOffset;
|
||||
// const uint32_t dataLength = glyph->dataLength;
|
||||
const uint8_t width = glyph->width;
|
||||
const uint8_t height = glyph->height;
|
||||
const int left = glyph->left;
|
||||
const size_t outputDataSize = is2Bit ? ((width * height + 3) / 4) : ((width * height + 7) / 8);
|
||||
|
||||
const uint8_t* bitmap = nullptr;
|
||||
bitmap = &fontFamily.getData(style)->bitmap[offset];
|
||||
if (outputDataSize != glyph->dataLength && !glyph->compressed) {
|
||||
Serial.printf("[%lu] [GFX] Glyph bitmap size mismatch for codepoint %d (expected %zu, got %d)\n", millis(), cp,
|
||||
outputDataSize, glyph->dataLength);
|
||||
}
|
||||
|
||||
uint8_t* bitmapData = nullptr;
|
||||
const uint8_t* bitmap;
|
||||
|
||||
if (glyph->compressed) {
|
||||
bitmapData = static_cast<uint8_t*>(malloc(outputDataSize));
|
||||
if (!bitmapData) {
|
||||
Serial.printf("[%lu] [GFX] Failed to allocate memory for glyph bitmap for codepoint %d\n", millis(), cp);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto success = inflateOneShot(&fontFamily.getData(style)->bitmap[glyph->dataOffset], glyph->dataLength,
|
||||
bitmapData, outputDataSize);
|
||||
if (!success) {
|
||||
Serial.printf("[%lu] [GFX] Failed to inflate glyph bitmap for codepoint %d\n", millis(), cp);
|
||||
free(bitmapData);
|
||||
*x += glyph->advanceX;
|
||||
return;
|
||||
}
|
||||
|
||||
bitmap = bitmapData;
|
||||
} else {
|
||||
bitmap = &fontFamily.getData(style)->bitmap[glyph->dataOffset];
|
||||
}
|
||||
|
||||
if (bitmap != nullptr) {
|
||||
for (int glyphY = 0; glyphY < height; glyphY++) {
|
||||
const int screenY = *y - glyph->top + glyphY;
|
||||
for (int glyphX = 0; glyphX < width; glyphX++) {
|
||||
@ -660,6 +723,9 @@ void GfxRenderer::renderChar(const EpdFontFamily& fontFamily, const uint32_t cp,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bitmapData) {
|
||||
free(bitmapData);
|
||||
}
|
||||
|
||||
*x += glyph->advanceX;
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include <SDCardManager.h>
|
||||
#include <miniz.h>
|
||||
|
||||
namespace {
|
||||
bool inflateOneShot(const uint8_t* inputBuf, const size_t deflatedSize, uint8_t* outputBuf, const size_t inflatedSize) {
|
||||
// Setup inflator
|
||||
const auto inflator = static_cast<tinfl_decompressor*>(malloc(sizeof(tinfl_decompressor)));
|
||||
@ -27,6 +28,7 @@ bool inflateOneShot(const uint8_t* inputBuf, const size_t deflatedSize, uint8_t*
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool ZipFile::loadAllFileStatSlims() {
|
||||
const bool wasOpen = isOpen();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user