Compare commits
3 Commits
crosspoint
...
feature/gl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
551e57295f | ||
|
|
c9cfedf3d6 | ||
|
|
cb3e08e73c |
@ -5,6 +5,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
/// Font data stored PER GLYPH
|
/// Font data stored PER GLYPH
|
||||||
|
#pragma pack(push, 1)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t width; ///< Bitmap dimensions in pixels
|
uint8_t width; ///< Bitmap dimensions in pixels
|
||||||
uint8_t height; ///< 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
|
int16_t top; ///< Y dist from cursor pos to UL corner
|
||||||
uint16_t dataLength; ///< Size of the font data.
|
uint16_t dataLength; ///< Size of the font data.
|
||||||
uint32_t dataOffset; ///< Pointer into EpdFont->bitmap
|
uint32_t dataOffset; ///< Pointer into EpdFont->bitmap
|
||||||
|
bool compressed;
|
||||||
} EpdGlyph;
|
} EpdGlyph;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
/// Glyph interval structure
|
/// Glyph interval structure
|
||||||
typedef struct {
|
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.")
|
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()
|
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]
|
font_stack = [freetype.Face(f) for f in args.fontstack]
|
||||||
is2Bit = args.is2Bit
|
is2Bit = args.is2Bit
|
||||||
@ -124,7 +124,6 @@ def load_glyph(code_point):
|
|||||||
face.load_glyph(glyph_index, freetype.FT_LOAD_RENDER)
|
face.load_glyph(glyph_index, freetype.FT_LOAD_RENDER)
|
||||||
return face
|
return face
|
||||||
face_index += 1
|
face_index += 1
|
||||||
print(f"code point {code_point} ({hex(code_point)}) not found in font stack!", file=sys.stderr)
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
unmerged_intervals = sorted(intervals + add_ints)
|
unmerged_intervals = sorted(intervals + add_ints)
|
||||||
@ -242,6 +241,13 @@ for i_start, i_end in intervals:
|
|||||||
|
|
||||||
# Build output data
|
# Build output data
|
||||||
packed = bytes(pixels)
|
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(
|
glyph = GlyphProps(
|
||||||
width = bitmap.width,
|
width = bitmap.width,
|
||||||
height = bitmap.rows,
|
height = bitmap.rows,
|
||||||
@ -250,6 +256,7 @@ for i_start, i_end in intervals:
|
|||||||
top = face.glyph.bitmap_top,
|
top = face.glyph.bitmap_top,
|
||||||
data_length = len(packed),
|
data_length = len(packed),
|
||||||
data_offset = total_size,
|
data_offset = total_size,
|
||||||
|
compressed = 'true' if is_compressed else 'false',
|
||||||
code_point = code_point,
|
code_point = code_point,
|
||||||
)
|
)
|
||||||
total_size += len(packed)
|
total_size += len(packed)
|
||||||
|
|||||||
@ -1,6 +1,31 @@
|
|||||||
#include "GfxRenderer.h"
|
#include "GfxRenderer.h"
|
||||||
|
|
||||||
#include <Utf8.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}); }
|
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;
|
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;
|
uint32_t cp;
|
||||||
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&text)))) {
|
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&text)))) {
|
||||||
renderChar(font, cp, &xpos, &yPos, black, style);
|
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 {
|
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 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 width = glyph->width;
|
||||||
const uint8_t height = glyph->height;
|
const uint8_t height = glyph->height;
|
||||||
const int left = glyph->left;
|
const int left = glyph->left;
|
||||||
|
const size_t outputDataSize = is2Bit ? ((width * height + 3) / 4) : ((width * height + 7) / 8);
|
||||||
|
|
||||||
const uint8_t* bitmap = nullptr;
|
if (outputDataSize != glyph->dataLength && !glyph->compressed) {
|
||||||
bitmap = &fontFamily.getData(style)->bitmap[offset];
|
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++) {
|
for (int glyphY = 0; glyphY < height; glyphY++) {
|
||||||
const int screenY = *y - glyph->top + glyphY;
|
const int screenY = *y - glyph->top + glyphY;
|
||||||
for (int glyphX = 0; glyphX < width; glyphX++) {
|
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;
|
*x += glyph->advanceX;
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include <SDCardManager.h>
|
#include <SDCardManager.h>
|
||||||
#include <miniz.h>
|
#include <miniz.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
bool inflateOneShot(const uint8_t* inputBuf, const size_t deflatedSize, uint8_t* outputBuf, const size_t inflatedSize) {
|
bool inflateOneShot(const uint8_t* inputBuf, const size_t deflatedSize, uint8_t* outputBuf, const size_t inflatedSize) {
|
||||||
// Setup inflator
|
// Setup inflator
|
||||||
const auto inflator = static_cast<tinfl_decompressor*>(malloc(sizeof(tinfl_decompressor)));
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
bool ZipFile::loadAllFileStatSlims() {
|
bool ZipFile::loadAllFileStatSlims() {
|
||||||
const bool wasOpen = isOpen();
|
const bool wasOpen = isOpen();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user