You've already forked crosspoint-reader
mirror of
https://github.com/crosspoint-reader/crosspoint-reader.git
synced 2026-04-29 10:26:52 -07:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 77a964e83a | |||
| e20f4550ce |
@@ -12,7 +12,7 @@ Xteink firmware. It aims to match or improve upon the standard EPUB reading expe
|
||||
|
||||
E-paper devices are fantastic for reading, but most commercially available readers are closed systems with limited
|
||||
customisation. The **Xteink X4** is an affordable, e-paper device, however the official firmware remains closed.
|
||||
CrossPoint exists partly as a fun side-project and partly to open up the ecosystem and truly unlock the device's
|
||||
CrossPoint exists partly as a fun side-project and partly to open up the ecosystem and truely unlock the device's
|
||||
potential.
|
||||
|
||||
CrossPoint Reader aims to:
|
||||
@@ -68,24 +68,6 @@ back to the other partition using the "Swap boot partition" button here https://
|
||||
To revert back to the official firmware, you can flash the latest official firmware from https://xteink.dve.al/, or swap
|
||||
back to the other partition using the "Swap boot partition" button here https://xteink.dve.al/debug.
|
||||
|
||||
### Command line (specific firmware version)
|
||||
|
||||
1. Install [`esptool`](https://github.com/espressif/esptool) :
|
||||
```bash
|
||||
pip install esptool
|
||||
```
|
||||
2. Download the `firmware.bin` file from the release of your choice via the [releases page](https://github.com/crosspoint-reader/crosspoint-reader/releases)
|
||||
3. Connect your Xteink X4 to your computer via USB-C.
|
||||
4. Note the device location. On Linux, run `dmesg` after connecting. On MacOS, run :
|
||||
```bash
|
||||
log stream --predicate 'subsystem == "com.apple.iokit"' --info
|
||||
```
|
||||
5. Flash the firmware :
|
||||
```bash
|
||||
esptool.py --chip esp32c3 --port /dev/ttyACM0 --baud 921600 write_flash 0x10000 /path/to/firmware.bin
|
||||
```
|
||||
Change `/dev/ttyACM0` to the device for your system.
|
||||
|
||||
### Manual
|
||||
|
||||
See [Development](#development) below.
|
||||
@@ -179,7 +161,7 @@ If you are new to the codebase, start with the [contributing docs](./docs/contri
|
||||
If you're looking for a way to help out, take a look at the [ideas discussion board](https://github.com/crosspoint-reader/crosspoint-reader/discussions/categories/ideas).
|
||||
If there's something there you'd like to work on, leave a comment so that we can avoid duplicated effort.
|
||||
|
||||
Everyone here is a volunteer, so please be respectful and patient. For more details on our governance and community
|
||||
Everyone here is a volunteer, so please be respectful and patient. For more details on our goverance and community
|
||||
principles, please see [GOVERNANCE.md](GOVERNANCE.md).
|
||||
|
||||
### To submit a contribution:
|
||||
|
||||
@@ -27,12 +27,6 @@ usability over "swiss-army-knife" functionality.
|
||||
* **Language Support:** E.g. Support for multiple languages both in the reader and in the interfaces.
|
||||
* **Reference Tools:** E.g. Local dictionary lookup. Providing quick, offline definitions to enhance comprehension
|
||||
without breaking focus.
|
||||
* **Clock Display (device dependent):**
|
||||
|
||||
| Device | Scope |
|
||||
| -- | -- |
|
||||
| X3 | The X3 uses a dedicated DS3231 RTC, which maintains accurate time across sleep cycles and can be treated as a reliable wall clock. |
|
||||
| X4 | The X4 relies on the ESP32-C3's internal RTC, which drifts significantly during deep sleep. NTP sync could correct this, with an appropriate user experience around connecting to the internet on wake or on demand. This causes some tension with the **Active Connectivity** section below, so please open a discussion about this UX if it's a feature you would find useful. |
|
||||
|
||||
### Out-of-Scope
|
||||
|
||||
@@ -49,6 +43,8 @@ usability over "swiss-army-knife" functionality.
|
||||
|
||||
*These features align with CrossPoint's goals but are impractical on the current hardware or produce poor UX.*
|
||||
|
||||
* **Clock Display:** The ESP32-C3's RTC drifts significantly during deep sleep; making the clock untrustworthy after any sleep cycle. NTP sync could help, but CrossPoint doesn't connect to the internet on every boot.
|
||||
|
||||
* **PDF Rendering:** PDFs are fixed-layout documents, so rendering them requires displaying pages as images rather than reflowable text — resulting in constant panning and zooming that makes for a poor reading experience on e-ink.
|
||||
|
||||
## 3. Idea Evaluation
|
||||
|
||||
+1
-2
@@ -336,8 +336,7 @@ To use custom sleep images, set the sleep screen mode to **Custom** or **Cover +
|
||||
> [!TIP]
|
||||
> For best results:
|
||||
> - Use uncompressed BMP files with 24-bit color depth
|
||||
> - X4: Use a resolution of 480x800 pixels to match the device's screen resolution.
|
||||
> - X3: Use a resolution of 528x792 pixels to match the device's screen resolution.
|
||||
> - Use a resolution of 480x800 pixels to match the device's screen resolution.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -97,7 +97,6 @@ $exclude = @(
|
||||
'lib\Epub\Epub\hyphenation\generated'
|
||||
'lib\uzlib'
|
||||
'.pio'
|
||||
'.venv'
|
||||
)
|
||||
|
||||
function Test-Excluded($fullPath) {
|
||||
|
||||
@@ -26,7 +26,6 @@ If you'd like to add your name to this list, please open a PR adding yourself an
|
||||
## Italian
|
||||
- [andreaturchet](https://github.com/andreaturchet)
|
||||
- [fragolinux](https://github.com/fragolinux)
|
||||
- [alan0ford](https://github.com/alan0ford)
|
||||
|
||||
## Russian
|
||||
- [madebyKir](https://github.com/madebyKir)
|
||||
|
||||
+19
-24
@@ -15,11 +15,11 @@ void EpdFont::getTextBounds(const char* string, const int startX, const int star
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t cursorXFP = fp4::fromPixel(startX); // 12.4 fixed-point accumulator
|
||||
int lastBaseX = startX;
|
||||
int lastBaseLeft = 0;
|
||||
int lastBaseWidth = 0;
|
||||
int lastBaseAdvanceFP = 0; // 12.4 fixed-point
|
||||
int lastBaseTop = 0;
|
||||
int32_t prevAdvanceFP = 0; // 12.4 fixed-point: prev glyph's advance + next kern for snap
|
||||
constexpr int MIN_COMBINING_GAP_PX = 1;
|
||||
uint32_t cp;
|
||||
uint32_t prevCp = 0;
|
||||
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&string)))) {
|
||||
@@ -31,29 +31,24 @@ void EpdFont::getTextBounds(const char* string, const int startX, const int star
|
||||
|
||||
const EpdGlyph* glyph = getGlyph(cp);
|
||||
if (!glyph) {
|
||||
// Keep cursor movement stable when a base glyph is missing, but don't attach subsequent
|
||||
// combining marks to stale base metrics.
|
||||
if (!isCombining) {
|
||||
lastBaseX += fp4::toPixel(prevAdvanceFP); // flush pending advance before resetting
|
||||
prevCp = 0;
|
||||
prevAdvanceFP = 0;
|
||||
lastBaseLeft = 0;
|
||||
lastBaseWidth = 0;
|
||||
lastBaseTop = 0;
|
||||
}
|
||||
prevCp = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
const int raiseBy = isCombining ? combiningMark::raiseAboveBase(glyph->top, glyph->height, lastBaseTop) : 0;
|
||||
|
||||
if (!isCombining && prevCp != 0) {
|
||||
const auto kernFP = getKerning(prevCp, cp); // 4.4 fixed-point kern
|
||||
lastBaseX += fp4::toPixel(prevAdvanceFP + kernFP);
|
||||
int raiseBy = 0;
|
||||
if (isCombining) {
|
||||
const int currentGap = glyph->top - glyph->height - lastBaseTop;
|
||||
if (currentGap < MIN_COMBINING_GAP_PX) {
|
||||
raiseBy = MIN_COMBINING_GAP_PX - currentGap;
|
||||
}
|
||||
}
|
||||
|
||||
const int glyphBaseX =
|
||||
isCombining ? combiningMark::centerOver(lastBaseX, lastBaseLeft, lastBaseWidth, glyph->left, glyph->width)
|
||||
: lastBaseX;
|
||||
if (!isCombining && prevCp != 0) {
|
||||
cursorXFP += getKerning(prevCp, cp); // 4.4 fixed-point kern
|
||||
}
|
||||
|
||||
const int cursorXPixels = fp4::toPixel(cursorXFP); // snap 12.4 fixed-point to nearest pixel
|
||||
const int glyphBaseX = isCombining ? (lastBaseX + fp4::toPixel(lastBaseAdvanceFP / 2)) : cursorXPixels;
|
||||
const int glyphBaseY = startY - raiseBy;
|
||||
|
||||
*minX = std::min(*minX, glyphBaseX + glyph->left);
|
||||
@@ -62,10 +57,10 @@ void EpdFont::getTextBounds(const char* string, const int startX, const int star
|
||||
*maxY = std::max(*maxY, glyphBaseY + glyph->top);
|
||||
|
||||
if (!isCombining) {
|
||||
lastBaseLeft = glyph->left;
|
||||
lastBaseWidth = glyph->width;
|
||||
lastBaseX = cursorXPixels;
|
||||
lastBaseAdvanceFP = glyph->advanceX; // 12.4 fixed-point
|
||||
lastBaseTop = glyph->top;
|
||||
prevAdvanceFP = glyph->advanceX; // 12.4 fixed-point
|
||||
cursorXFP += glyph->advanceX; // 12.4 fixed-point advance
|
||||
prevCp = cp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,10 @@
|
||||
/// Font metrics use "fixed-point 4" (4 fractional bits, i.e. 1/16-pixel
|
||||
/// resolution). Both the 12.4 glyph advances (uint16_t) and the 4.4 kern
|
||||
/// values (int8_t) share the same 4 fractional bits, so they can be freely
|
||||
/// added before snapping to whole pixels.
|
||||
///
|
||||
/// Rendering and measurement use "differential rounding": each glyph step
|
||||
/// (previous advance + current kern) is combined in fixed-point and snapped
|
||||
/// to a pixel as one unit. This guarantees identical character pairs always
|
||||
/// produce the same pixel spacing, regardless of position on the line.
|
||||
/// added into a single int32_t accumulator during text layout. The
|
||||
/// accumulator is snapped to the nearest whole pixel only at render time,
|
||||
/// which avoids the per-character rounding errors that plagued integer-only
|
||||
/// layout.
|
||||
///
|
||||
/// The helpers below eliminate the raw bit-shifts that would otherwise be
|
||||
/// scattered across every layout / measurement call site.
|
||||
@@ -30,37 +28,6 @@ constexpr int toPixel(int32_t fp) { return static_cast<int>((fp + HALF) >> FRAC_
|
||||
constexpr float toFloat(int32_t fp) { return fp / static_cast<float>(1 << FRAC_BITS); }
|
||||
} // namespace fp4
|
||||
|
||||
/// Helpers for positioning Unicode combining marks (U+0300 ff.) over a
|
||||
/// preceding base glyph without GPOS anchor tables.
|
||||
namespace combiningMark {
|
||||
|
||||
constexpr int MIN_GAP_PX = 1;
|
||||
|
||||
/// Compute the cursor-X at which to render a combining mark so its bitmap
|
||||
/// is visually centered over the base glyph's bitmap.
|
||||
constexpr int centerOver(int baseCursorPos, int baseLeft, int baseWidth, int markLeft, int markWidth) {
|
||||
return baseCursorPos + baseLeft + baseWidth / 2 - markWidth / 2 - markLeft;
|
||||
}
|
||||
|
||||
/// Rotated-90CW variant of centerOver. In the rotated coordinate system
|
||||
/// renderCharImpl uses (cursorY - left) instead of (cursorX + left), so
|
||||
/// every left/width term inverts sign.
|
||||
constexpr int centerOverRotated90CW(int baseCursorPos, int baseLeft, int baseWidth, int markLeft, int markWidth) {
|
||||
return baseCursorPos - baseLeft - baseWidth / 2 + markWidth / 2 + markLeft;
|
||||
}
|
||||
|
||||
/// For combining marks that sit entirely above the baseline, compute how many
|
||||
/// pixels to raise the mark so there is at least MIN_GAP_PX between its bottom
|
||||
/// edge and the top of the base glyph. Returns 0 for marks that extend to or
|
||||
/// below the baseline (e.g. cedilla, dot-below, ogonek).
|
||||
constexpr int raiseAboveBase(int markTop, int markHeight, int baseTop) {
|
||||
if (markTop - markHeight <= 0) return 0;
|
||||
const int gap = markTop - markHeight - baseTop;
|
||||
return (gap < MIN_GAP_PX) ? (MIN_GAP_PX - gap) : 0;
|
||||
}
|
||||
|
||||
} // namespace combiningMark
|
||||
|
||||
/// Fixed-point conventions used by EpdGlyph and EpdFontData:
|
||||
/// advanceX: 12.4 unsigned fixed-point in uint16_t (use fp4::toPixel)
|
||||
/// kernMatrix: 4.4 signed fixed-point in int8_t (use fp4::toPixel)
|
||||
|
||||
+3278
-3331
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
+3602
-3653
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
+3945
-3996
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
+4409
-4462
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user