Feature/cover crop mode (#225)
Added a setting to select `fit` or `crop` for cover image on sleep screen. Might add a `expand` feature in the future that does not crop but rather fills the blank space with a mirror of the image. --------- Co-authored-by: Dave Allie <dave@daveallie.com>
This commit is contained in:
@@ -250,34 +250,29 @@ BmpReaderError Bitmap::parseHeaders() {
|
|||||||
delete[] errorNextRow;
|
delete[] errorNextRow;
|
||||||
errorCurRow = new int16_t[width + 2](); // +2 for boundary handling
|
errorCurRow = new int16_t[width + 2](); // +2 for boundary handling
|
||||||
errorNextRow = new int16_t[width + 2]();
|
errorNextRow = new int16_t[width + 2]();
|
||||||
lastRowY = -1;
|
prevRowY = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BmpReaderError::Ok;
|
return BmpReaderError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
// packed 2bpp output, 0 = black, 1 = dark gray, 2 = light gray, 3 = white
|
// packed 2bpp output, 0 = black, 1 = dark gray, 2 = light gray, 3 = white
|
||||||
BmpReaderError Bitmap::readRow(uint8_t* data, uint8_t* rowBuffer, int rowY) const {
|
BmpReaderError Bitmap::readNextRow(uint8_t* data, uint8_t* rowBuffer) const {
|
||||||
// Note: rowBuffer should be pre-allocated by the caller to size 'rowBytes'
|
// Note: rowBuffer should be pre-allocated by the caller to size 'rowBytes'
|
||||||
if (file.read(rowBuffer, rowBytes) != rowBytes) return BmpReaderError::ShortReadRow;
|
if (file.read(rowBuffer, rowBytes) != rowBytes) return BmpReaderError::ShortReadRow;
|
||||||
|
|
||||||
// Handle Floyd-Steinberg error buffer progression
|
// Handle Floyd-Steinberg error buffer progression
|
||||||
const bool useFS = USE_FLOYD_STEINBERG && errorCurRow && errorNextRow;
|
const bool useFS = USE_FLOYD_STEINBERG && errorCurRow && errorNextRow;
|
||||||
if (useFS) {
|
if (useFS) {
|
||||||
// Check if we need to advance to next row (or reset if jumping)
|
if (prevRowY != -1) {
|
||||||
if (rowY != lastRowY + 1 && rowY != 0) {
|
|
||||||
// Non-sequential row access - reset error buffers
|
|
||||||
memset(errorCurRow, 0, (width + 2) * sizeof(int16_t));
|
|
||||||
memset(errorNextRow, 0, (width + 2) * sizeof(int16_t));
|
|
||||||
} else if (rowY > 0) {
|
|
||||||
// Sequential access - swap buffers
|
// Sequential access - swap buffers
|
||||||
int16_t* temp = errorCurRow;
|
int16_t* temp = errorCurRow;
|
||||||
errorCurRow = errorNextRow;
|
errorCurRow = errorNextRow;
|
||||||
errorNextRow = temp;
|
errorNextRow = temp;
|
||||||
memset(errorNextRow, 0, (width + 2) * sizeof(int16_t));
|
memset(errorNextRow, 0, (width + 2) * sizeof(int16_t));
|
||||||
}
|
}
|
||||||
lastRowY = rowY;
|
|
||||||
}
|
}
|
||||||
|
prevRowY += 1;
|
||||||
|
|
||||||
uint8_t* outPtr = data;
|
uint8_t* outPtr = data;
|
||||||
uint8_t currentOutByte = 0;
|
uint8_t currentOutByte = 0;
|
||||||
@@ -292,7 +287,7 @@ BmpReaderError Bitmap::readRow(uint8_t* data, uint8_t* rowBuffer, int rowY) cons
|
|||||||
color = quantizeFloydSteinberg(lum, currentX, width, errorCurRow, errorNextRow, false);
|
color = quantizeFloydSteinberg(lum, currentX, width, errorCurRow, errorNextRow, false);
|
||||||
} else {
|
} else {
|
||||||
// Simple quantization or noise dithering
|
// Simple quantization or noise dithering
|
||||||
color = quantize(lum, currentX, rowY);
|
color = quantize(lum, currentX, prevRowY);
|
||||||
}
|
}
|
||||||
currentOutByte |= (color << bitShift);
|
currentOutByte |= (color << bitShift);
|
||||||
if (bitShift == 0) {
|
if (bitShift == 0) {
|
||||||
@@ -365,7 +360,7 @@ BmpReaderError Bitmap::rewindToData() const {
|
|||||||
if (USE_FLOYD_STEINBERG && errorCurRow && errorNextRow) {
|
if (USE_FLOYD_STEINBERG && errorCurRow && errorNextRow) {
|
||||||
memset(errorCurRow, 0, (width + 2) * sizeof(int16_t));
|
memset(errorCurRow, 0, (width + 2) * sizeof(int16_t));
|
||||||
memset(errorNextRow, 0, (width + 2) * sizeof(int16_t));
|
memset(errorNextRow, 0, (width + 2) * sizeof(int16_t));
|
||||||
lastRowY = -1;
|
prevRowY = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BmpReaderError::Ok;
|
return BmpReaderError::Ok;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class Bitmap {
|
|||||||
explicit Bitmap(FsFile& file) : file(file) {}
|
explicit Bitmap(FsFile& file) : file(file) {}
|
||||||
~Bitmap();
|
~Bitmap();
|
||||||
BmpReaderError parseHeaders();
|
BmpReaderError parseHeaders();
|
||||||
BmpReaderError readRow(uint8_t* data, uint8_t* rowBuffer, int rowY) const;
|
BmpReaderError readNextRow(uint8_t* data, uint8_t* rowBuffer) const;
|
||||||
BmpReaderError rewindToData() const;
|
BmpReaderError rewindToData() const;
|
||||||
int getWidth() const { return width; }
|
int getWidth() const { return width; }
|
||||||
int getHeight() const { return height; }
|
int getHeight() const { return height; }
|
||||||
@@ -55,5 +55,5 @@ class Bitmap {
|
|||||||
// Floyd-Steinberg dithering state (mutable for const methods)
|
// Floyd-Steinberg dithering state (mutable for const methods)
|
||||||
mutable int16_t* errorCurRow = nullptr;
|
mutable int16_t* errorCurRow = nullptr;
|
||||||
mutable int16_t* errorNextRow = nullptr;
|
mutable int16_t* errorNextRow = nullptr;
|
||||||
mutable int lastRowY = -1; // Track row progression for error propagation
|
mutable int prevRowY = -1; // Track row progression for error propagation
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -152,18 +152,24 @@ void GfxRenderer::drawImage(const uint8_t bitmap[], const int x, const int y, co
|
|||||||
einkDisplay.drawImage(bitmap, rotatedX, rotatedY, width, height);
|
einkDisplay.drawImage(bitmap, rotatedX, rotatedY, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, const int maxWidth,
|
void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, const int maxWidth, const int maxHeight,
|
||||||
const int maxHeight) const {
|
const float cropX, const float cropY) const {
|
||||||
float scale = 1.0f;
|
float scale = 1.0f;
|
||||||
bool isScaled = false;
|
bool isScaled = false;
|
||||||
if (maxWidth > 0 && bitmap.getWidth() > maxWidth) {
|
int cropPixX = std::floor(bitmap.getWidth() * cropX / 2.0f);
|
||||||
scale = static_cast<float>(maxWidth) / static_cast<float>(bitmap.getWidth());
|
int cropPixY = std::floor(bitmap.getHeight() * cropY / 2.0f);
|
||||||
|
Serial.printf("[%lu] [GFX] Cropping %dx%d by %dx%d pix, is %s\n", millis(), bitmap.getWidth(), bitmap.getHeight(),
|
||||||
|
cropPixX, cropPixY, bitmap.isTopDown() ? "top-down" : "bottom-up");
|
||||||
|
|
||||||
|
if (maxWidth > 0 && (1.0f - cropX) * bitmap.getWidth() > maxWidth) {
|
||||||
|
scale = static_cast<float>(maxWidth) / static_cast<float>((1.0f - cropX) * bitmap.getWidth());
|
||||||
isScaled = true;
|
isScaled = true;
|
||||||
}
|
}
|
||||||
if (maxHeight > 0 && bitmap.getHeight() > maxHeight) {
|
if (maxHeight > 0 && (1.0f - cropY) * bitmap.getHeight() > maxHeight) {
|
||||||
scale = std::min(scale, static_cast<float>(maxHeight) / static_cast<float>(bitmap.getHeight()));
|
scale = std::min(scale, static_cast<float>(maxHeight) / static_cast<float>((1.0f - cropY) * bitmap.getHeight()));
|
||||||
isScaled = true;
|
isScaled = true;
|
||||||
}
|
}
|
||||||
|
Serial.printf("[%lu] [GFX] Scaling by %f - %s\n", millis(), scale, isScaled ? "scaled" : "not scaled");
|
||||||
|
|
||||||
// Calculate output row size (2 bits per pixel, packed into bytes)
|
// Calculate output row size (2 bits per pixel, packed into bytes)
|
||||||
// IMPORTANT: Use int, not uint8_t, to avoid overflow for images > 1020 pixels wide
|
// IMPORTANT: Use int, not uint8_t, to avoid overflow for images > 1020 pixels wide
|
||||||
@@ -178,29 +184,36 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int bmpY = 0; bmpY < bitmap.getHeight(); bmpY++) {
|
for (int bmpY = 0; bmpY < (bitmap.getHeight() - cropPixY); bmpY++) {
|
||||||
// The BMP's (0, 0) is the bottom-left corner (if the height is positive, top-left if negative).
|
// The BMP's (0, 0) is the bottom-left corner (if the height is positive, top-left if negative).
|
||||||
// Screen's (0, 0) is the top-left corner.
|
// Screen's (0, 0) is the top-left corner.
|
||||||
int screenY = y + (bitmap.isTopDown() ? bmpY : bitmap.getHeight() - 1 - bmpY);
|
int screenY = -cropPixY + (bitmap.isTopDown() ? bmpY : bitmap.getHeight() - 1 - bmpY);
|
||||||
if (isScaled) {
|
if (isScaled) {
|
||||||
screenY = std::floor(screenY * scale);
|
screenY = std::floor(screenY * scale);
|
||||||
}
|
}
|
||||||
|
screenY += y; // the offset should not be scaled
|
||||||
if (screenY >= getScreenHeight()) {
|
if (screenY >= getScreenHeight()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bitmap.readRow(outputRow, rowBytes, bmpY) != BmpReaderError::Ok) {
|
if (bitmap.readNextRow(outputRow, rowBytes) != BmpReaderError::Ok) {
|
||||||
Serial.printf("[%lu] [GFX] Failed to read row %d from bitmap\n", millis(), bmpY);
|
Serial.printf("[%lu] [GFX] Failed to read row %d from bitmap\n", millis(), bmpY);
|
||||||
free(outputRow);
|
free(outputRow);
|
||||||
free(rowBytes);
|
free(rowBytes);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int bmpX = 0; bmpX < bitmap.getWidth(); bmpX++) {
|
if (bmpY < cropPixY) {
|
||||||
int screenX = x + bmpX;
|
// Skip the row if it's outside the crop area
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int bmpX = cropPixX; bmpX < bitmap.getWidth() - cropPixX; bmpX++) {
|
||||||
|
int screenX = bmpX - cropPixX;
|
||||||
if (isScaled) {
|
if (isScaled) {
|
||||||
screenX = std::floor(screenX * scale);
|
screenX = std::floor(screenX * scale);
|
||||||
}
|
}
|
||||||
|
screenX += x; // the offset should not be scaled
|
||||||
if (screenX >= getScreenWidth()) {
|
if (screenX >= getScreenWidth()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ class GfxRenderer {
|
|||||||
void drawRect(int x, int y, int width, int height, 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 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 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) const;
|
void drawBitmap(const Bitmap& bitmap, int x, int y, int maxWidth, int maxHeight, float cropX = 0,
|
||||||
|
float cropY = 0) const;
|
||||||
|
|
||||||
// Text
|
// Text
|
||||||
int getTextWidth(int fontId, const char* text, EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
|
int getTextWidth(int fontId, const char* text, EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
|
||||||
|
|||||||
@@ -468,7 +468,9 @@ bool JpegToBmpConverter::jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut) {
|
|||||||
// Calculate scale to fit within target dimensions while maintaining aspect ratio
|
// Calculate scale to fit within target dimensions while maintaining aspect ratio
|
||||||
const float scaleToFitWidth = static_cast<float>(TARGET_MAX_WIDTH) / imageInfo.m_width;
|
const float scaleToFitWidth = static_cast<float>(TARGET_MAX_WIDTH) / imageInfo.m_width;
|
||||||
const float scaleToFitHeight = static_cast<float>(TARGET_MAX_HEIGHT) / imageInfo.m_height;
|
const float scaleToFitHeight = static_cast<float>(TARGET_MAX_HEIGHT) / imageInfo.m_height;
|
||||||
const float scale = (scaleToFitWidth < scaleToFitHeight) ? scaleToFitWidth : scaleToFitHeight;
|
// 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;
|
||||||
|
|
||||||
outWidth = static_cast<int>(imageInfo.m_width * scale);
|
outWidth = static_cast<int>(imageInfo.m_width * scale);
|
||||||
outHeight = static_cast<int>(imageInfo.m_height * scale);
|
outHeight = static_cast<int>(imageInfo.m_height * scale);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ CrossPointSettings CrossPointSettings::instance;
|
|||||||
namespace {
|
namespace {
|
||||||
constexpr uint8_t SETTINGS_FILE_VERSION = 1;
|
constexpr uint8_t SETTINGS_FILE_VERSION = 1;
|
||||||
// Increment this when adding new persisted settings fields
|
// Increment this when adding new persisted settings fields
|
||||||
constexpr uint8_t SETTINGS_COUNT = 14;
|
constexpr uint8_t SETTINGS_COUNT = 15;
|
||||||
constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin";
|
constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin";
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ bool CrossPointSettings::saveToFile() const {
|
|||||||
serialization::writePod(outputFile, sleepTimeout);
|
serialization::writePod(outputFile, sleepTimeout);
|
||||||
serialization::writePod(outputFile, refreshFrequency);
|
serialization::writePod(outputFile, refreshFrequency);
|
||||||
serialization::writePod(outputFile, screenMargin);
|
serialization::writePod(outputFile, screenMargin);
|
||||||
|
serialization::writePod(outputFile, sleepScreenCoverMode);
|
||||||
outputFile.close();
|
outputFile.close();
|
||||||
|
|
||||||
Serial.printf("[%lu] [CPS] Settings saved to file\n", millis());
|
Serial.printf("[%lu] [CPS] Settings saved to file\n", millis());
|
||||||
@@ -96,7 +96,8 @@ bool CrossPointSettings::loadFromFile() {
|
|||||||
if (++settingsRead >= fileSettingsCount) break;
|
if (++settingsRead >= fileSettingsCount) break;
|
||||||
serialization::readPod(inputFile, screenMargin);
|
serialization::readPod(inputFile, screenMargin);
|
||||||
if (++settingsRead >= fileSettingsCount) break;
|
if (++settingsRead >= fileSettingsCount) break;
|
||||||
|
serialization::readPod(inputFile, sleepScreenCoverMode);
|
||||||
|
if (++settingsRead >= fileSettingsCount) break;
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
inputFile.close();
|
inputFile.close();
|
||||||
@@ -212,4 +213,4 @@ int CrossPointSettings::getReaderFontId() const {
|
|||||||
return OPENDYSLEXIC_14_FONT_ID;
|
return OPENDYSLEXIC_14_FONT_ID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class CrossPointSettings {
|
|||||||
|
|
||||||
// Should match with SettingsActivity text
|
// Should match with SettingsActivity text
|
||||||
enum SLEEP_SCREEN_MODE { DARK = 0, LIGHT = 1, CUSTOM = 2, COVER = 3, BLANK = 4 };
|
enum SLEEP_SCREEN_MODE { DARK = 0, LIGHT = 1, CUSTOM = 2, COVER = 3, BLANK = 4 };
|
||||||
|
enum SLEEP_SCREEN_COVER_MODE { FIT = 0, CROP = 1 };
|
||||||
|
|
||||||
// Status bar display type enum
|
// Status bar display type enum
|
||||||
enum STATUS_BAR_MODE { NONE = 0, NO_PROGRESS = 1, FULL = 2 };
|
enum STATUS_BAR_MODE { NONE = 0, NO_PROGRESS = 1, FULL = 2 };
|
||||||
@@ -53,6 +54,8 @@ class CrossPointSettings {
|
|||||||
|
|
||||||
// Sleep screen settings
|
// Sleep screen settings
|
||||||
uint8_t sleepScreen = DARK;
|
uint8_t sleepScreen = DARK;
|
||||||
|
// Sleep screen cover mode settings
|
||||||
|
uint8_t sleepScreenCoverMode = FIT;
|
||||||
// Status bar settings
|
// Status bar settings
|
||||||
uint8_t statusBar = FULL;
|
uint8_t statusBar = FULL;
|
||||||
// Text rendering settings
|
// Text rendering settings
|
||||||
|
|||||||
@@ -146,20 +146,36 @@ void SleepActivity::renderBitmapSleepScreen(const Bitmap& bitmap) const {
|
|||||||
int x, y;
|
int x, y;
|
||||||
const auto pageWidth = renderer.getScreenWidth();
|
const auto pageWidth = renderer.getScreenWidth();
|
||||||
const auto pageHeight = renderer.getScreenHeight();
|
const auto pageHeight = renderer.getScreenHeight();
|
||||||
|
float cropX = 0, cropY = 0;
|
||||||
|
|
||||||
|
Serial.printf("[%lu] [SLP] bitmap %d x %d, screen %d x %d\n", millis(), bitmap.getWidth(), bitmap.getHeight(),
|
||||||
|
pageWidth, pageHeight);
|
||||||
if (bitmap.getWidth() > pageWidth || bitmap.getHeight() > pageHeight) {
|
if (bitmap.getWidth() > pageWidth || bitmap.getHeight() > pageHeight) {
|
||||||
// image will scale, make sure placement is right
|
// image will scale, make sure placement is right
|
||||||
const float ratio = static_cast<float>(bitmap.getWidth()) / static_cast<float>(bitmap.getHeight());
|
float ratio = static_cast<float>(bitmap.getWidth()) / static_cast<float>(bitmap.getHeight());
|
||||||
const float screenRatio = static_cast<float>(pageWidth) / static_cast<float>(pageHeight);
|
const float screenRatio = static_cast<float>(pageWidth) / static_cast<float>(pageHeight);
|
||||||
|
|
||||||
|
Serial.printf("[%lu] [SLP] bitmap ratio: %f, screen ratio: %f\n", millis(), ratio, screenRatio);
|
||||||
if (ratio > screenRatio) {
|
if (ratio > screenRatio) {
|
||||||
// image wider than viewport ratio, scaled down image needs to be centered vertically
|
// image wider than viewport ratio, scaled down image needs to be centered vertically
|
||||||
|
if (SETTINGS.sleepScreenCoverMode == CrossPointSettings::SLEEP_SCREEN_COVER_MODE::CROP) {
|
||||||
|
cropX = 1.0f - (screenRatio / ratio);
|
||||||
|
Serial.printf("[%lu] [SLP] Cropping bitmap x: %f\n", millis(), cropX);
|
||||||
|
ratio = (1.0f - cropX) * static_cast<float>(bitmap.getWidth()) / static_cast<float>(bitmap.getHeight());
|
||||||
|
}
|
||||||
x = 0;
|
x = 0;
|
||||||
y = (pageHeight - pageWidth / ratio) / 2;
|
y = std::round((static_cast<float>(pageHeight) - static_cast<float>(pageWidth) / ratio) / 2);
|
||||||
|
Serial.printf("[%lu] [SLP] Centering with ratio %f to y=%d\n", millis(), ratio, y);
|
||||||
} else {
|
} else {
|
||||||
// image taller than viewport ratio, scaled down image needs to be centered horizontally
|
// image taller than viewport ratio, scaled down image needs to be centered horizontally
|
||||||
x = (pageWidth - pageHeight * ratio) / 2;
|
if (SETTINGS.sleepScreenCoverMode == CrossPointSettings::SLEEP_SCREEN_COVER_MODE::CROP) {
|
||||||
|
cropY = 1.0f - (ratio / screenRatio);
|
||||||
|
Serial.printf("[%lu] [SLP] Cropping bitmap y: %f\n", millis(), cropY);
|
||||||
|
ratio = static_cast<float>(bitmap.getWidth()) / ((1.0f - cropY) * static_cast<float>(bitmap.getHeight()));
|
||||||
|
}
|
||||||
|
x = std::round((pageWidth - pageHeight * ratio) / 2);
|
||||||
y = 0;
|
y = 0;
|
||||||
|
Serial.printf("[%lu] [SLP] Centering with ratio %f to x=%d\n", millis(), ratio, x);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// center the image
|
// center the image
|
||||||
@@ -167,21 +183,22 @@ void SleepActivity::renderBitmapSleepScreen(const Bitmap& bitmap) const {
|
|||||||
y = (pageHeight - bitmap.getHeight()) / 2;
|
y = (pageHeight - bitmap.getHeight()) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Serial.printf("[%lu] [SLP] drawing to %d x %d\n", millis(), x, y);
|
||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight);
|
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY);
|
||||||
renderer.displayBuffer(EInkDisplay::HALF_REFRESH);
|
renderer.displayBuffer(EInkDisplay::HALF_REFRESH);
|
||||||
|
|
||||||
if (bitmap.hasGreyscale()) {
|
if (bitmap.hasGreyscale()) {
|
||||||
bitmap.rewindToData();
|
bitmap.rewindToData();
|
||||||
renderer.clearScreen(0x00);
|
renderer.clearScreen(0x00);
|
||||||
renderer.setRenderMode(GfxRenderer::GRAYSCALE_LSB);
|
renderer.setRenderMode(GfxRenderer::GRAYSCALE_LSB);
|
||||||
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight);
|
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY);
|
||||||
renderer.copyGrayscaleLsbBuffers();
|
renderer.copyGrayscaleLsbBuffers();
|
||||||
|
|
||||||
bitmap.rewindToData();
|
bitmap.rewindToData();
|
||||||
renderer.clearScreen(0x00);
|
renderer.clearScreen(0x00);
|
||||||
renderer.setRenderMode(GfxRenderer::GRAYSCALE_MSB);
|
renderer.setRenderMode(GfxRenderer::GRAYSCALE_MSB);
|
||||||
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight);
|
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY);
|
||||||
renderer.copyGrayscaleMsbBuffers();
|
renderer.copyGrayscaleMsbBuffers();
|
||||||
|
|
||||||
renderer.displayGrayBuffer();
|
renderer.displayGrayBuffer();
|
||||||
|
|||||||
@@ -10,10 +10,11 @@
|
|||||||
|
|
||||||
// Define the static settings list
|
// Define the static settings list
|
||||||
namespace {
|
namespace {
|
||||||
constexpr int settingsCount = 15;
|
constexpr int settingsCount = 16;
|
||||||
const SettingInfo settingsList[settingsCount] = {
|
const SettingInfo settingsList[settingsCount] = {
|
||||||
// Should match with SLEEP_SCREEN_MODE
|
// Should match with SLEEP_SCREEN_MODE
|
||||||
SettingInfo::Enum("Sleep Screen", &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover", "None"}),
|
SettingInfo::Enum("Sleep Screen", &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover", "None"}),
|
||||||
|
SettingInfo::Enum("Sleep Screen Cover Mode", &CrossPointSettings::sleepScreenCoverMode, {"Fit", "Crop"}),
|
||||||
SettingInfo::Enum("Status Bar", &CrossPointSettings::statusBar, {"None", "No Progress", "Full"}),
|
SettingInfo::Enum("Status Bar", &CrossPointSettings::statusBar, {"None", "No Progress", "Full"}),
|
||||||
SettingInfo::Toggle("Extra Paragraph Spacing", &CrossPointSettings::extraParagraphSpacing),
|
SettingInfo::Toggle("Extra Paragraph Spacing", &CrossPointSettings::extraParagraphSpacing),
|
||||||
SettingInfo::Toggle("Short Power Button Click", &CrossPointSettings::shortPwrBtn),
|
SettingInfo::Toggle("Short Power Button Click", &CrossPointSettings::shortPwrBtn),
|
||||||
|
|||||||
Reference in New Issue
Block a user