Recover parts of the regression fiasco
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <builtinFonts/bookerly_10_bold.h>
|
||||
#include <builtinFonts/bookerly_10_bolditalic.h>
|
||||
#include <builtinFonts/bookerly_10_italic.h>
|
||||
#include <builtinFonts/bookerly_10_regular.h>
|
||||
#include <builtinFonts/bookerly_12_bold.h>
|
||||
#include <builtinFonts/bookerly_12_bolditalic.h>
|
||||
#include <builtinFonts/bookerly_12_italic.h>
|
||||
@@ -16,6 +20,14 @@
|
||||
#include <builtinFonts/bookerly_18_bolditalic.h>
|
||||
#include <builtinFonts/bookerly_18_italic.h>
|
||||
#include <builtinFonts/bookerly_18_regular.h>
|
||||
#include <builtinFonts/inter_ui_10_bold.h>
|
||||
#include <builtinFonts/inter_ui_10_regular.h>
|
||||
#include <builtinFonts/inter_ui_12_bold.h>
|
||||
#include <builtinFonts/inter_ui_12_regular.h>
|
||||
#include <builtinFonts/notosans_10_bold.h>
|
||||
#include <builtinFonts/notosans_10_bolditalic.h>
|
||||
#include <builtinFonts/notosans_10_italic.h>
|
||||
#include <builtinFonts/notosans_10_regular.h>
|
||||
#include <builtinFonts/notosans_8_regular.h>
|
||||
#include <builtinFonts/notosans_12_bold.h>
|
||||
#include <builtinFonts/notosans_12_bolditalic.h>
|
||||
@@ -33,23 +45,3 @@
|
||||
#include <builtinFonts/notosans_18_bolditalic.h>
|
||||
#include <builtinFonts/notosans_18_italic.h>
|
||||
#include <builtinFonts/notosans_18_regular.h>
|
||||
#include <builtinFonts/opendyslexic_10_bold.h>
|
||||
#include <builtinFonts/opendyslexic_10_bolditalic.h>
|
||||
#include <builtinFonts/opendyslexic_10_italic.h>
|
||||
#include <builtinFonts/opendyslexic_10_regular.h>
|
||||
#include <builtinFonts/opendyslexic_12_bold.h>
|
||||
#include <builtinFonts/opendyslexic_12_bolditalic.h>
|
||||
#include <builtinFonts/opendyslexic_12_italic.h>
|
||||
#include <builtinFonts/opendyslexic_12_regular.h>
|
||||
#include <builtinFonts/opendyslexic_14_bold.h>
|
||||
#include <builtinFonts/opendyslexic_14_bolditalic.h>
|
||||
#include <builtinFonts/opendyslexic_14_italic.h>
|
||||
#include <builtinFonts/opendyslexic_14_regular.h>
|
||||
#include <builtinFonts/opendyslexic_8_bold.h>
|
||||
#include <builtinFonts/opendyslexic_8_bolditalic.h>
|
||||
#include <builtinFonts/opendyslexic_8_italic.h>
|
||||
#include <builtinFonts/opendyslexic_8_regular.h>
|
||||
#include <builtinFonts/ubuntu_10_bold.h>
|
||||
#include <builtinFonts/ubuntu_10_regular.h>
|
||||
#include <builtinFonts/ubuntu_12_bold.h>
|
||||
#include <builtinFonts/ubuntu_12_regular.h>
|
||||
|
||||
@@ -8,6 +8,15 @@ echo "// The contents of this file are generated by ./lib/EpdFont/scripts/build-
|
||||
echo "#pragma once"
|
||||
echo ""
|
||||
|
||||
echo "#define BOOKERLY_10_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./bookerly_10_regular.h",
|
||||
"./bookerly_10_bold.h",
|
||||
"./bookerly_10_bolditalic.h",
|
||||
"./bookerly_10_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define BOOKERLY_12_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./bookerly_12_regular.h",
|
||||
@@ -80,53 +89,26 @@ ruby -rdigest -e 'puts [
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define OPENDYSLEXIC_8_FONT_ID ($(
|
||||
echo "#define NOTOSANS_10_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./opendyslexic_8_regular.h",
|
||||
"./opendyslexic_8_bold.h",
|
||||
"./opendyslexic_8_bolditalic.h",
|
||||
"./opendyslexic_8_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define OPENDYSLEXIC_10_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./opendyslexic_10_regular.h",
|
||||
"./opendyslexic_10_bold.h",
|
||||
"./opendyslexic_10_bolditalic.h",
|
||||
"./opendyslexic_10_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define OPENDYSLEXIC_12_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./opendyslexic_12_regular.h",
|
||||
"./opendyslexic_12_bold.h",
|
||||
"./opendyslexic_12_bolditalic.h",
|
||||
"./opendyslexic_12_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define OPENDYSLEXIC_14_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./opendyslexic_14_regular.h",
|
||||
"./opendyslexic_14_bold.h",
|
||||
"./opendyslexic_14_bolditalic.h",
|
||||
"./opendyslexic_14_italic.h",
|
||||
"./notosans_10_regular.h",
|
||||
"./notosans_10_bold.h",
|
||||
"./notosans_10_bolditalic.h",
|
||||
"./notosans_10_italic.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define UI_10_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./ubuntu_10_regular.h",
|
||||
"./ubuntu_10_bold.h",
|
||||
"./inter_ui_10_regular.h",
|
||||
"./inter_ui_10_bold.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
echo "#define UI_12_FONT_ID ($(
|
||||
ruby -rdigest -e 'puts [
|
||||
"./ubuntu_12_regular.h",
|
||||
"./ubuntu_12_bold.h",
|
||||
"./inter_ui_12_regular.h",
|
||||
"./inter_ui_12_bold.h",
|
||||
].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
|
||||
))"
|
||||
|
||||
|
||||
@@ -5,9 +5,8 @@ set -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
READER_FONT_STYLES=("Regular" "Italic" "Bold" "BoldItalic")
|
||||
BOOKERLY_FONT_SIZES=(12 14 16 18)
|
||||
NOTOSANS_FONT_SIZES=(12 14 16 18)
|
||||
OPENDYSLEXIC_FONT_SIZES=(8 10 12 14)
|
||||
BOOKERLY_FONT_SIZES=(10 12 14 16 18)
|
||||
NOTOSANS_FONT_SIZES=(10 12 14 16 18)
|
||||
|
||||
for size in ${BOOKERLY_FONT_SIZES[@]}; do
|
||||
for style in ${READER_FONT_STYLES[@]}; do
|
||||
@@ -29,28 +28,36 @@ for size in ${NOTOSANS_FONT_SIZES[@]}; do
|
||||
done
|
||||
done
|
||||
|
||||
for size in ${OPENDYSLEXIC_FONT_SIZES[@]}; do
|
||||
for style in ${READER_FONT_STYLES[@]}; do
|
||||
font_name="opendyslexic_${size}_$(echo $style | tr '[:upper:]' '[:lower:]')"
|
||||
font_path="../builtinFonts/source/OpenDyslexic/OpenDyslexic-${style}.otf"
|
||||
output_path="../builtinFonts/${font_name}.h"
|
||||
python fontconvert.py $font_name $size $font_path --2bit --compress > $output_path
|
||||
echo "Generated $output_path"
|
||||
done
|
||||
done
|
||||
|
||||
UI_FONT_SIZES=(10 12)
|
||||
UI_FONT_STYLES=("Regular" "Bold")
|
||||
UI_LANG_INTERVALS=(
|
||||
"0x0000,0x007F"
|
||||
"0x0080,0x00FF"
|
||||
"0x0100,0x017F"
|
||||
"0x01A0,0x01A1"
|
||||
"0x01AF,0x01B0"
|
||||
"0x01C4,0x021F"
|
||||
"0x0300,0x036F"
|
||||
"0x0400,0x04FF"
|
||||
"0x1EA0,0x1EF9"
|
||||
"0x2010,0x206F"
|
||||
"0x20A0,0x20CF"
|
||||
"0xFB00,0xFB06"
|
||||
"0xFFFD,0xFFFD"
|
||||
)
|
||||
|
||||
for size in ${UI_FONT_SIZES[@]}; do
|
||||
for style in ${UI_FONT_STYLES[@]}; do
|
||||
font_name="ubuntu_${size}_$(echo $style | tr '[:upper:]' '[:lower:]')"
|
||||
ubuntu_path="../builtinFonts/source/Ubuntu/Ubuntu-${style}.ttf"
|
||||
# NotoSans used as fallback to fill missing glyphs (e.g. Vietnamese U+1EA0-1EF9)
|
||||
# that are absent from the Ubuntu TTF source.
|
||||
noto_path="../builtinFonts/source/NotoSans/NotoSans-${style}.ttf"
|
||||
font_name="inter_ui_${size}_$(echo $style | tr '[:upper:]' '[:lower:]')"
|
||||
inter_path="../builtinFonts/source/Inter/Inter-${style}.ttf"
|
||||
output_path="../builtinFonts/${font_name}.h"
|
||||
python fontconvert.py $font_name $size $ubuntu_path $noto_path > $output_path
|
||||
|
||||
cmd=(python fontconvert.py "$font_name" "$size" "$inter_path")
|
||||
for interval in "${UI_LANG_INTERVALS[@]}"; do
|
||||
cmd+=(--additional-intervals "$interval")
|
||||
done
|
||||
"${cmd[@]}" > "$output_path"
|
||||
|
||||
echo "Generated $output_path"
|
||||
done
|
||||
done
|
||||
|
||||
@@ -173,6 +173,84 @@ int32_t jpegSeek(JPEGFILE* pFile, int32_t pos) {
|
||||
constexpr size_t JPEG_DECODER_APPROX_SIZE = 20 * 1024;
|
||||
constexpr size_t MIN_FREE_HEAP_FOR_JPEG = JPEG_DECODER_APPROX_SIZE + 16 * 1024;
|
||||
|
||||
bool readJpegDimensionsFromHeader(const std::string& imagePath, ImageDimensions& out) {
|
||||
FsFile f;
|
||||
if (!Storage.openFileForRead("JPG", imagePath, f)) {
|
||||
LOG_ERR("JPG", "Failed to open file for dimensions: %s", imagePath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto readByte = [&f](uint8_t& b) -> bool { return f.read(&b, 1) == 1; };
|
||||
auto readU16BE = [&f](uint16_t& v) -> bool {
|
||||
uint8_t b[2];
|
||||
if (f.read(b, 2) != 2) return false;
|
||||
v = static_cast<uint16_t>((static_cast<uint16_t>(b[0]) << 8) | b[1]);
|
||||
return true;
|
||||
};
|
||||
|
||||
uint8_t b0 = 0;
|
||||
uint8_t b1 = 0;
|
||||
if (!readByte(b0) || !readByte(b1) || b0 != 0xFF || b1 != 0xD8) {
|
||||
f.close();
|
||||
LOG_ERR("JPG", "Not a JPEG file: %s", imagePath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
while (f.available()) {
|
||||
uint8_t prefix = 0;
|
||||
if (!readByte(prefix)) break;
|
||||
if (prefix != 0xFF) continue;
|
||||
|
||||
uint8_t marker = 0;
|
||||
do {
|
||||
if (!readByte(marker)) {
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
} while (marker == 0xFF);
|
||||
|
||||
if (marker == 0x00 || marker == 0xD8 || marker == 0xD9 || (marker >= 0xD0 && marker <= 0xD7)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16_t segLen = 0;
|
||||
if (!readU16BE(segLen) || segLen < 2) {
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool isSof = (marker >= 0xC0 && marker <= 0xC3) || (marker >= 0xC5 && marker <= 0xC7) ||
|
||||
(marker >= 0xC9 && marker <= 0xCB) || (marker >= 0xCD && marker <= 0xCF);
|
||||
if (isSof) {
|
||||
uint8_t sof[5];
|
||||
if (segLen < 7 || f.read(sof, sizeof(sof)) != static_cast<int>(sizeof(sof))) {
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
uint16_t height = static_cast<uint16_t>((static_cast<uint16_t>(sof[1]) << 8) | sof[2]);
|
||||
uint16_t width = static_cast<uint16_t>((static_cast<uint16_t>(sof[3]) << 8) | sof[4]);
|
||||
f.close();
|
||||
if (width == 0 || height == 0) {
|
||||
LOG_ERR("JPG", "Invalid JPEG dimensions %ux%u: %s", width, height, imagePath.c_str());
|
||||
return false;
|
||||
}
|
||||
out.width = static_cast<int16_t>(width);
|
||||
out.height = static_cast<int16_t>(height);
|
||||
return true;
|
||||
}
|
||||
|
||||
const int32_t skip = static_cast<int32_t>(segLen) - 2;
|
||||
if (!f.seek(f.position() + skip)) {
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
f.close();
|
||||
LOG_ERR("JPG", "No SOF marker found for dimensions: %s", imagePath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Choose JPEGDEC's built-in scale factor for coarse downscaling.
|
||||
// Returns the scale denominator (1, 2, 4, or 8) and sets jpegScaleOption.
|
||||
int chooseJpegScale(float targetScale, int& jpegScaleOption) {
|
||||
@@ -401,29 +479,10 @@ int jpegDrawCallback(JPEGDRAW* pDraw) {
|
||||
} // namespace
|
||||
|
||||
bool JpegToFramebufferConverter::getDimensionsStatic(const std::string& imagePath, ImageDimensions& out) {
|
||||
size_t freeHeap = ESP.getFreeHeap();
|
||||
if (freeHeap < MIN_FREE_HEAP_FOR_JPEG) {
|
||||
LOG_ERR("JPG", "Not enough heap for JPEG decoder (%u free, need %u)", freeHeap, MIN_FREE_HEAP_FOR_JPEG);
|
||||
if (!readJpegDimensionsFromHeader(imagePath, out)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<JPEGDEC> jpeg(new (std::nothrow) JPEGDEC());
|
||||
if (!jpeg) {
|
||||
LOG_ERR("JPG", "Failed to allocate JPEG decoder for dimensions");
|
||||
return false;
|
||||
}
|
||||
|
||||
int rc = jpeg->open(imagePath.c_str(), jpegOpen, jpegClose, jpegRead, jpegSeek, nullptr);
|
||||
if (rc != 1) {
|
||||
LOG_ERR("JPG", "Failed to open JPEG for dimensions (err=%d): %s", jpeg->getLastError(), imagePath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
out.width = jpeg->getWidth();
|
||||
out.height = jpeg->getHeight();
|
||||
LOG_DBG("JPG", "Image dimensions: %dx%d", out.width, out.height);
|
||||
|
||||
jpeg->close();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,6 @@ void FontCacheManager::recordText(const char* text, int fontId, EpdFontFamily::S
|
||||
|
||||
FontCacheManager::PrewarmScope::PrewarmScope(FontCacheManager& manager) : manager_(&manager) {
|
||||
manager_->scanMode_ = ScanMode::Scanning;
|
||||
manager_->clearCache();
|
||||
manager_->resetStats();
|
||||
manager_->scanText_.clear();
|
||||
manager_->scanText_.reserve(2048); // Pre-allocate to avoid heap fragmentation from repeated concat
|
||||
@@ -110,15 +109,13 @@ void FontCacheManager::PrewarmScope::endScanAndPrewarm() {
|
||||
|
||||
manager_->prewarmCache(manager_->scanFontId_, manager_->scanText_.c_str(), styleMask);
|
||||
|
||||
// Free scan string memory
|
||||
// Keep reserved capacity to avoid repeated alloc/free churn between pages.
|
||||
manager_->scanText_.clear();
|
||||
manager_->scanText_.shrink_to_fit();
|
||||
}
|
||||
|
||||
FontCacheManager::PrewarmScope::~PrewarmScope() {
|
||||
if (active_) {
|
||||
endScanAndPrewarm(); // no-op if already called (scanText_ is empty)
|
||||
manager_->clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -219,6 +219,7 @@ STR_SMALL: "Small"
|
||||
STR_MEDIUM: "Medium"
|
||||
STR_LARGE: "Large"
|
||||
STR_X_LARGE: "X Large"
|
||||
STR_TINY: "Tiny"
|
||||
STR_TIGHT: "Tight"
|
||||
STR_NORMAL: "Normal"
|
||||
STR_WIDE: "Wide"
|
||||
|
||||
Reference in New Issue
Block a user