mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-08 08:37:38 +03:00
Basic glyph compression
This commit is contained in:
parent
afe9672156
commit
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,12 @@ for i_start, i_end in intervals:
|
||||
|
||||
# Build output data
|
||||
packed = bytes(pixels)
|
||||
compressed = zlib.compress(packed)
|
||||
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 +255,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,33 @@
|
||||
#include "GfxRenderer.h"
|
||||
|
||||
#include <Utf8.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)));
|
||||
if (!inflator) {
|
||||
Serial.printf("[%lu] [ZIP] Failed to allocate memory for inflator\n", millis());
|
||||
return false;
|
||||
}
|
||||
memset(inflator, 0, sizeof(tinfl_decompressor));
|
||||
tinfl_init(inflator);
|
||||
|
||||
size_t inBytes = deflatedSize;
|
||||
size_t outBytes = inflatedSize;
|
||||
const tinfl_status status = tinfl_decompress(inflator, inputBuf, &inBytes, nullptr, outputBuf, &outBytes,
|
||||
TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
|
||||
free(inflator);
|
||||
|
||||
if (status != TINFL_STATUS_DONE) {
|
||||
Serial.printf("[%lu] [ZIP] 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}); }
|
||||
|
||||
@ -616,15 +643,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 +714,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…
Reference in New Issue
Block a user