Merge 077526a12699e75b45783a9c16da76cec56f10dc into 3ce11f14ce7bc3ce1f2f040bfb09a9b3d9f87f72
This commit is contained in:
commit
a7fb41a3ac
@ -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";
|
||||
}
|
||||
|
||||
|
||||
@ -152,8 +152,17 @@ void GfxRenderer::drawImage(const uint8_t bitmap[], const int x, const int y, co
|
||||
einkDisplay.drawImage(bitmap, rotatedX, rotatedY, width, height);
|
||||
}
|
||||
|
||||
void GfxRenderer::drawVal(const int x, const int y, const uint8_t val) const {
|
||||
if (renderMode == BW && val < 3) {
|
||||
drawPixel(x, y);
|
||||
} else if (renderMode == GRAYSCALE_MSB && (val == 1 || val == 2)) {
|
||||
drawPixel(x, y, false);
|
||||
} else if (renderMode == GRAYSCALE_LSB && val == 1) {
|
||||
drawPixel(x, y, false);
|
||||
}
|
||||
}
|
||||
void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, const int maxWidth, const int maxHeight,
|
||||
const float cropX, const float cropY) const {
|
||||
const float cropX, const float cropY, bool extend) const {
|
||||
// For 1-bit bitmaps, use optimized 1-bit rendering path (no crop support for 1-bit)
|
||||
if (bitmap.is1Bit() && cropX == 0.0f && cropY == 0.0f) {
|
||||
drawBitmap1Bit(bitmap, x, y, maxWidth, maxHeight);
|
||||
@ -233,12 +242,85 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con
|
||||
|
||||
const uint8_t val = outputRow[bmpX / 4] >> (6 - ((bmpX * 2) % 8)) & 0x3;
|
||||
|
||||
if (renderMode == BW && val < 3) {
|
||||
drawPixel(screenX, screenY);
|
||||
} else if (renderMode == GRAYSCALE_MSB && (val == 1 || val == 2)) {
|
||||
drawPixel(screenX, screenY, false);
|
||||
} else if (renderMode == GRAYSCALE_LSB && val == 1) {
|
||||
drawPixel(screenX, screenY, false);
|
||||
drawVal(screenX, screenY, val);
|
||||
|
||||
// draw extended pixels
|
||||
// amount of pixels taken from bitmap and repeated to extend.
|
||||
// Trade-off between risk of repeating "edgy" content like text and more quality
|
||||
int extendY = 20;
|
||||
int extendX = 20;
|
||||
int drawExtY = 0;
|
||||
if (extend) {
|
||||
int imgHeight = std::floor(scale * (bitmap.getHeight() - cropPixY));
|
||||
int imgWidth = std::floor(scale * (bitmap.getWidth() - cropPixX));
|
||||
// 1. TOP EXTENSION
|
||||
// Check if the current pixel is within the strip to be mirrored
|
||||
if (screenY >= y && screenY < y + extendY) {
|
||||
// How many times do we need to mirror to fill the gap 'y'?
|
||||
// Using +1 to ensure we cover fractional blocks at the screen edge
|
||||
int numIterations = (y / extendY) + 1;
|
||||
|
||||
for (int ny = 0; ny < numIterations; ny++) {
|
||||
// Compute 2 target rows t1, t2 for "accordeon" effect.
|
||||
// Mirror Fold (e.g., pixel 0 goes to y-1, pixel 1 to y-2)
|
||||
int t1 = y - 1 - (2 * ny * extendY + (screenY - y));
|
||||
// Reverse Fold (creates the 'accordion' continuity)
|
||||
int t2 = y - 1 - (2 * ny * extendY + (2 * extendY - 1 - (screenY - y)));
|
||||
|
||||
if (t1 >= 0 && t1 < y) drawVal(screenX, t1, val);
|
||||
if (t2 >= 0 && t2 < y) drawVal(screenX, t2, val);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. BOTTOM EXTENSION
|
||||
int imgBottom = y + imgHeight;
|
||||
int gapBottom = getScreenHeight() - imgBottom;
|
||||
|
||||
if (screenY >= imgBottom - extendY && screenY < imgBottom) {
|
||||
int numIterations = (gapBottom / extendY) + 1;
|
||||
|
||||
for (int ny = 0; ny < numIterations; ny++) {
|
||||
// Mirror Fold (pixel at imgBottom-1 goes to imgBottom)
|
||||
int t1 = imgBottom + (2 * ny * extendY + (imgBottom - 1 - screenY));
|
||||
// Reverse Fold
|
||||
int t2 = imgBottom + (2 * ny * extendY + (2 * extendY - 1 - (imgBottom - 1 - screenY)));
|
||||
|
||||
if (t1 >= imgBottom && t1 < getScreenHeight()) drawVal(screenX, t1, val);
|
||||
if (t2 >= imgBottom && t2 < getScreenHeight()) drawVal(screenX, t2, val);
|
||||
}
|
||||
}
|
||||
|
||||
// --- 2. LEFT EXTENSION ---
|
||||
int imgRight = x + imgWidth; // x is the left margin/offset
|
||||
// If the current pixel is within the leftmost 'extendX' pixels of the image
|
||||
if (screenX >= x && screenX < x + extendX) {
|
||||
int numIterations = (x / extendX) + 1;
|
||||
for (int nx = 0; nx < numIterations; nx++) {
|
||||
// Mirror Fold (pixel at 'x' maps to 'x-1')
|
||||
int t1 = x - 1 - (2 * nx * extendX + (screenX - x));
|
||||
// Reverse Fold
|
||||
int t2 = x - 1 - (2 * nx * extendX + (2 * extendX - 1 - (screenX - x)));
|
||||
|
||||
if (t1 >= 0 && t1 < x) drawVal(t1, screenY, val);
|
||||
if (t2 >= 0 && t2 < x) drawVal(t2, screenY, val);
|
||||
}
|
||||
}
|
||||
|
||||
// --- 3. RIGHT EXTENSION ---
|
||||
int gapRight = getScreenWidth() - imgRight;
|
||||
// If the current pixel is within the rightmost 'extendX' pixels of the image
|
||||
if (screenX >= imgRight - extendX && screenX < imgRight) {
|
||||
int numIterations = (gapRight / extendX) + 1;
|
||||
for (int nx = 0; nx < numIterations; nx++) {
|
||||
// Mirror Fold (pixel at 'imgRight-1' maps to 'imgRight')
|
||||
int t1 = imgRight + (2 * nx * extendX + (imgRight - 1 - screenX));
|
||||
// Reverse Fold
|
||||
int t2 = imgRight + (2 * nx * extendX + (2 * extendX - 1 - (imgRight - 1 - screenX)));
|
||||
|
||||
if (t1 >= imgRight && t1 < getScreenWidth()) drawVal(t1, screenY, val);
|
||||
if (t2 >= imgRight && t2 < getScreenWidth()) drawVal(t2, screenY, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,12 +62,13 @@ class GfxRenderer {
|
||||
|
||||
// Drawing
|
||||
void drawPixel(int x, int y, bool state = true) const;
|
||||
void drawVal(const int x, const int y, const uint8_t val) const;
|
||||
void drawLine(int x1, int y1, int x2, int y2, bool state = true) const;
|
||||
void drawRect(int x, int y, int width, int height, bool state = true) const;
|
||||
void fillRect(int x, int y, int width, int height, bool state = true) const;
|
||||
void drawImage(const uint8_t bitmap[], int x, int y, int width, int height) const;
|
||||
void drawBitmap(const Bitmap& bitmap, int x, int y, int maxWidth, int maxHeight, float cropX = 0,
|
||||
float cropY = 0) const;
|
||||
void drawBitmap(const Bitmap& bitmap, int x, int y, int maxWidth, int maxHeight, float cropX = 0, float cropY = 0,
|
||||
bool extend = false) const;
|
||||
void drawBitmap1Bit(const Bitmap& bitmap, int x, int y, int maxWidth, int maxHeight) const;
|
||||
void fillPolygon(const int* xPoints, const int* yPoints, int numPoints, bool state = true) const;
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ class CrossPointSettings {
|
||||
|
||||
// Should match with SettingsActivity text
|
||||
enum SLEEP_SCREEN_MODE { DARK = 0, LIGHT = 1, CUSTOM = 2, COVER = 3, BLANK = 4 };
|
||||
enum SLEEP_SCREEN_COVER_MODE { FIT = 0, CROP = 1 };
|
||||
enum SLEEP_SCREEN_COVER_MODE { FIT = 0, CROP = 1, EXTEND = 2 };
|
||||
|
||||
// Status bar display type enum
|
||||
enum STATUS_BAR_MODE { NONE = 0, NO_PROGRESS = 1, FULL = 2 };
|
||||
|
||||
@ -177,22 +177,23 @@ void SleepActivity::renderBitmapSleepScreen(const Bitmap& bitmap) const {
|
||||
y = (pageHeight - bitmap.getHeight()) / 2;
|
||||
}
|
||||
|
||||
bool extended = SETTINGS.sleepScreenCoverMode == CrossPointSettings::SLEEP_SCREEN_COVER_MODE::EXTEND;
|
||||
Serial.printf("[%lu] [SLP] drawing to %d x %d\n", millis(), x, y);
|
||||
renderer.clearScreen();
|
||||
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY);
|
||||
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY, extended);
|
||||
renderer.displayBuffer(EInkDisplay::HALF_REFRESH);
|
||||
|
||||
if (bitmap.hasGreyscale()) {
|
||||
bitmap.rewindToData();
|
||||
renderer.clearScreen(0x00);
|
||||
renderer.setRenderMode(GfxRenderer::GRAYSCALE_LSB);
|
||||
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY);
|
||||
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY, extended);
|
||||
renderer.copyGrayscaleLsbBuffers();
|
||||
|
||||
bitmap.rewindToData();
|
||||
renderer.clearScreen(0x00);
|
||||
renderer.setRenderMode(GfxRenderer::GRAYSCALE_MSB);
|
||||
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY);
|
||||
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY, extended);
|
||||
renderer.copyGrayscaleMsbBuffers();
|
||||
|
||||
renderer.displayGrayBuffer();
|
||||
|
||||
@ -15,7 +15,7 @@ constexpr int displaySettingsCount = 5;
|
||||
const SettingInfo displaySettings[displaySettingsCount] = {
|
||||
// Should match with SLEEP_SCREEN_MODE
|
||||
SettingInfo::Enum("Sleep Screen", &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover", "None"}),
|
||||
SettingInfo::Enum("Sleep Screen Cover Mode", &CrossPointSettings::sleepScreenCoverMode, {"Fit", "Crop"}),
|
||||
SettingInfo::Enum("Sleep Screen Cover Mode", &CrossPointSettings::sleepScreenCoverMode, {"Fit", "Crop", "Extend"}),
|
||||
SettingInfo::Enum("Status Bar", &CrossPointSettings::statusBar, {"None", "No Progress", "Full"}),
|
||||
SettingInfo::Enum("Hide Battery %", &CrossPointSettings::hideBatteryPercentage, {"Never", "In Reader", "Always"}),
|
||||
SettingInfo::Enum("Refresh Frequency", &CrossPointSettings::refreshFrequency,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user