mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-05 15:17:37 +03:00
Compare commits
6 Commits
4547dacdd9
...
01182ca57a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01182ca57a | ||
|
|
b8ebcf5867 | ||
|
|
e858ebbe88 | ||
|
|
9224bc3f8c | ||
|
|
67a679ab41 | ||
|
|
7a53342f9d |
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,5 +4,6 @@
|
||||
.vscode
|
||||
lib/EpdFont/fontsrc
|
||||
*.generated.h
|
||||
.vs
|
||||
build
|
||||
**/__pycache__/
|
||||
@ -116,6 +116,7 @@ The Settings screen allows you to configure the device's behavior. There are a f
|
||||
- Back, Confirm, Left, Right (default)
|
||||
- Left, Right, Back, Confirm
|
||||
- Left, Back, Confirm, Right
|
||||
- Back, Confirm, Right, Left
|
||||
- **Side Button Layout (reader)**: Swap the order of the up and down volume buttons from Previous/Next to Next/Previous. This change is only in effect when reading.
|
||||
- **Long-press Chapter Skip**: Set whether long-pressing page turn buttons skip to the next/previous chapter.
|
||||
- "Chapter Skip" (default) - Long-pressing skips to next/previous chapter
|
||||
|
||||
@ -359,7 +359,7 @@ const std::string& Epub::getLanguage() const {
|
||||
}
|
||||
|
||||
std::string Epub::getCoverBmpPath(bool cropped) const {
|
||||
const auto coverFileName = "cover" + cropped ? "_crop" : "";
|
||||
const auto coverFileName = std::string("cover") + (cropped ? "_crop" : "");
|
||||
return cachePath + "/" + coverFileName + ".bmp";
|
||||
}
|
||||
|
||||
@ -382,7 +382,7 @@ bool Epub::generateCoverBmp(bool cropped) const {
|
||||
|
||||
if (coverImageHref.substr(coverImageHref.length() - 4) == ".jpg" ||
|
||||
coverImageHref.substr(coverImageHref.length() - 5) == ".jpeg") {
|
||||
Serial.printf("[%lu] [EBP] Generating BMP from JPG cover image\n", millis());
|
||||
Serial.printf("[%lu] [EBP] Generating BMP from JPG cover image (%s mode)\n", millis(), cropped ? "cropped" : "fit");
|
||||
const auto coverJpgTempPath = getCachePath() + "/.cover.jpg";
|
||||
|
||||
FsFile coverJpg;
|
||||
@ -401,7 +401,7 @@ bool Epub::generateCoverBmp(bool cropped) const {
|
||||
coverJpg.close();
|
||||
return false;
|
||||
}
|
||||
const bool success = JpegToBmpConverter::jpegFileToBmpStream(coverJpg, coverBmp);
|
||||
const bool success = JpegToBmpConverter::jpegFileToBmpStream(coverJpg, coverBmp, cropped);
|
||||
coverJpg.close();
|
||||
coverBmp.close();
|
||||
SdMan.remove(coverJpgTempPath.c_str());
|
||||
|
||||
@ -125,6 +125,8 @@ bool isExplicitHyphen(const uint32_t cp) {
|
||||
case 0xFE58: // small em dash
|
||||
case 0xFE63: // small hyphen-minus
|
||||
case 0xFF0D: // fullwidth hyphen-minus
|
||||
case 0x005F: // Underscore
|
||||
case 0x2026: // Ellipsis
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
@ -200,7 +200,7 @@ unsigned char JpegToBmpConverter::jpegReadCallback(unsigned char* pBuf, const un
|
||||
|
||||
// Internal implementation with configurable target size and bit depth
|
||||
bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bmpOut, int targetWidth, int targetHeight,
|
||||
bool oneBit) {
|
||||
bool oneBit, bool crop) {
|
||||
Serial.printf("[%lu] [JPG] Converting JPEG to %s BMP (target: %dx%d)\n", millis(), oneBit ? "1-bit" : "2-bit",
|
||||
targetWidth, targetHeight);
|
||||
|
||||
@ -242,8 +242,12 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bm
|
||||
const float scaleToFitWidth = static_cast<float>(targetWidth) / imageInfo.m_width;
|
||||
const float scaleToFitHeight = static_cast<float>(targetHeight) / imageInfo.m_height;
|
||||
// We scale to the smaller dimension, so we can potentially crop later.
|
||||
// TODO: ideally, we already crop here.
|
||||
const float scale = (scaleToFitWidth > scaleToFitHeight) ? scaleToFitWidth : scaleToFitHeight;
|
||||
float scale = 1.0;
|
||||
if (crop) { // if we will crop, scale to the smaller dimension
|
||||
scale = (scaleToFitWidth > scaleToFitHeight) ? scaleToFitWidth : scaleToFitHeight;
|
||||
} else { // else, scale to the larger dimension to fit
|
||||
scale = (scaleToFitWidth < scaleToFitHeight) ? scaleToFitWidth : scaleToFitHeight;
|
||||
}
|
||||
|
||||
outWidth = static_cast<int>(imageInfo.m_width * scale);
|
||||
outHeight = static_cast<int>(imageInfo.m_height * scale);
|
||||
@ -550,8 +554,8 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bm
|
||||
}
|
||||
|
||||
// Core function: Convert JPEG file to 2-bit BMP (uses default target size)
|
||||
bool JpegToBmpConverter::jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut) {
|
||||
return jpegFileToBmpStreamInternal(jpegFile, bmpOut, TARGET_MAX_WIDTH, TARGET_MAX_HEIGHT, false);
|
||||
bool JpegToBmpConverter::jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut, bool crop) {
|
||||
return jpegFileToBmpStreamInternal(jpegFile, bmpOut, TARGET_MAX_WIDTH, TARGET_MAX_HEIGHT, false, crop);
|
||||
}
|
||||
|
||||
// Convert with custom target size (for thumbnails, 2-bit)
|
||||
|
||||
@ -8,10 +8,10 @@ class JpegToBmpConverter {
|
||||
static unsigned char jpegReadCallback(unsigned char* pBuf, unsigned char buf_size,
|
||||
unsigned char* pBytes_actually_read, void* pCallback_data);
|
||||
static bool jpegFileToBmpStreamInternal(class FsFile& jpegFile, Print& bmpOut, int targetWidth, int targetHeight,
|
||||
bool oneBit);
|
||||
bool oneBit, bool crop = true);
|
||||
|
||||
public:
|
||||
static bool jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut);
|
||||
static bool jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut, bool crop = true);
|
||||
// Convert with custom target size (for thumbnails)
|
||||
static bool jpegFileToBmpStreamWithSize(FsFile& jpegFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight);
|
||||
// Convert to 1-bit BMP (black and white only, no grays) for fast home screen rendering
|
||||
|
||||
@ -32,7 +32,12 @@ class CrossPointSettings {
|
||||
// Front button layout options
|
||||
// Default: Back, Confirm, Left, Right
|
||||
// Swapped: Left, Right, Back, Confirm
|
||||
enum FRONT_BUTTON_LAYOUT { BACK_CONFIRM_LEFT_RIGHT = 0, LEFT_RIGHT_BACK_CONFIRM = 1, LEFT_BACK_CONFIRM_RIGHT = 2 };
|
||||
enum FRONT_BUTTON_LAYOUT {
|
||||
BACK_CONFIRM_LEFT_RIGHT = 0,
|
||||
LEFT_RIGHT_BACK_CONFIRM = 1,
|
||||
LEFT_BACK_CONFIRM_RIGHT = 2,
|
||||
BACK_CONFIRM_RIGHT_LEFT = 3
|
||||
};
|
||||
|
||||
// Side button layout options
|
||||
// Default: Previous, Next
|
||||
|
||||
@ -14,6 +14,9 @@ decltype(InputManager::BTN_BACK) MappedInputManager::mapButton(const Button butt
|
||||
case CrossPointSettings::LEFT_BACK_CONFIRM_RIGHT:
|
||||
return InputManager::BTN_CONFIRM;
|
||||
case CrossPointSettings::BACK_CONFIRM_LEFT_RIGHT:
|
||||
/* fall through */
|
||||
case CrossPointSettings::BACK_CONFIRM_RIGHT_LEFT:
|
||||
/* fall through */
|
||||
default:
|
||||
return InputManager::BTN_BACK;
|
||||
}
|
||||
@ -24,15 +27,22 @@ decltype(InputManager::BTN_BACK) MappedInputManager::mapButton(const Button butt
|
||||
case CrossPointSettings::LEFT_BACK_CONFIRM_RIGHT:
|
||||
return InputManager::BTN_LEFT;
|
||||
case CrossPointSettings::BACK_CONFIRM_LEFT_RIGHT:
|
||||
/* fall through */
|
||||
case CrossPointSettings::BACK_CONFIRM_RIGHT_LEFT:
|
||||
/* fall through */
|
||||
default:
|
||||
return InputManager::BTN_CONFIRM;
|
||||
}
|
||||
case Button::Left:
|
||||
switch (frontLayout) {
|
||||
case CrossPointSettings::LEFT_RIGHT_BACK_CONFIRM:
|
||||
/* fall through */
|
||||
case CrossPointSettings::LEFT_BACK_CONFIRM_RIGHT:
|
||||
return InputManager::BTN_BACK;
|
||||
case CrossPointSettings::BACK_CONFIRM_RIGHT_LEFT:
|
||||
return InputManager::BTN_RIGHT;
|
||||
case CrossPointSettings::BACK_CONFIRM_LEFT_RIGHT:
|
||||
/* fall through */
|
||||
default:
|
||||
return InputManager::BTN_LEFT;
|
||||
}
|
||||
@ -40,8 +50,12 @@ decltype(InputManager::BTN_BACK) MappedInputManager::mapButton(const Button butt
|
||||
switch (frontLayout) {
|
||||
case CrossPointSettings::LEFT_RIGHT_BACK_CONFIRM:
|
||||
return InputManager::BTN_CONFIRM;
|
||||
case CrossPointSettings::BACK_CONFIRM_RIGHT_LEFT:
|
||||
return InputManager::BTN_LEFT;
|
||||
case CrossPointSettings::BACK_CONFIRM_LEFT_RIGHT:
|
||||
/* fall through */
|
||||
case CrossPointSettings::LEFT_BACK_CONFIRM_RIGHT:
|
||||
/* fall through */
|
||||
default:
|
||||
return InputManager::BTN_RIGHT;
|
||||
}
|
||||
@ -56,6 +70,7 @@ decltype(InputManager::BTN_BACK) MappedInputManager::mapButton(const Button butt
|
||||
case CrossPointSettings::NEXT_PREV:
|
||||
return InputManager::BTN_DOWN;
|
||||
case CrossPointSettings::PREV_NEXT:
|
||||
/* fall through */
|
||||
default:
|
||||
return InputManager::BTN_UP;
|
||||
}
|
||||
@ -64,6 +79,7 @@ decltype(InputManager::BTN_BACK) MappedInputManager::mapButton(const Button butt
|
||||
case CrossPointSettings::NEXT_PREV:
|
||||
return InputManager::BTN_UP;
|
||||
case CrossPointSettings::PREV_NEXT:
|
||||
/* fall through */
|
||||
default:
|
||||
return InputManager::BTN_DOWN;
|
||||
}
|
||||
|
||||
@ -261,6 +261,7 @@ void SleepActivity::renderCoverSleepScreen() const {
|
||||
if (SdMan.openFileForRead("SLP", coverBmpPath, file)) {
|
||||
Bitmap bitmap(file);
|
||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||
Serial.printf("[SLP] Rendering sleep cover: %s\n", coverBmpPath);
|
||||
renderBitmapSleepScreen(bitmap);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -427,7 +427,7 @@ void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const in
|
||||
|
||||
// Right aligned text for progress counter
|
||||
char progressStr[32];
|
||||
snprintf(progressStr, sizeof(progressStr), "%d/%d %.1f%%", section->currentPage + 1, section->pageCount,
|
||||
snprintf(progressStr, sizeof(progressStr), "%d/%d %.0f%%", section->currentPage + 1, section->pageCount,
|
||||
bookProgress);
|
||||
const std::string progress = progressStr;
|
||||
progressTextWidth = renderer.getTextWidth(SMALL_FONT_ID, progress.c_str());
|
||||
|
||||
@ -37,8 +37,9 @@ const SettingInfo readerSettings[readerSettingsCount] = {
|
||||
|
||||
constexpr int controlsSettingsCount = 4;
|
||||
const SettingInfo controlsSettings[controlsSettingsCount] = {
|
||||
SettingInfo::Enum("Front Button Layout", &CrossPointSettings::frontButtonLayout,
|
||||
{"Bck, Cnfrm, Lft, Rght", "Lft, Rght, Bck, Cnfrm", "Lft, Bck, Cnfrm, Rght"}),
|
||||
SettingInfo::Enum(
|
||||
"Front Button Layout", &CrossPointSettings::frontButtonLayout,
|
||||
{"Bck, Cnfrm, Lft, Rght", "Lft, Rght, Bck, Cnfrm", "Lft, Bck, Cnfrm, Rght", "Bck, Cnfrm, Rght, Lft"}),
|
||||
SettingInfo::Enum("Side Button Layout (reader)", &CrossPointSettings::sideButtonLayout,
|
||||
{"Prev, Next", "Next, Prev"}),
|
||||
SettingInfo::Toggle("Long-press Chapter Skip", &CrossPointSettings::longPressChapterSkip),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user