Compare commits
248 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17fedd2a69 | ||
|
|
768c2f8eed | ||
|
|
216dbc8ee3 | ||
|
|
ee987f07ff | ||
|
|
23ecc52261 | ||
|
|
edaf8fff9d | ||
|
|
c8683340ab | ||
|
|
5a9ee19eb8 | ||
|
|
c49a819939 | ||
|
|
bf87a7dc60 | ||
|
|
2cf799f45b | ||
|
|
db659f3ea2 | ||
|
|
78d6e5931c | ||
|
|
dac11c3fdd | ||
|
|
d403044f76 | ||
|
|
f67c544e16 | ||
|
|
e5c0ddc9fa | ||
|
|
b1dcb7733b | ||
|
|
0d82b03981 | ||
|
|
5a97334ace | ||
|
|
4dd73a211a | ||
|
|
634f6279cb | ||
|
|
11b2a59233 | ||
|
|
12c20bb09e | ||
|
|
6b7065b986 | ||
|
|
f4df513bf3 | ||
|
|
f935b59a41 | ||
|
|
da4d3b5ea5 | ||
|
|
172916afd4 | ||
|
|
ebcd813ff6 | ||
|
|
712c566664 | ||
|
|
5894ae5afe | ||
|
|
8c1c80787a | ||
|
|
140fcb9db5 | ||
|
|
e0b6b9b28a | ||
|
|
83315b6179 | ||
|
|
8e0d2bece2 | ||
|
|
4848a77e1b | ||
|
|
49190cca6d | ||
|
|
e9c2fe1c87 | ||
|
|
dd1741bf0b | ||
|
|
51c5c3c0aa | ||
|
|
5e24895f6d | ||
|
|
e2ca0e94ca | ||
|
|
a4b9a43ca1 | ||
|
|
c73fca26f5 | ||
|
|
dfd7b615dc | ||
|
|
aca6dceaa8 | ||
|
|
6ca75c4653 | ||
|
|
1b9c8ab545 | ||
|
|
bf6cf83577 | ||
|
|
3a761b18af | ||
|
|
13f0ebed96 | ||
|
|
0bc0baa966 | ||
|
|
5d369df6be | ||
|
|
b8ebcf5867 | ||
|
|
e858ebbe88 | ||
|
|
9224bc3f8c | ||
|
|
67a679ab41 | ||
|
|
7a53342f9d | ||
|
|
3ce11f14ce | ||
|
|
47ef92e8fd | ||
|
|
e3d6e32609 | ||
|
|
d399afb53d | ||
|
|
838993259d | ||
|
|
cc74039cab | ||
|
|
87d6c032a5 | ||
|
|
c9b5462370 | ||
|
|
e548bfc0e1 | ||
|
|
73c30748d8 | ||
|
|
6d68466891 | ||
|
|
8824c87490 | ||
|
|
5fef99c641 | ||
|
|
7a792a5384 | ||
|
|
f69cddf2cc | ||
|
|
7185e5d287 | ||
|
|
12940cc546 | ||
|
|
21277e03eb | ||
|
|
4eef2b5793 | ||
|
|
5a55fa1c6e | ||
|
|
c98ba142e8 | ||
|
|
c1c94c0112 | ||
|
|
eb84bcee7c | ||
|
|
d45f355e87 | ||
|
|
56ec3dfb6d | ||
|
|
e517945aaa | ||
|
|
489220832f | ||
|
|
3ee10b31ab | ||
|
|
a946c83a07 | ||
|
|
847786e342 | ||
|
|
c2fb8ce55d | ||
|
|
ed05554d74 | ||
|
|
9a9dc044ce | ||
|
|
1c027ce2cd | ||
|
|
49f97b69ca | ||
|
|
14643d0225 | ||
|
|
fecd1849b9 | ||
|
|
2040e088e7 | ||
|
|
65d23910a3 | ||
|
|
52995fa722 | ||
|
|
d4f8eda154 | ||
|
|
33b8fa0e19 | ||
|
|
16c760b2d2 | ||
|
|
8f3df7e10e | ||
|
|
0165fab581 | ||
|
|
66b100c6ca | ||
|
|
41bda43899 | ||
|
|
82f21f3c1d | ||
|
|
a9242fe61f | ||
|
|
88d0d90471 | ||
|
|
97c4871316 | ||
|
|
66811bf50b | ||
|
|
87287012ba | ||
|
|
d4ae108d9b | ||
|
|
7240cd52a9 | ||
|
|
0bae3bbf64 | ||
|
|
2b12a65011 | ||
|
|
46fa186b82 | ||
|
|
0cc2c64df2 | ||
|
|
1f956e972b | ||
|
|
9c573e6f7f | ||
|
|
0edb2baced | ||
|
|
b792b792bf | ||
|
|
afe9672156 | ||
|
|
9f95b31de5 | ||
|
|
c76507c937 | ||
|
|
881aa2e005 | ||
|
|
14972b34cb | ||
|
|
c8f4870d7c | ||
|
|
5fdf23f1d2 | ||
|
|
2fb417ee90 | ||
|
|
c8f6160fbc | ||
|
|
8e4484cd22 | ||
|
|
0332e1103a | ||
|
|
5790d6f5dc | ||
|
|
062d69dc2a | ||
|
|
5e9626eb2a | ||
|
|
00e83af4e8 | ||
|
|
39080c0e51 | ||
|
|
9e59a5106b | ||
|
|
a922e553ed | ||
|
|
04ad4e5aa4 | ||
|
|
6e9ba1006a | ||
|
|
40f9ed485c | ||
|
|
b82e044ac3 | ||
|
|
026733a4fe | ||
|
|
57b075ec97 | ||
|
|
648c688642 | ||
|
|
06065dfd8b | ||
|
|
93226c9fbb | ||
|
|
941643cf97 | ||
|
|
9bba41ed96 | ||
|
|
34cf5f0636 | ||
|
|
f2ca65d752 | ||
|
|
6a8971fc20 | ||
|
|
e2cba5be83 | ||
|
|
52a0b5bbe9 | ||
|
|
3abcd0d05d | ||
|
|
03f0ce04cc | ||
|
|
be1b5bad21 | ||
|
|
3dd52f30fa | ||
|
|
e43fec79be | ||
|
|
bf7bffd506 | ||
|
|
9f31f80c80 | ||
|
|
fb5fc32c5d | ||
|
|
d4bd119950 | ||
|
|
85d76da967 | ||
|
|
e4ac90f5c1 | ||
|
|
278b056bd0 | ||
|
|
b01eb50325 | ||
|
|
1bfe694807 | ||
|
|
7b32a87596 | ||
|
|
071ccb9d1b | ||
|
|
d7f4bd54f5 | ||
|
|
2437943c94 | ||
|
|
140d8749a6 | ||
|
|
534504cf7a | ||
|
|
b1763821b5 | ||
|
|
c0b83b626e | ||
|
|
f8c0b1acea | ||
|
|
f9b604f04e | ||
|
|
3dc5f6fec4 | ||
|
|
41c93e4eba | ||
|
|
1c33162368 | ||
|
|
27d42fbef3 | ||
|
|
dd280bdc97 | ||
|
|
bf031fd999 | ||
|
|
02350c6a9f | ||
|
|
9023b262a1 | ||
|
|
eabd149371 | ||
|
|
838246d147 | ||
|
|
f96b6ab29c | ||
|
|
e3d0201365 | ||
|
|
286b47f489 | ||
|
|
aff4dc6628 | ||
|
|
98a39374e8 | ||
|
|
e8c0fb42d4 | ||
|
|
b77af16caa | ||
|
|
e3c1e28b8f | ||
|
|
dc7544d944 | ||
|
|
504c7b307d | ||
|
|
b6bc1f7ed3 | ||
|
|
ea0abaf351 | ||
|
|
2771579007 | ||
|
|
27035b2b91 | ||
|
|
1107590b56 | ||
|
|
66ddb52103 | ||
|
|
9f4f71fabe | ||
|
|
d23020e268 | ||
|
|
f4491875ab | ||
|
|
6fe28da41b | ||
|
|
689b539c6b | ||
|
|
ce37c80c2d | ||
|
|
b39ce22e54 | ||
|
|
77c655fcf5 | ||
|
|
246afae6ef | ||
|
|
fcfa10bb1f | ||
|
|
febf79a98a | ||
|
|
424104f8ff | ||
|
|
955c78de64 | ||
|
|
958508eb6b | ||
|
|
6aa5d41a42 | ||
|
|
2a27c6d068 | ||
|
|
b73ae7fe74 | ||
|
|
f264efdb12 | ||
|
|
0d32d21d75 | ||
|
|
9b4dfbd180 | ||
|
|
926c786705 | ||
|
|
299623927e | ||
|
|
9a3bb81337 | ||
|
|
73d1839ddd | ||
|
|
cc86533e86 | ||
|
|
bf3f270067 | ||
|
|
cfe838e03b | ||
|
|
7484fe478c | ||
|
|
d41d539435 | ||
|
|
cf6fec78dc | ||
|
|
10d76dde12 | ||
|
|
7b5a63d220 | ||
|
|
c1d5f5d562 | ||
|
|
adfeee063f | ||
|
|
2d3928ed81 | ||
|
|
48249fbd1e | ||
|
|
1a53dccebd | ||
|
|
3e28724b62 | ||
|
|
d86b3fe134 | ||
|
|
1a3d6b125d | ||
|
|
b2020f5512 |
15
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,9 +1,18 @@
|
|||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
* **What is the goal of this PR?** (e.g., Fixes a bug in the user authentication module, Implements the new feature for
|
* **What is the goal of this PR?** (e.g., Implements the new feature for file uploading.)
|
||||||
file uploading.)
|
|
||||||
* **What changes are included?**
|
* **What changes are included?**
|
||||||
|
|
||||||
## Additional Context
|
## Additional Context
|
||||||
|
|
||||||
* Add any other information that might be helpful for the reviewer (e.g., performance implications, potential risks, specific areas to focus on).
|
* Add any other information that might be helpful for the reviewer (e.g., performance implications, potential risks,
|
||||||
|
specific areas to focus on).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### AI Usage
|
||||||
|
|
||||||
|
While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it
|
||||||
|
helps set the right context for reviewers.
|
||||||
|
|
||||||
|
Did you use AI tools to help write this code? _**< YES | PARTIALLY | NO >**_
|
||||||
|
|||||||
104
.github/workflows/ci.yml
vendored
@ -1,30 +1,25 @@
|
|||||||
name: CI
|
name: CI (build)
|
||||||
'on':
|
|
||||||
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [master]
|
branches: [master]
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
permissions:
|
||||||
build:
|
contents: read
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
clang-format:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- uses: actions/cache@v5
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.cache/pip
|
|
||||||
~/.platformio/.cache
|
|
||||||
key: ${{ runner.os }}-pio
|
|
||||||
- uses: actions/setup-python@v6
|
- uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: '3.14'
|
python-version: '3.14'
|
||||||
|
|
||||||
- name: Install PlatformIO Core
|
|
||||||
run: pip install --upgrade platformio
|
|
||||||
|
|
||||||
- name: Install clang-format-21
|
- name: Install clang-format-21
|
||||||
run: |
|
run: |
|
||||||
wget https://apt.llvm.org/llvm.sh
|
wget https://apt.llvm.org/llvm.sh
|
||||||
@ -33,11 +28,82 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y clang-format-21
|
sudo apt-get install -y clang-format-21
|
||||||
|
|
||||||
- name: Run cppcheck
|
|
||||||
run: pio check --fail-on-defect medium --fail-on-defect high
|
|
||||||
|
|
||||||
- name: Run clang-format
|
- name: Run clang-format
|
||||||
run: PATH="/usr/lib/llvm-21/bin:$PATH" ./bin/clang-format-fix && git diff --exit-code || (echo "Please run 'bin/clang-format-fix' to fix formatting issues" && exit 1)
|
run: |
|
||||||
|
PATH="/usr/lib/llvm-21/bin:$PATH" ./bin/clang-format-fix
|
||||||
|
git diff --exit-code || (echo "Please run 'bin/clang-format-fix' to fix formatting issues" && exit 1)
|
||||||
|
|
||||||
|
cppcheck:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v6
|
||||||
|
with:
|
||||||
|
python-version: '3.14'
|
||||||
|
|
||||||
|
- name: Install PlatformIO Core
|
||||||
|
run: pip install --upgrade platformio
|
||||||
|
|
||||||
|
- name: Run cppcheck
|
||||||
|
run: pio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high
|
||||||
|
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v6
|
||||||
|
with:
|
||||||
|
python-version: '3.14'
|
||||||
|
|
||||||
|
- name: Install PlatformIO Core
|
||||||
|
run: pip install --upgrade platformio
|
||||||
|
|
||||||
- name: Build CrossPoint
|
- name: Build CrossPoint
|
||||||
run: pio run
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
pio run | tee pio.log
|
||||||
|
|
||||||
|
- name: Extract firmware stats
|
||||||
|
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
ram_line="$(grep -E "RAM:\\s" -m1 pio.log || true)"
|
||||||
|
flash_line="$(grep -E "Flash:\\s" -m1 pio.log || true)"
|
||||||
|
echo "ram_line=${ram_line}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "flash_line=${flash_line}" >> "$GITHUB_OUTPUT"
|
||||||
|
{
|
||||||
|
echo "## Firmware build stats"
|
||||||
|
if [ -n "$ram_line" ]; then echo "- ${ram_line}"; else echo "- RAM: not found"; fi
|
||||||
|
if [ -n "$flash_line" ]; then echo "- ${flash_line}"; else echo "- Flash: not found"; fi
|
||||||
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
|
||||||
|
- name: Upload firmware.bin artifact
|
||||||
|
uses: actions/upload-artifact@v6
|
||||||
|
with:
|
||||||
|
name: firmware.bin
|
||||||
|
path: .pio/build/default/firmware.bin
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
# This job is used as the PR required actions check, allows for changes to other steps in the future without breaking
|
||||||
|
# PR requirements.
|
||||||
|
test-status:
|
||||||
|
name: Test Status
|
||||||
|
needs:
|
||||||
|
- build
|
||||||
|
- clang-format
|
||||||
|
- cppcheck
|
||||||
|
if: always()
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Fail because needed jobs failed
|
||||||
|
# Fail if any job failed or was cancelled (skipped jobs are ok)
|
||||||
|
if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
|
||||||
|
run: exit 1
|
||||||
|
- name: Success
|
||||||
|
run: exit 0
|
||||||
|
|||||||
26
.github/workflows/pr-formatting-check.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
name: "PR Formatting"
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
- reopened
|
||||||
|
- edited
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
statuses: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
title-check:
|
||||||
|
name: Title Check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Harden Runner
|
||||||
|
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
|
||||||
|
- name: Check PR Title
|
||||||
|
uses: amannn/action-semantic-pull-request@v6
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
3
.github/workflows/release.yml
vendored
@ -7,17 +7,18 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build-release:
|
build-release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- uses: actions/cache@v5
|
- uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cache/pip
|
~/.cache/pip
|
||||||
~/.platformio/.cache
|
~/.platformio/.cache
|
||||||
key: ${{ runner.os }}-pio
|
key: ${{ runner.os }}-pio
|
||||||
|
|
||||||
- uses: actions/setup-python@v6
|
- uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: '3.14'
|
python-version: '3.14'
|
||||||
|
|||||||
6
.gitignore
vendored
@ -3,3 +3,9 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
.vscode
|
.vscode
|
||||||
lib/EpdFont/fontsrc
|
lib/EpdFont/fontsrc
|
||||||
|
*.generated.h
|
||||||
|
.vs
|
||||||
|
build
|
||||||
|
**/__pycache__/
|
||||||
|
/compile_commands.json
|
||||||
|
/.cache
|
||||||
|
|||||||
38
GOVERNANCE.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Project Governance & Community Principles
|
||||||
|
|
||||||
|
CrossPoint Reader is a community-driven, open-source project. Our goal is to provide a high-quality, open-source
|
||||||
|
firmware alternative for the Xteink X4 hardware. To keep this project productive and welcoming as we grow, we ask all
|
||||||
|
contributors to follow these principles.
|
||||||
|
|
||||||
|
### 1. The "Human First" Rule
|
||||||
|
Technical discussions can get heated, but they should never be personal.
|
||||||
|
- **Assume good intent:** We are all volunteers working on this in our free time. If a comment seems abrasive, assume
|
||||||
|
it’s a language barrier or a misunderstanding before taking offense.
|
||||||
|
- **Focus on the code, not the person:** Critique the implementation, the performance, or the UX. Never the intelligence
|
||||||
|
or character of the contributor.
|
||||||
|
- **Inflammatory language:** Personal attacks, trolling, or exclusionary language (based on race, gender, background,
|
||||||
|
etc.) are not welcome here and will be moderated.
|
||||||
|
|
||||||
|
### 2. A "Do-ocracy" with Guidance
|
||||||
|
CrossPoint thrives because people step up to build what they want to see.
|
||||||
|
- If you want a feature, the best way to get it is to start an
|
||||||
|
[Idea Discussion](https://github.com/crosspoint-reader/crosspoint-reader/discussions/categories/ideas) or open a PR.
|
||||||
|
- If you want to report a bug, check for duplicates and create an
|
||||||
|
[Issue](https://github.com/crosspoint-reader/crosspoint-reader/issues).
|
||||||
|
- While we encourage experimentation, the maintainers reserve the right to guide the project’s technical direction to
|
||||||
|
ensure stability on the ESP32-C3’s constrained hardware.
|
||||||
|
- For more guidance on the scope of the project, see the [SCOPE.md](SCOPE.md) document.
|
||||||
|
|
||||||
|
### 3. Transparent Communication
|
||||||
|
To keep the project healthy, we keep our "work" in the open.
|
||||||
|
- **Public by Default:** All technical decisions and project management discussions happen in GitHub Issues, Pull
|
||||||
|
Requests, or the public Discussions tab.
|
||||||
|
- **Clarity in Writing:** Because we have a global community with different levels of English proficiency, please be as
|
||||||
|
explicit and clear as possible in your PR descriptions and bug reports.
|
||||||
|
|
||||||
|
### 4. Moderation & Safety
|
||||||
|
The maintainers are responsible for keeping the community a safe place to contribute.
|
||||||
|
- We reserve the right to hide comments, lock threads, or block users who repeatedly violate these principles or engage
|
||||||
|
in harassment.
|
||||||
|
- **Reporting:** If you feel you are being harassed or see behavior that is damaging the community, please reach out
|
||||||
|
privately to @daveallie.
|
||||||
84
README.md
@ -23,18 +23,29 @@ CrossPoint Reader aims to:
|
|||||||
|
|
||||||
This project is **not affiliated with Xteink**; it's built as a community project.
|
This project is **not affiliated with Xteink**; it's built as a community project.
|
||||||
|
|
||||||
## Features
|
## Features & Usage
|
||||||
|
|
||||||
- [x] EPUB parsing and rendering
|
- [x] EPUB parsing and rendering (EPUB 2 and EPUB 3)
|
||||||
|
- [ ] Image support within EPUB
|
||||||
- [x] Saved reading position
|
- [x] Saved reading position
|
||||||
- [ ] File explorer with file picker
|
- [x] File explorer with file picker
|
||||||
- [x] Basic EPUB picker from root directory
|
- [x] Basic EPUB picker from root directory
|
||||||
- [x] Support nested folders
|
- [x] Support nested folders
|
||||||
- [ ] EPUB picker with cover art
|
- [ ] EPUB picker with cover art
|
||||||
- [ ] Image support within EPUB
|
- [x] Custom sleep screen
|
||||||
- [ ] Configurable font, layout, and display options
|
- [x] Cover sleep screen
|
||||||
- [ ] WiFi connectivity
|
- [x] Wifi book upload
|
||||||
- [ ] BLE connectivity
|
- [x] Wifi OTA updates
|
||||||
|
- [x] Configurable font, layout, and display options
|
||||||
|
- [ ] User provided fonts
|
||||||
|
- [ ] Full UTF support
|
||||||
|
- [x] Screen rotation
|
||||||
|
|
||||||
|
Multi-language support: Read EPUBs in various languages, including English, Spanish, French, German, Italian, Portuguese, Russian, Ukrainian, Polish, Swedish, Norwegian, [and more](./USER_GUIDE.md#supported-languages).
|
||||||
|
|
||||||
|
See [the user guide](./USER_GUIDE.md) for instructions on operating CrossPoint.
|
||||||
|
|
||||||
|
For more details about the scope of the project, see the [SCOPE.md](SCOPE.md) document.
|
||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
@ -49,7 +60,7 @@ back to the other partition using the "Swap boot partition" button here https://
|
|||||||
### Web (specific firmware version)
|
### Web (specific firmware version)
|
||||||
|
|
||||||
1. Connect your Xteink X4 to your computer via USB-C
|
1. Connect your Xteink X4 to your computer via USB-C
|
||||||
2. Download the `firmware.bin` file from the release of your choice via the [releases page](https://github.com/daveallie/crosspoint-reader/releases)
|
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. Go to https://xteink.dve.al/ and flash the firmware file using the "OTA fast flash controls" section
|
3. Go to https://xteink.dve.al/ and flash the firmware file using the "OTA fast flash controls" section
|
||||||
|
|
||||||
To revert back to the official firmware, you can flash the latest official firmware from https://xteink.dve.al/, or swap
|
To revert back to the official firmware, you can flash the latest official firmware from https://xteink.dve.al/, or swap
|
||||||
@ -59,10 +70,6 @@ back to the other partition using the "Swap boot partition" button here https://
|
|||||||
|
|
||||||
See [Development](#development) below.
|
See [Development](#development) below.
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
See [the user guide](./USER_GUIDE.md) for instructions on operating CrossPoint.
|
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
@ -77,7 +84,7 @@ See [the user guide](./USER_GUIDE.md) for instructions on operating CrossPoint.
|
|||||||
CrossPoint uses PlatformIO for building and flashing the firmware. To get started, clone the repository:
|
CrossPoint uses PlatformIO for building and flashing the firmware. To get started, clone the repository:
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone --recursive https://github.com/daveallie/crosspoint-reader
|
git clone --recursive https://github.com/crosspoint-reader/crosspoint-reader
|
||||||
|
|
||||||
# Or, if you've already cloned without --recursive:
|
# Or, if you've already cloned without --recursive:
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
@ -90,6 +97,25 @@ Connect your Xteink X4 to your computer via USB-C and run the following command.
|
|||||||
```sh
|
```sh
|
||||||
pio run --target upload
|
pio run --target upload
|
||||||
```
|
```
|
||||||
|
### Debugging
|
||||||
|
|
||||||
|
After flashing the new features, it’s recommended to capture detailed logs from the serial port.
|
||||||
|
|
||||||
|
First, make sure all required Python packages are installed:
|
||||||
|
|
||||||
|
```python
|
||||||
|
python3 -m pip install pyserial colorama matplotlib
|
||||||
|
```
|
||||||
|
after that run the script:
|
||||||
|
```sh
|
||||||
|
# For Linux
|
||||||
|
# This was tested on Debian and should work on most Linux systems.
|
||||||
|
python3 scripts/debugging_monitor.py
|
||||||
|
|
||||||
|
# For macOS
|
||||||
|
python3 scripts/debugging_monitor.py /dev/cu.usbmodem2101
|
||||||
|
```
|
||||||
|
Minor adjustments may be required for Windows.
|
||||||
|
|
||||||
## Internals
|
## Internals
|
||||||
|
|
||||||
@ -97,9 +123,9 @@ CrossPoint Reader is pretty aggressive about caching data down to the SD card to
|
|||||||
has ~380KB of usable RAM, so we have to be careful. A lot of the decisions made in the design of the firmware were based
|
has ~380KB of usable RAM, so we have to be careful. A lot of the decisions made in the design of the firmware were based
|
||||||
on this constraint.
|
on this constraint.
|
||||||
|
|
||||||
### EPUB caching
|
### Data caching
|
||||||
|
|
||||||
The first time chapters of an EPUB are loaded, they are cached to the SD card. Subsequent loads are served from the
|
The first time chapters of a book are loaded, they are cached to the SD card. Subsequent loads are served from the
|
||||||
cache. This cache directory exists at `.crosspoint` on the SD card. The structure is as follows:
|
cache. This cache directory exists at `.crosspoint` on the SD card. The structure is as follows:
|
||||||
|
|
||||||
|
|
||||||
@ -107,33 +133,33 @@ cache. This cache directory exists at `.crosspoint` on the SD card. The structur
|
|||||||
.crosspoint/
|
.crosspoint/
|
||||||
├── epub_12471232/ # Each EPUB is cached to a subdirectory named `epub_<hash>`
|
├── epub_12471232/ # Each EPUB is cached to a subdirectory named `epub_<hash>`
|
||||||
│ ├── progress.bin # Stores reading progress (chapter, page, etc.)
|
│ ├── progress.bin # Stores reading progress (chapter, page, etc.)
|
||||||
│ ├── 0/ # Each chapter is stored in a subdirectory named by its index (based on the spine order)
|
│ ├── cover.bmp # Book cover image (once generated)
|
||||||
│ │ ├── section.bin # Section metadata (page count)
|
│ ├── book.bin # Book metadata (title, author, spine, table of contents, etc.)
|
||||||
│ │ ├── page_0.bin # Each page is stored in a separate file, it
|
│ └── sections/ # All chapter data is stored in the sections subdirectory
|
||||||
│ │ ├── page_1.bin # contains the position (x, y) and text for each word
|
│ ├── 0.bin # Chapter data (screen count, all text layout info, etc.)
|
||||||
│ │ └── ...
|
│ ├── 1.bin # files are named by their index in the spine
|
||||||
│ ├── 1/
|
|
||||||
│ │ ├── section.bin
|
|
||||||
│ │ ├── page_0.bin
|
|
||||||
│ │ ├── page_1.bin
|
|
||||||
│ │ └── ...
|
|
||||||
│ └── ...
|
│ └── ...
|
||||||
│
|
│
|
||||||
└── epub_189013891/
|
└── epub_189013891/
|
||||||
```
|
```
|
||||||
|
|
||||||
Deleting the `.crosspoint` directory will clear the cache.
|
Deleting the `.crosspoint` directory will clear the entire cache.
|
||||||
|
|
||||||
Due the way it's currently implemented, the cache is not automatically cleared when the EPUB is deleted and moving an
|
Due the way it's currently implemented, the cache is not automatically cleared when a book is deleted and moving a book
|
||||||
EPUB file will reset the reading progress.
|
file will use a new cache directory, resetting the reading progress.
|
||||||
|
|
||||||
|
For more details on the internal file structures, see the [file formats document](./docs/file-formats.md).
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Contributions are very welcome!
|
Contributions are very welcome!
|
||||||
|
|
||||||
If you're looking for a way to help out, take a look at the [ideas discussion board](https://github.com/daveallie/crosspoint-reader/discussions/categories/ideas).
|
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.
|
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 goverance and community
|
||||||
|
principles, please see [GOVERNANCE.md](GOVERNANCE.md).
|
||||||
|
|
||||||
### To submit a contribution:
|
### To submit a contribution:
|
||||||
|
|
||||||
1. Fork the repo
|
1. Fork the repo
|
||||||
|
|||||||
48
SCOPE.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# Project Vision & Scope: CrossPoint Reader
|
||||||
|
|
||||||
|
The goal of CrossPoint Reader is to create an efficient, open-source reading experience for the Xteink X4. We believe a
|
||||||
|
dedicated e-reader should do one thing exceptionally well: **facilitate focused reading.**
|
||||||
|
|
||||||
|
## 1. Core Mission
|
||||||
|
|
||||||
|
To provide a lightweight, high-performance firmware that maximizes the potential of the X4, prioritizing legibility and
|
||||||
|
usability over "swiss-army-knife" functionality.
|
||||||
|
|
||||||
|
## 2. Scope
|
||||||
|
|
||||||
|
### In-Scope
|
||||||
|
|
||||||
|
*These are features that directly improve the primary purpose of the device.*
|
||||||
|
|
||||||
|
* **User Experience:** E.g. User-friendly interfaces, and interactions, both inside the reader and navigating the
|
||||||
|
firmware. This includes things like button mapping, book loading, and book navigation like bookmarks.
|
||||||
|
* **Document Rendering:** E.g. Support for rendering documents (primarily EPUB) and improvements to the rendering
|
||||||
|
engine.
|
||||||
|
* **Format Optimization:** E.g. Efficiently parsing EPUB (CSS/Images) and other documents within the device's
|
||||||
|
capabilities.
|
||||||
|
* **Typography & Legibility:** E.g. Custom font support, hyphenation engines, and adjustable line spacing.
|
||||||
|
* **E-Ink Driver Refinement:** E.g. Reducing full-screen flashes (ghosting management) and improving general rendering.
|
||||||
|
* **Library Management:** E.g. Simple, intuitive ways to organize and navigate a collection of books.
|
||||||
|
* **Local Transfer:** E.g. Simple, "pull" based book loading via a basic web-server or public and widely-used standards.
|
||||||
|
* **Language Support:** E.g. Support for multiple languages both in the reader and in the interfaces.
|
||||||
|
|
||||||
|
### Out-of-Scope
|
||||||
|
|
||||||
|
*These items are rejected because they compromise the device's stability or mission.*
|
||||||
|
|
||||||
|
* **Interactive Apps:** No Notepads, Calculators, or Games. This is a reader, not a PDA.
|
||||||
|
* **Active Connectivity:** No RSS readers, News aggregators, or Web browsers. Background Wi-Fi tasks drain the battery
|
||||||
|
and complicate the single-core CPU's execution.
|
||||||
|
* **Media Playback:** No Audio players or Audio-books.
|
||||||
|
* **Complex Reader Features:** No highlighting, notes, or dictionary lookup. These features are better suited for
|
||||||
|
devices with better input capabilities and more powerful chips.
|
||||||
|
|
||||||
|
## 3. Idea Evaluation
|
||||||
|
|
||||||
|
While I appreciate the desire to add new and exciting features to CrossPoint Reader, CrossPoint Reader is designed to be
|
||||||
|
a lightweight, reliable, and performant e-reader. Things which distract or compromise the device's core mission will not
|
||||||
|
be accepted. As a guiding question, consider if your idea improve the "core reading experience" for the average user,
|
||||||
|
and, critically, not distract from that reading experience.
|
||||||
|
|
||||||
|
> **Note to Contributors:** If you are unsure if your idea fits the scope, please open a **Discussion** before you start
|
||||||
|
> coding!
|
||||||
194
USER_GUIDE.md
@ -1,17 +1,40 @@
|
|||||||
# CrossPoint User Guide
|
# CrossPoint User Guide
|
||||||
|
|
||||||
Welcome to the **CrossPoint** firmware. This guide outlines the hardware controls, navigation, and reading features of
|
Welcome to the **CrossPoint** firmware. This guide outlines the hardware controls, navigation, and reading features of the device.
|
||||||
the device.
|
|
||||||
|
- [CrossPoint User Guide](#crosspoint-user-guide)
|
||||||
|
- [1. Hardware Overview](#1-hardware-overview)
|
||||||
|
- [Button Layout](#button-layout)
|
||||||
|
- [2. Power \& Startup](#2-power--startup)
|
||||||
|
- [Power On / Off](#power-on--off)
|
||||||
|
- [First Launch](#first-launch)
|
||||||
|
- [3. Screens](#3-screens)
|
||||||
|
- [3.1 Home Screen](#31-home-screen)
|
||||||
|
- [3.2 Book Selection](#32-book-selection)
|
||||||
|
- [3.3 Reading Mode](#33-reading-mode)
|
||||||
|
- [3.4 File Upload Screen](#34-file-upload-screen)
|
||||||
|
- [3.5 Settings](#35-settings)
|
||||||
|
- [3.6 Sleep Screen](#36-sleep-screen)
|
||||||
|
- [4. Reading Mode](#4-reading-mode)
|
||||||
|
- [Page Turning](#page-turning)
|
||||||
|
- [Chapter Navigation](#chapter-navigation)
|
||||||
|
- [System Navigation](#system-navigation)
|
||||||
|
- [5. Chapter Selection Screen](#5-chapter-selection-screen)
|
||||||
|
- [6. Current Limitations \& Roadmap](#6-current-limitations--roadmap)
|
||||||
|
- [7. Troubleshooting Issues \& Escaping Bootloop](#7-troubleshooting-issues--escaping-bootloop)
|
||||||
|
|
||||||
|
|
||||||
## 1. Hardware Overview
|
## 1. Hardware Overview
|
||||||
|
|
||||||
The device utilises the standard buttons on the Xtink X4 in the same layout:
|
The device utilises the standard buttons on the Xtink X4 (in the same layout as the manufacturer firmware, by default):
|
||||||
|
|
||||||
### Button Layout
|
### Button Layout
|
||||||
| Location | Buttons |
|
| Location | Buttons |
|
||||||
|-----------------|--------------------------------------------|
|
| --------------- | ---------------------------------------------------- |
|
||||||
| **Bottom Edge** | **Back**, **Confirm**, **Left**, **Right** |
|
| **Bottom Edge** | **Back**, **Confirm**, **Left**, **Right** |
|
||||||
| **Right Side** | **Power**, **Volume Up**, **Volume Down** |
|
| **Right Side** | **Power**, **Volume Up**, **Volume Down**, **Reset** |
|
||||||
|
|
||||||
|
Button layout can be customized in **[Settings](#35-settings)**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -19,24 +42,132 @@ The device utilises the standard buttons on the Xtink X4 in the same layout:
|
|||||||
|
|
||||||
### Power On / Off
|
### Power On / Off
|
||||||
|
|
||||||
To turn the device on or off, **press and hold the Power button for 1 full second**.
|
To turn the device on or off, **press and hold the Power button for approximately half a second**.
|
||||||
|
In **[Settings](#35-settings)** you can configure the power button to turn the device off with a short press instead of a long one.
|
||||||
|
|
||||||
|
To reboot the device (for example if it's frozen, or after a firmware update), press and release the Reset button, and then quickly press and hold the Power button for a few seconds.
|
||||||
|
|
||||||
### First Launch
|
### First Launch
|
||||||
|
|
||||||
Upon turning the device on for the first time, you will be placed on the **Book Selection Screen** (File Browser).
|
Upon turning the device on for the first time, you will be placed on the **[Home](#31-home-screen)** screen.
|
||||||
|
|
||||||
> **Note:** On subsequent restarts, the firmware will automatically reopen the last book you were reading.
|
> [!NOTE]
|
||||||
|
> On subsequent restarts, the firmware will automatically reopen the last book you were reading.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Book Selection
|
## 3. Screens
|
||||||
|
|
||||||
The Home Screen acts as a folder and file browser.
|
### 3.1 Home Screen
|
||||||
|
|
||||||
* **Navigate List:** Use **Left** (or **Volume Up**), or **Right** (or **Volume Down**) to move the selection cursor up
|
The Home Screen is the main entry point to the firmware. From here you can navigate to **[Reading Mode](#4-reading-mode)** with the most recently read book, **[Book Selection](#32-book-selection)**, **[Settings](#35-settings)**, or the **[File Upload](#34-file-upload-screen)** screen.
|
||||||
and down through folders and books.
|
|
||||||
|
### 3.2 Book Selection
|
||||||
|
|
||||||
|
The Book Selection acts as a folder and file browser.
|
||||||
|
|
||||||
|
* **Navigate List:** Use **Left** (or **Volume Up**), or **Right** (or **Volume Down**) to move the selection cursor up and down through folders and books. You can also long-press these buttons to scroll a full page up or down.
|
||||||
* **Open Selection:** Press **Confirm** to open a folder or read a selected book.
|
* **Open Selection:** Press **Confirm** to open a folder or read a selected book.
|
||||||
|
|
||||||
|
### 3.3 Reading Mode
|
||||||
|
|
||||||
|
See [Reading Mode](#4-reading-mode) below for more information.
|
||||||
|
|
||||||
|
### 3.4 File Upload Screen
|
||||||
|
|
||||||
|
The File Upload screen allows you to upload new e-books to the device. When you enter the screen, you'll be prompted with a WiFi selection dialog and then your X4 will start hosting a web server.
|
||||||
|
|
||||||
|
See the [webserver docs](./docs/webserver.md) for more information on how to connect to the web server and upload files.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> Advanced users can also manage files programmatically or via the command line using `curl`. See the [webserver docs](./docs/webserver.md) for details.
|
||||||
|
|
||||||
|
### 3.4.1 Calibre Wireless Transfers
|
||||||
|
|
||||||
|
CrossPoint supports sending books from Calibre using the CrossPoint Reader device plugin.
|
||||||
|
|
||||||
|
1. Install the plugin in Calibre:
|
||||||
|
- Head to https://github.com/crosspoint-reader/calibre-plugins/releases to download the latest version of the crosspoint_reader plugin.
|
||||||
|
- Download the zip file.
|
||||||
|
- Open Calibre → Preferences → Plugins → Load plugin from file → Select the zip file.
|
||||||
|
2. On the device: File Transfer → Connect to Calibre → Join a network.
|
||||||
|
3. Make sure your computer is on the same WiFi network.
|
||||||
|
4. In Calibre, click "Send to device" to transfer books.
|
||||||
|
|
||||||
|
### 3.5 Settings
|
||||||
|
|
||||||
|
The Settings screen allows you to configure the device's behavior. There are a few settings you can adjust:
|
||||||
|
- **Sleep Screen**: Which sleep screen to display when the device sleeps:
|
||||||
|
- "Dark" (default) - The default dark Crosspoint logo sleep screen
|
||||||
|
- "Light" - The same default sleep screen, on a white background
|
||||||
|
- "Custom" - Custom images from the SD card; see [Sleep Screen](#36-sleep-screen) below for more information
|
||||||
|
- "Cover" - The book cover image (Note: this is experimental and may not work as expected)
|
||||||
|
- "None" - A blank screen
|
||||||
|
- "Cover + Custom" - The book cover image, fallbacks to "Custom" behavior
|
||||||
|
- **Sleep Screen Cover Mode**: How to display the book cover when "Cover" sleep screen is selected:
|
||||||
|
- "Fit" (default) - Scale the image down to fit centered on the screen, padding with white borders as necessary
|
||||||
|
- "Crop" - Scale the image down and crop as necessary to try to to fill the screen (Note: this is experimental and may not work as expected)
|
||||||
|
- **Sleep Screen Cover Filter**: What filter will be applied to the book cover when "Cover" sleep screen is selected
|
||||||
|
- "None" (default) - The cover image will be converted to a grayscale image and displayed as it is
|
||||||
|
- "Contrast" - The image will be displayed as a black & white image without grayscale conversion
|
||||||
|
- "Inverted" - The image will be inverted as in white&black and will be displayed without grayscale conversion
|
||||||
|
- **Status Bar**: Configure the status bar displayed while reading:
|
||||||
|
- "None" - No status bar
|
||||||
|
- "No Progress" - Show status bar without reading progress
|
||||||
|
- "Full" - Show status bar with reading progress
|
||||||
|
- **Hide Battery %**: Configure where to suppress the battery pecentage display in the status bar; the battery icon will still be shown:
|
||||||
|
- "Never" - Always show battery percentage (default)
|
||||||
|
- "In Reader" - Show battery percentage everywhere except in reading mode
|
||||||
|
- "Always" - Always hide battery percentage
|
||||||
|
- **Extra Paragraph Spacing**: If enabled, vertical space will be added between paragraphs in the book. If disabled, paragraphs will not have vertical space between them, but will have first-line indentation.
|
||||||
|
- **Text Anti-Aliasing**: Whether to show smooth grey edges (anti-aliasing) on text in reading mode. Note this slows down page turns slightly.
|
||||||
|
- **Short Power Button Click**: Controls the effect of a short click of the power button:
|
||||||
|
- "Ignore" - Require a long press to turn off the device
|
||||||
|
- "Sleep" - A short press powers the device off
|
||||||
|
- "Page Turn" - A short press in reading mode turns to the next page; a long press turns the device off
|
||||||
|
- **Reading Orientation**: Set the screen orientation for reading EPUB files:
|
||||||
|
- "Portrait" (default) - Standard portrait orientation
|
||||||
|
- "Landscape CW" - Landscape, rotated clockwise
|
||||||
|
- "Inverted" - Portrait, upside down
|
||||||
|
- "Landscape CCW" - Landscape, rotated counter-clockwise
|
||||||
|
- **Front Button Layout**: Configure the order of the bottom edge buttons:
|
||||||
|
- 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
|
||||||
|
- "Page Scroll" - Long-pressing scrolls a page up/down
|
||||||
|
- Swap the order of the up and down volume buttons from Previous/Next to Next/Previous. This change is only in effect when reading.
|
||||||
|
- **Reader Font Family**: Choose the font used for reading:
|
||||||
|
- "Bookerly" (default) - Amazon's reading font
|
||||||
|
- "Noto Sans" - Google's sans-serif font
|
||||||
|
- "Open Dyslexic" - Font designed for readers with dyslexia
|
||||||
|
- **Reader Font Size**: Adjust the text size for reading; options are "Small", "Medium", "Large", or "X Large".
|
||||||
|
- **Reader Line Spacing**: Adjust the spacing between lines; options are "Tight", "Normal", or "Wide".
|
||||||
|
- **Reader Screen Margin**: Controls the screen margins in reader mode between 5 and 40 pixels in 5 pixel increments.
|
||||||
|
- **Reader Paragraph Alignment**: Set the alignment of paragraphs; options are "Justified" (default), "Left", "Center", or "Right".
|
||||||
|
- **Time to Sleep**: Set the duration of inactivity before the device automatically goes to sleep.
|
||||||
|
- **Refresh Frequency**: Set how often the screen does a full refresh while reading to reduce ghosting.
|
||||||
|
- **OPDS Browser**: Configure OPDS server settings for browsing and downloading books. Set the server URL (for Calibre Content Server, add `/opds` to the end), and optionally configure username and password for servers requiring authentication. Note: Only HTTP Basic authentication is supported. If using Calibre Content Server with authentication enabled, you must set it to use Basic authentication instead of the default Digest authentication.
|
||||||
|
- **Check for updates**: Check for firmware updates over WiFi.
|
||||||
|
|
||||||
|
### 3.6 Sleep Screen
|
||||||
|
|
||||||
|
You can customize the sleep screen by placing custom images in specific locations on the SD card:
|
||||||
|
|
||||||
|
- **Single Image:** Place a file named `sleep.bmp` in the root directory.
|
||||||
|
- **Multiple Images:** Create a `sleep` directory in the root of the SD card and place any number of `.bmp` images inside. If images are found in this directory, they will take priority over the `sleep.bmp` file, and one will be randomly selected each time the device sleeps.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> You'll need to set the **Sleep Screen** setting to **Custom** in order to use these images.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> For best results:
|
||||||
|
> - Use uncompressed BMP files with 24-bit color depth
|
||||||
|
> - Use a resolution of 480x800 pixels to match the device's screen resolution.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. Reading Mode
|
## 4. Reading Mode
|
||||||
@ -45,17 +176,34 @@ Once you have opened a book, the button layout changes to facilitate reading.
|
|||||||
|
|
||||||
### Page Turning
|
### Page Turning
|
||||||
| Action | Buttons |
|
| Action | Buttons |
|
||||||
|-------------------|--------------------------------------|
|
| ----------------- | ------------------------------------ |
|
||||||
| **Previous Page** | Press **Left** _or_ **Volume Up** |
|
| **Previous Page** | Press **Left** _or_ **Volume Up** |
|
||||||
| **Next Page** | Press **Right** _or_ **Volume Down** |
|
| **Next Page** | Press **Right** _or_ **Volume Down** |
|
||||||
|
|
||||||
|
The role of the volume (side) buttons can be swapped in **[Settings](#35-settings)**.
|
||||||
|
|
||||||
|
If the **Short Power Button Click** setting is set to "Page Turn", you can also turn to the next page by briefly pressing the Power button.
|
||||||
|
|
||||||
### Chapter Navigation
|
### Chapter Navigation
|
||||||
* **Next Chapter:** Press and **hold** the **Right** (or **Volume Down**) button briefly, then release.
|
* **Next Chapter:** Press and **hold** the **Right** (or **Volume Down**) button briefly, then release.
|
||||||
* **Previous Chapter:** Press and **hold** the **Left** (or **Volume Up**) button briefly, then release.
|
* **Previous Chapter:** Press and **hold** the **Left** (or **Volume Up**) button briefly, then release.
|
||||||
|
|
||||||
|
This feature can be disabled in **[Settings](#35-settings)** to help avoid changing chapters by mistake.
|
||||||
|
|
||||||
|
|
||||||
### System Navigation
|
### System Navigation
|
||||||
* **Return to Home:** Press **Back** to close the book and return to the Book Selection screen.
|
* **Return to Book Selection:** Press **Back** to close the book and return to the **[Book Selection](#32-book-selection)** screen.
|
||||||
* **Chapter Menu:** Press **Confirm** to open the Table of Contents/Chapter Selection screen.
|
* **Return to Home:** Press and **hold** the **Back** button to close the book and return to the **[Home](#31-home-screen)** screen.
|
||||||
|
* **Chapter Menu:** Press **Confirm** to open the **[Table of Contents/Chapter Selection](#5-chapter-selection-screen)**.
|
||||||
|
|
||||||
|
### Supported Languages
|
||||||
|
|
||||||
|
CrossPoint renders text using the following Unicode character blocks, enabling support for a wide range of languages:
|
||||||
|
|
||||||
|
* **Latin Script (Basic, Supplement, Extended-A):** Covers English, German, French, Spanish, Portuguese, Italian, Dutch, Swedish, Norwegian, Danish, Finnish, Polish, Czech, Hungarian, Romanian, Slovak, Slovenian, Turkish, and others.
|
||||||
|
* **Cyrillic Script (Standard and Extended):** Covers Russian, Ukrainian, Belarusian, Bulgarian, Serbian, Macedonian, Kazakh, Kyrgyz, Mongolian, and others.
|
||||||
|
|
||||||
|
What is not supported: Chinese, Japanese, Korean, Vietnamese, Hebrew, Arabic, Greek and Farsi.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -71,8 +219,18 @@ Accessible by pressing **Confirm** while inside a book.
|
|||||||
|
|
||||||
## 6. Current Limitations & Roadmap
|
## 6. Current Limitations & Roadmap
|
||||||
|
|
||||||
Please note that this firmware is currently in active development. The following features are **not yet supported** but
|
Please note that this firmware is currently in active development. The following features are **not yet supported** but are planned for future updates:
|
||||||
are planned for future updates:
|
|
||||||
|
|
||||||
* **Images:** Embedded images in e-books will not render.
|
* **Images:** Embedded images in e-books will not render.
|
||||||
* **Text Formatting:** There are currently no settings to adjust font type, size, line spacing, or margins.
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Troubleshooting Issues & Escaping Bootloop
|
||||||
|
|
||||||
|
If an issue or crash is encountered while using Crosspoint, feel free to raise an issue ticket and attach the serial monitor logs. The logs can be obtained by connecting the device to a computer and starting a serial monitor. Either [Serial Monitor](https://www.serialmonitor.org/) or the following command can be used:
|
||||||
|
|
||||||
|
```
|
||||||
|
pio device monitor
|
||||||
|
```
|
||||||
|
|
||||||
|
If the device is stuck in a bootloop, press and release the Reset button. Then, press and hold on to the configured Back button and the Power Button to boot to the Home Screen.
|
||||||
|
|||||||
@ -1,3 +1,19 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
find src lib \( -name "*.c" -o -name "*.cpp" -o -name "*.h" -o -name "*.hpp" \) -exec clang-format -style=file -i {} +
|
GIT_LS_FILES_FLAGS=""
|
||||||
|
if [[ "$1" == "-g" ]]; then
|
||||||
|
GIT_LS_FILES_FLAGS="--modified"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Main Logic ---
|
||||||
|
|
||||||
|
# Format all files (or only modified files if -g is passed)
|
||||||
|
|
||||||
|
# Use 'git ls-files' to get a list of all files tracked by git:
|
||||||
|
# --modified: files tracked by git that have been modified (staged or unstaged)
|
||||||
|
# --exclude-standard: ignores files in .gitignore
|
||||||
|
# Additionally exclude files in 'lib/EpdFont/builtinFonts/' as they are script-generated.
|
||||||
|
git ls-files --exclude-standard ${GIT_LS_FILES_FLAGS} \
|
||||||
|
| grep -E '\.(c|cpp|h|hpp)$' \
|
||||||
|
| grep -v -E '^lib/EpdFont/builtinFonts/' \
|
||||||
|
| xargs -r clang-format -style=file -i
|
||||||
|
|||||||
221
docs/file-formats.md
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
# File Formats
|
||||||
|
|
||||||
|
## `book.bin`
|
||||||
|
|
||||||
|
### Version 3
|
||||||
|
|
||||||
|
ImHex Pattern:
|
||||||
|
|
||||||
|
```c++
|
||||||
|
import std.mem;
|
||||||
|
import std.string;
|
||||||
|
import std.core;
|
||||||
|
|
||||||
|
// === Configuration ===
|
||||||
|
#define EXPECTED_VERSION 3
|
||||||
|
#define MAX_STRING_LENGTH 65535
|
||||||
|
|
||||||
|
// === String Structure ===
|
||||||
|
|
||||||
|
struct String {
|
||||||
|
u32 length [[hidden, comment("String byte length")]];
|
||||||
|
if (length > MAX_STRING_LENGTH) {
|
||||||
|
std::warning(std::format("Unusually large string length: {} bytes", length));
|
||||||
|
}
|
||||||
|
char data[length] [[comment("UTF-8 string data")]];
|
||||||
|
} [[sealed, format("format_string"), comment("Length-prefixed UTF-8 string")]];
|
||||||
|
|
||||||
|
fn format_string(String s) {
|
||||||
|
return s.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// === Metadata Structure ===
|
||||||
|
|
||||||
|
struct Metadata {
|
||||||
|
String title [[comment("Book title")]];
|
||||||
|
String author [[comment("Book author")]];
|
||||||
|
String coverItemHref [[comment("Path to cover image")]];
|
||||||
|
String textReferenceHref [[comment("Path to guided first text reference")]];
|
||||||
|
} [[comment("Book metadata information")]];
|
||||||
|
|
||||||
|
// === Spine Entry Structure ===
|
||||||
|
|
||||||
|
struct SpineEntry {
|
||||||
|
String href [[comment("Resource path")]];
|
||||||
|
u32 cumulativeSize [[comment("Cumulative size in bytes"), color("FF6B6B")]];
|
||||||
|
s16 tocIndex [[comment("Index into TOC (-1 if none)"), color("4ECDC4")]];
|
||||||
|
} [[comment("Spine entry defining reading order")]];
|
||||||
|
|
||||||
|
// === TOC Entry Structure ===
|
||||||
|
|
||||||
|
struct TocEntry {
|
||||||
|
String title [[comment("Chapter/section title")]];
|
||||||
|
String href [[comment("Resource path")]];
|
||||||
|
String anchor [[comment("Fragment identifier")]];
|
||||||
|
u8 level [[comment("Nesting level (0-255)"), color("95E1D3")]];
|
||||||
|
s16 spineIndex [[comment("Index into spine (-1 if none)"), color("F38181")]];
|
||||||
|
} [[comment("Table of contents entry")]];
|
||||||
|
|
||||||
|
// === Book Bin Structure ===
|
||||||
|
|
||||||
|
struct BookBin {
|
||||||
|
// Header
|
||||||
|
u8 version [[comment("Format version"), color("FFD93D")]];
|
||||||
|
|
||||||
|
// Version validation
|
||||||
|
if (version != EXPECTED_VERSION) {
|
||||||
|
std::error(std::format("Unsupported version: {} (expected {})", version, EXPECTED_VERSION));
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 lutOffset [[comment("Offset to lookup tables"), color("6BCB77")]];
|
||||||
|
u16 spineCount [[comment("Number of spine entries"), color("4D96FF")]];
|
||||||
|
u16 tocCount [[comment("Number of TOC entries"), color("FF6B9D")]];
|
||||||
|
|
||||||
|
// Metadata section
|
||||||
|
Metadata metadata [[comment("Book metadata")]];
|
||||||
|
|
||||||
|
// Validate LUT offset alignment
|
||||||
|
u32 currentOffset = $;
|
||||||
|
if (currentOffset != lutOffset) {
|
||||||
|
std::warning(std::format("LUT offset mismatch: expected 0x{:X}, got 0x{:X}", lutOffset, currentOffset));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup Tables
|
||||||
|
u32 spineLut[spineCount] [[comment("Spine entry offsets"), color("4D96FF")]];
|
||||||
|
u32 tocLut[tocCount] [[comment("TOC entry offsets"), color("FF6B9D")]];
|
||||||
|
|
||||||
|
// Data Entries
|
||||||
|
SpineEntry spines[spineCount] [[comment("Spine entries (reading order)")]];
|
||||||
|
TocEntry toc[tocCount] [[comment("Table of contents entries")]];
|
||||||
|
};
|
||||||
|
|
||||||
|
// === File Parsing ===
|
||||||
|
|
||||||
|
BookBin book @ 0x00;
|
||||||
|
|
||||||
|
// Validate we've consumed the entire file
|
||||||
|
u32 fileSize = std::mem::size();
|
||||||
|
u32 parsedSize = $;
|
||||||
|
|
||||||
|
if (parsedSize != fileSize) {
|
||||||
|
std::warning(std::format("Unparsed data detected: {} bytes remaining at offset 0x{:X}", fileSize - parsedSize, parsedSize));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## `section.bin`
|
||||||
|
|
||||||
|
### Version 8
|
||||||
|
|
||||||
|
ImHex Pattern:
|
||||||
|
|
||||||
|
```c++
|
||||||
|
import std.mem;
|
||||||
|
import std.string;
|
||||||
|
import std.core;
|
||||||
|
|
||||||
|
// === Configuration ===
|
||||||
|
#define EXPECTED_VERSION 8
|
||||||
|
#define MAX_STRING_LENGTH 65535
|
||||||
|
|
||||||
|
// === String Structure ===
|
||||||
|
|
||||||
|
struct String {
|
||||||
|
u32 length [[hidden, comment("String byte length")]];
|
||||||
|
if (length > MAX_STRING_LENGTH) {
|
||||||
|
std::warning(std::format("Unusually large string length: {} bytes", length));
|
||||||
|
}
|
||||||
|
char data[length] [[comment("UTF-8 string data")]];
|
||||||
|
} [[sealed, format("format_string"), comment("Length-prefixed UTF-8 string")]];
|
||||||
|
|
||||||
|
fn format_string(String s) {
|
||||||
|
return s.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// === Page Structure ===
|
||||||
|
|
||||||
|
enum StorageType : u8 {
|
||||||
|
PageLine = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum WordStyle : u8 {
|
||||||
|
REGULAR = 0,
|
||||||
|
BOLD = 1,
|
||||||
|
ITALIC = 2,
|
||||||
|
BOLD_ITALIC = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BlockStyle : u8 {
|
||||||
|
JUSTIFIED = 0,
|
||||||
|
LEFT_ALIGN = 1,
|
||||||
|
CENTER_ALIGN = 2,
|
||||||
|
RIGHT_ALIGN = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PageLine {
|
||||||
|
s16 xPos;
|
||||||
|
s16 yPos;
|
||||||
|
u16 wordCount;
|
||||||
|
String words[wordCount];
|
||||||
|
u16 wordXPos[wordCount];
|
||||||
|
WordStyle wordStyle[wordCount];
|
||||||
|
BlockStyle blockStyle;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PageElement {
|
||||||
|
u8 pageElementType;
|
||||||
|
if (pageElementType == 1) {
|
||||||
|
PageLine pageLine [[inline]];
|
||||||
|
} else {
|
||||||
|
std::error(std::format("Unknown page element type: {}", pageElementType));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Page {
|
||||||
|
u16 elementCount;
|
||||||
|
PageElement elements[elementCount] [[inline]];
|
||||||
|
};
|
||||||
|
|
||||||
|
// === Section Bin Structure ===
|
||||||
|
|
||||||
|
struct SectionBin {
|
||||||
|
// Header
|
||||||
|
u8 version [[comment("Format version"), color("FFD93D")]];
|
||||||
|
|
||||||
|
// Version validation
|
||||||
|
if (version != EXPECTED_VERSION) {
|
||||||
|
std::error(std::format("Unsupported version: {} (expected {})", version, EXPECTED_VERSION));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache busting parameters
|
||||||
|
s32 fontId;
|
||||||
|
float lineCompression;
|
||||||
|
bool extraParagraphSpacing;
|
||||||
|
u16 viewportWidth;
|
||||||
|
u16 vieportHeight;
|
||||||
|
u16 pageCount;
|
||||||
|
u32 lutOffset;
|
||||||
|
|
||||||
|
Page page[pageCount];
|
||||||
|
|
||||||
|
// Validate LUT offset alignment
|
||||||
|
u32 currentOffset = $;
|
||||||
|
if (currentOffset != lutOffset) {
|
||||||
|
std::warning(std::format("LUT offset mismatch: expected 0x{:X}, got 0x{:X}", lutOffset, currentOffset));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup Tables
|
||||||
|
u32 lut[pageCount];
|
||||||
|
};
|
||||||
|
|
||||||
|
// === File Parsing ===
|
||||||
|
|
||||||
|
SectionBin book @ 0x00;
|
||||||
|
|
||||||
|
// Validate we've consumed the entire file
|
||||||
|
u32 fileSize = std::mem::size();
|
||||||
|
u32 parsedSize = $;
|
||||||
|
|
||||||
|
if (parsedSize != fileSize) {
|
||||||
|
std::warning(std::format("Unparsed data detected: {} bytes remaining at offset 0x{:X}", fileSize - parsedSize, parsedSize));
|
||||||
|
}
|
||||||
|
```
|
||||||
66
docs/hyphenation-trie-format.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# Hypher Binary Tries
|
||||||
|
|
||||||
|
CrossPoint embeds the exact binary automata produced by
|
||||||
|
[Typst's `hypher`](https://github.com/typst/hypher).
|
||||||
|
|
||||||
|
## File layout
|
||||||
|
|
||||||
|
Each `.bin` blob is a single self-contained automaton:
|
||||||
|
|
||||||
|
```
|
||||||
|
uint32_t root_addr_be; // big-endian offset of the root node
|
||||||
|
uint8_t levels[]; // shared "levels" tape (dist/score pairs)
|
||||||
|
uint8_t nodes[]; // node records packed back-to-back
|
||||||
|
```
|
||||||
|
|
||||||
|
The size of the `levels` tape is implicit. Individual nodes reference slices
|
||||||
|
inside that tape via 12-bit offsets, so no additional pointers are required.
|
||||||
|
|
||||||
|
### Node encoding
|
||||||
|
|
||||||
|
Every node starts with a single control byte:
|
||||||
|
|
||||||
|
- Bit 7 – set when the node stores scores (`levels`).
|
||||||
|
- Bits 5-6 – stride of the target deltas (1, 2, or 3 bytes, big-endian).
|
||||||
|
- Bits 0-4 – transition count (values ≥ 31 spill into an extra byte).
|
||||||
|
|
||||||
|
If the `levels` flag is set, two more bytes follow. Together they encode a
|
||||||
|
12-bit offset into the global `levels` tape and a 4-bit length. Each byte in the
|
||||||
|
levels tape packs a distance/score pair as `dist * 10 + score`, where `dist`
|
||||||
|
counts how many UTF-8 bytes we advanced since the previous digit.
|
||||||
|
|
||||||
|
After the optional levels header come the transition labels (one byte per edge)
|
||||||
|
followed by the signed target deltas. Targets are stored as relative offsets
|
||||||
|
from the current node address. Deltas up to ±128 fit in a single byte, larger
|
||||||
|
distances grow to 2 or 3 bytes. The runtime walks the transitions with a simple
|
||||||
|
linear scan and materializes the absolute address by adding the decoded delta
|
||||||
|
to the current node’s base.
|
||||||
|
|
||||||
|
## Embedding blobs into the firmware
|
||||||
|
|
||||||
|
The helper script `scripts/generate_hyphenation_trie.py` acts as a thin
|
||||||
|
wrapper: it reads the hypher-generated `.bin` files, formats them as `constexpr`
|
||||||
|
byte arrays, and emits headers under
|
||||||
|
`lib/Epub/Epub/hyphenation/generated/`. Each header defines the raw data plus a
|
||||||
|
`SerializedHyphenationPatterns` descriptor so the reader can keep the automaton
|
||||||
|
in flash.
|
||||||
|
|
||||||
|
To refresh the firmware assets after updating the `.bin` files, run:
|
||||||
|
|
||||||
|
```
|
||||||
|
./scripts/generate_hyphenation_trie.py \
|
||||||
|
--input lib/Epub/Epub/hyphenation/tries/en.bin \
|
||||||
|
--output lib/Epub/Epub/hyphenation/generated/hyph-en.trie.h
|
||||||
|
|
||||||
|
./scripts/generate_hyphenation_trie.py \
|
||||||
|
--input lib/Epub/Epub/hyphenation/tries/fr.bin \
|
||||||
|
--output lib/Epub/Epub/hyphenation/generated/hyph-fr.trie.h
|
||||||
|
|
||||||
|
./scripts/generate_hyphenation_trie.py \
|
||||||
|
--input lib/Epub/Epub/hyphenation/tries/de.bin \
|
||||||
|
--output lib/Epub/Epub/hyphenation/generated/hyph-de.trie.h
|
||||||
|
|
||||||
|
./scripts/generate_hyphenation_trie.py \
|
||||||
|
--input lib/Epub/Epub/hyphenation/tries/ru.bin \
|
||||||
|
--output lib/Epub/Epub/hyphenation/generated/hyph-ru.trie.h
|
||||||
|
```
|
||||||
|
Before Width: | Height: | Size: 2.2 MiB After Width: | Height: | Size: 899 KiB |
BIN
docs/images/wifi/webserver_files.png
Normal file
|
After Width: | Height: | Size: 193 KiB |
BIN
docs/images/wifi/webserver_homepage.png
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
docs/images/wifi/webserver_upload.png
Normal file
|
After Width: | Height: | Size: 135 KiB |
BIN
docs/images/wifi/wifi_connected.jpeg
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
docs/images/wifi/wifi_networks.jpeg
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
docs/images/wifi/wifi_password.jpeg
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
57
docs/troubleshooting.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# Troubleshooting
|
||||||
|
|
||||||
|
This document show most common issues and possible solutions while using the device features.
|
||||||
|
|
||||||
|
- [Troubleshooting](#troubleshooting)
|
||||||
|
- [Cannot See the Device on the Network](#cannot-see-the-device-on-the-network)
|
||||||
|
- [Connection Drops or Times Out](#connection-drops-or-times-out)
|
||||||
|
- [Upload Fails](#upload-fails)
|
||||||
|
- [Saved Password Not Working](#saved-password-not-working)
|
||||||
|
|
||||||
|
### Cannot See the Device on the Network
|
||||||
|
|
||||||
|
**Problem:** Browser shows "Cannot connect" or "Site can't be reached"
|
||||||
|
|
||||||
|
**Solutions:**
|
||||||
|
|
||||||
|
1. Verify both devices are on the **same WiFi network**
|
||||||
|
- Check your computer/phone WiFi settings
|
||||||
|
- Confirm the CrossPoint Reader shows "Connected" status
|
||||||
|
2. Double-check the IP address
|
||||||
|
- Make sure you typed it correctly
|
||||||
|
- Include `http://` at the beginning
|
||||||
|
3. Try disabling VPN if you're using one
|
||||||
|
4. Some networks have "client isolation" enabled - check with your network administrator
|
||||||
|
|
||||||
|
### Connection Drops or Times Out
|
||||||
|
|
||||||
|
**Problem:** WiFi connection is unstable
|
||||||
|
|
||||||
|
**Solutions:**
|
||||||
|
|
||||||
|
1. Move closer to the WiFi router
|
||||||
|
2. Check signal strength on the device (should be at least `||` or better)
|
||||||
|
3. Avoid interference from other devices
|
||||||
|
4. Try a different WiFi network if available
|
||||||
|
|
||||||
|
### Upload Fails
|
||||||
|
|
||||||
|
**Problem:** File upload doesn't complete or shows an error
|
||||||
|
|
||||||
|
**Solutions:**
|
||||||
|
|
||||||
|
1. Ensure the file is a valid `.epub` file
|
||||||
|
2. Check that the SD card has enough free space
|
||||||
|
3. Try uploading a smaller file first to test
|
||||||
|
4. Refresh the browser page and try again
|
||||||
|
|
||||||
|
### Saved Password Not Working
|
||||||
|
|
||||||
|
**Problem:** Device fails to connect with saved credentials
|
||||||
|
|
||||||
|
**Solutions:**
|
||||||
|
|
||||||
|
1. When connection fails, you'll be prompted to "Forget Network"
|
||||||
|
2. Select **Yes** to remove the saved password
|
||||||
|
3. Reconnect and enter the password again
|
||||||
|
4. Choose to save the new password
|
||||||
331
docs/webserver-endpoints.md
Normal file
@ -0,0 +1,331 @@
|
|||||||
|
# Webserver Endpoints
|
||||||
|
|
||||||
|
This document describes all HTTP and WebSocket endpoints available on the CrossPoint Reader webserver.
|
||||||
|
|
||||||
|
- [Webserver Endpoints](#webserver-endpoints)
|
||||||
|
- [Overview](#overview)
|
||||||
|
- [HTTP Endpoints](#http-endpoints)
|
||||||
|
- [GET `/` - Home Page](#get----home-page)
|
||||||
|
- [GET `/files` - File Browser Page](#get-files---file-browser-page)
|
||||||
|
- [GET `/api/status` - Device Status](#get-apistatus---device-status)
|
||||||
|
- [GET `/api/files` - List Files](#get-apifiles---list-files)
|
||||||
|
- [POST `/upload` - Upload File](#post-upload---upload-file)
|
||||||
|
- [POST `/mkdir` - Create Folder](#post-mkdir---create-folder)
|
||||||
|
- [POST `/delete` - Delete File or Folder](#post-delete---delete-file-or-folder)
|
||||||
|
- [WebSocket Endpoint](#websocket-endpoint)
|
||||||
|
- [Port 81 - Fast Binary Upload](#port-81---fast-binary-upload)
|
||||||
|
- [Network Modes](#network-modes)
|
||||||
|
- [Station Mode (STA)](#station-mode-sta)
|
||||||
|
- [Access Point Mode (AP)](#access-point-mode-ap)
|
||||||
|
- [Notes](#notes)
|
||||||
|
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The CrossPoint Reader exposes a webserver for file management and device monitoring:
|
||||||
|
|
||||||
|
- **HTTP Server**: Port 80
|
||||||
|
- **WebSocket Server**: Port 81 (for fast binary uploads)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## HTTP Endpoints
|
||||||
|
|
||||||
|
### GET `/` - Home Page
|
||||||
|
|
||||||
|
Serves the home page HTML interface.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```bash
|
||||||
|
curl http://crosspoint.local/
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:** HTML page (200 OK)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### GET `/files` - File Browser Page
|
||||||
|
|
||||||
|
Serves the file browser HTML interface.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```bash
|
||||||
|
curl http://crosspoint.local/files
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:** HTML page (200 OK)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### GET `/api/status` - Device Status
|
||||||
|
|
||||||
|
Returns JSON with device status information.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```bash
|
||||||
|
curl http://crosspoint.local/api/status
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response (200 OK):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": "1.0.0",
|
||||||
|
"ip": "192.168.1.100",
|
||||||
|
"mode": "STA",
|
||||||
|
"rssi": -45,
|
||||||
|
"freeHeap": 123456,
|
||||||
|
"uptime": 3600
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
| ---------- | ------ | --------------------------------------------------------- |
|
||||||
|
| `version` | string | CrossPoint firmware version |
|
||||||
|
| `ip` | string | Device IP address |
|
||||||
|
| `mode` | string | `"STA"` (connected to WiFi) or `"AP"` (access point mode) |
|
||||||
|
| `rssi` | number | WiFi signal strength in dBm (0 in AP mode) |
|
||||||
|
| `freeHeap` | number | Free heap memory in bytes |
|
||||||
|
| `uptime` | number | Seconds since device boot |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### GET `/api/files` - List Files
|
||||||
|
|
||||||
|
Returns a JSON array of files and folders in the specified directory.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```bash
|
||||||
|
# List root directory
|
||||||
|
curl http://crosspoint.local/api/files
|
||||||
|
|
||||||
|
# List specific directory
|
||||||
|
curl "http://crosspoint.local/api/files?path=/Books"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Query Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Required | Default | Description |
|
||||||
|
| --------- | -------- | ------- | ---------------------- |
|
||||||
|
| `path` | No | `/` | Directory path to list |
|
||||||
|
|
||||||
|
**Response (200 OK):**
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{"name": "MyBook.epub", "size": 1234567, "isDirectory": false, "isEpub": true},
|
||||||
|
{"name": "Notes", "size": 0, "isDirectory": true, "isEpub": false},
|
||||||
|
{"name": "document.pdf", "size": 54321, "isDirectory": false, "isEpub": false}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
| ------------- | ------- | ---------------------------------------- |
|
||||||
|
| `name` | string | File or folder name |
|
||||||
|
| `size` | number | Size in bytes (0 for directories) |
|
||||||
|
| `isDirectory` | boolean | `true` if the item is a folder |
|
||||||
|
| `isEpub` | boolean | `true` if the file has `.epub` extension |
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
- Hidden files (starting with `.`) are automatically filtered out
|
||||||
|
- System folders (`System Volume Information`, `XTCache`) are hidden
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### POST `/upload` - Upload File
|
||||||
|
|
||||||
|
Uploads a file to the SD card via multipart form data.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```bash
|
||||||
|
# Upload to root directory
|
||||||
|
curl -X POST -F "file=@mybook.epub" http://crosspoint.local/upload
|
||||||
|
|
||||||
|
# Upload to specific directory
|
||||||
|
curl -X POST -F "file=@mybook.epub" "http://crosspoint.local/upload?path=/Books"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Query Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Required | Default | Description |
|
||||||
|
| --------- | -------- | ------- | ------------------------------- |
|
||||||
|
| `path` | No | `/` | Target directory for the upload |
|
||||||
|
|
||||||
|
**Response (200 OK):**
|
||||||
|
```
|
||||||
|
File uploaded successfully: mybook.epub
|
||||||
|
```
|
||||||
|
|
||||||
|
**Error Responses:**
|
||||||
|
|
||||||
|
| Status | Body | Cause |
|
||||||
|
| ------ | ----------------------------------------------- | --------------------------- |
|
||||||
|
| 400 | `Failed to create file on SD card` | Cannot create file |
|
||||||
|
| 400 | `Failed to write to SD card - disk may be full` | Write error during upload |
|
||||||
|
| 400 | `Failed to write final data to SD card` | Error flushing final buffer |
|
||||||
|
| 400 | `Upload aborted` | Client aborted the upload |
|
||||||
|
| 400 | `Unknown error during upload` | Unspecified error |
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
- Existing files with the same name will be overwritten
|
||||||
|
- Uses a 4KB buffer for efficient SD card writes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### POST `/mkdir` - Create Folder
|
||||||
|
|
||||||
|
Creates a new folder on the SD card.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```bash
|
||||||
|
curl -X POST -d "name=NewFolder&path=/" http://crosspoint.local/mkdir
|
||||||
|
```
|
||||||
|
|
||||||
|
**Form Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Required | Default | Description |
|
||||||
|
| --------- | -------- | ------- | ---------------------------- |
|
||||||
|
| `name` | Yes | - | Name of the folder to create |
|
||||||
|
| `path` | No | `/` | Parent directory path |
|
||||||
|
|
||||||
|
**Response (200 OK):**
|
||||||
|
```
|
||||||
|
Folder created: NewFolder
|
||||||
|
```
|
||||||
|
|
||||||
|
**Error Responses:**
|
||||||
|
|
||||||
|
| Status | Body | Cause |
|
||||||
|
| ------ | ----------------------------- | ----------------------------- |
|
||||||
|
| 400 | `Missing folder name` | `name` parameter not provided |
|
||||||
|
| 400 | `Folder name cannot be empty` | Empty folder name |
|
||||||
|
| 400 | `Folder already exists` | Folder with same name exists |
|
||||||
|
| 500 | `Failed to create folder` | SD card error |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### POST `/delete` - Delete File or Folder
|
||||||
|
|
||||||
|
Deletes a file or folder from the SD card.
|
||||||
|
|
||||||
|
**Request:**
|
||||||
|
```bash
|
||||||
|
# Delete a file
|
||||||
|
curl -X POST -d "path=/Books/mybook.epub&type=file" http://crosspoint.local/delete
|
||||||
|
|
||||||
|
# Delete an empty folder
|
||||||
|
curl -X POST -d "path=/OldFolder&type=folder" http://crosspoint.local/delete
|
||||||
|
```
|
||||||
|
|
||||||
|
**Form Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Required | Default | Description |
|
||||||
|
| --------- | -------- | ------- | -------------------------------- |
|
||||||
|
| `path` | Yes | - | Path to the item to delete |
|
||||||
|
| `type` | No | `file` | Type of item: `file` or `folder` |
|
||||||
|
|
||||||
|
**Response (200 OK):**
|
||||||
|
```
|
||||||
|
Deleted successfully
|
||||||
|
```
|
||||||
|
|
||||||
|
**Error Responses:**
|
||||||
|
|
||||||
|
| Status | Body | Cause |
|
||||||
|
| ------ | --------------------------------------------- | ----------------------------- |
|
||||||
|
| 400 | `Missing path` | `path` parameter not provided |
|
||||||
|
| 400 | `Cannot delete root directory` | Attempted to delete `/` |
|
||||||
|
| 400 | `Folder is not empty. Delete contents first.` | Non-empty folder |
|
||||||
|
| 403 | `Cannot delete system files` | Hidden file (starts with `.`) |
|
||||||
|
| 403 | `Cannot delete protected items` | Protected system folder |
|
||||||
|
| 404 | `Item not found` | Path does not exist |
|
||||||
|
| 500 | `Failed to delete item` | SD card error |
|
||||||
|
|
||||||
|
**Protected Items:**
|
||||||
|
- Files/folders starting with `.`
|
||||||
|
- `System Volume Information`
|
||||||
|
- `XTCache`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## WebSocket Endpoint
|
||||||
|
|
||||||
|
### Port 81 - Fast Binary Upload
|
||||||
|
|
||||||
|
A WebSocket endpoint for high-speed binary file uploads. More efficient than HTTP multipart for large files.
|
||||||
|
|
||||||
|
**Connection:**
|
||||||
|
```
|
||||||
|
ws://crosspoint.local:81/
|
||||||
|
```
|
||||||
|
|
||||||
|
**Protocol:**
|
||||||
|
|
||||||
|
1. **Client** sends TEXT message: `START:<filename>:<size>:<path>`
|
||||||
|
2. **Server** responds with TEXT: `READY`
|
||||||
|
3. **Client** sends BINARY messages with file data chunks
|
||||||
|
4. **Server** sends TEXT progress updates: `PROGRESS:<received>:<total>`
|
||||||
|
5. **Server** sends TEXT when complete: `DONE` or `ERROR:<message>`
|
||||||
|
|
||||||
|
**Example Session:**
|
||||||
|
|
||||||
|
```
|
||||||
|
Client -> "START:mybook.epub:1234567:/Books"
|
||||||
|
Server -> "READY"
|
||||||
|
Client -> [binary chunk 1]
|
||||||
|
Client -> [binary chunk 2]
|
||||||
|
Server -> "PROGRESS:65536:1234567"
|
||||||
|
Client -> [binary chunk 3]
|
||||||
|
...
|
||||||
|
Server -> "PROGRESS:1234567:1234567"
|
||||||
|
Server -> "DONE"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Error Messages:**
|
||||||
|
|
||||||
|
| Message | Cause |
|
||||||
|
| --------------------------------- | ---------------------------------- |
|
||||||
|
| `ERROR:Failed to create file` | Cannot create file on SD card |
|
||||||
|
| `ERROR:Invalid START format` | Malformed START message |
|
||||||
|
| `ERROR:No upload in progress` | Binary data received without START |
|
||||||
|
| `ERROR:Write failed - disk full?` | SD card write error |
|
||||||
|
|
||||||
|
**Example with `websocat`:**
|
||||||
|
```bash
|
||||||
|
# Interactive session
|
||||||
|
websocat ws://crosspoint.local:81
|
||||||
|
|
||||||
|
# Then type:
|
||||||
|
START:mybook.epub:1234567:/Books
|
||||||
|
# Wait for READY, then send binary data
|
||||||
|
```
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
- Progress updates are sent every 64KB or at completion
|
||||||
|
- Disconnection during upload will delete the incomplete file
|
||||||
|
- Existing files with the same name will be overwritten
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Network Modes
|
||||||
|
|
||||||
|
The device can operate in two network modes:
|
||||||
|
|
||||||
|
### Station Mode (STA)
|
||||||
|
- Device connects to an existing WiFi network
|
||||||
|
- IP address assigned by router/DHCP
|
||||||
|
- `mode` field in `/api/status` returns `"STA"`
|
||||||
|
- `rssi` field shows signal strength
|
||||||
|
|
||||||
|
### Access Point Mode (AP)
|
||||||
|
- Device creates its own WiFi hotspot
|
||||||
|
- Default IP is typically `192.168.4.1`
|
||||||
|
- `mode` field in `/api/status` returns `"AP"`
|
||||||
|
- `rssi` field returns `0`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- These examples use `crosspoint.local`. If your network does not support mDNS or the address does not resolve, replace it with the specific **IP Address** displayed on your device screen (e.g., `http://192.168.1.102/`).
|
||||||
|
- All paths on the SD card start with `/`
|
||||||
|
- Trailing slashes are automatically stripped (except for root `/`)
|
||||||
|
- The webserver uses chunked transfer encoding for file listings
|
||||||
225
docs/webserver.md
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
# Web Server Guide
|
||||||
|
|
||||||
|
This guide explains how to connect your CrossPoint Reader to WiFi and use the built-in web server to upload EPUB files from your computer or phone.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
CrossPoint Reader includes a built-in web server that allows you to:
|
||||||
|
|
||||||
|
- Upload EPUB files wirelessly from any device on the same WiFi network
|
||||||
|
- Browse and manage files on your device's SD card
|
||||||
|
- Create folders to organize your ebooks
|
||||||
|
- Delete files and folders
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Your CrossPoint Reader device
|
||||||
|
- A WiFi network
|
||||||
|
- A computer, phone, or tablet connected to the **same WiFi network**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 1: Accessing the WiFi Screen
|
||||||
|
|
||||||
|
1. From the main menu or file browser, navigate to the **Settings** screen
|
||||||
|
2. Select the **WiFi** option
|
||||||
|
3. The device will automatically start scanning for available networks
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 2: Connecting to WiFi
|
||||||
|
|
||||||
|
### Viewing Available Networks
|
||||||
|
|
||||||
|
Once the scan completes, you'll see a list of available WiFi networks with the following indicators:
|
||||||
|
|
||||||
|
- **Signal strength bars** (`||||`, `|||`, `||`, `|`) - Shows connection quality
|
||||||
|
- **`*` symbol** - Indicates the network is password-protected (encrypted)
|
||||||
|
- **`+` symbol** - Indicates you have previously saved credentials for this network
|
||||||
|
|
||||||
|
<img src="./images/wifi/wifi_networks.jpeg" height="500">
|
||||||
|
|
||||||
|
### Selecting a Network
|
||||||
|
|
||||||
|
1. Use the **Left/Right** (or **Volume Up/Down**) buttons to navigate through the network list
|
||||||
|
2. Press **Confirm** to select the highlighted network
|
||||||
|
|
||||||
|
### Entering Password (for encrypted networks)
|
||||||
|
|
||||||
|
If the network requires a password:
|
||||||
|
|
||||||
|
1. An on-screen keyboard will appear
|
||||||
|
2. Use the navigation buttons to select characters
|
||||||
|
3. Press **Confirm** to enter each character
|
||||||
|
4. When complete, select the **Done** option on the keyboard
|
||||||
|
|
||||||
|
<img src="./images/wifi/wifi_password.jpeg" height="500">
|
||||||
|
|
||||||
|
**Note:** If you've previously connected to this network, the saved password will be used automatically.
|
||||||
|
|
||||||
|
### Connection Process
|
||||||
|
|
||||||
|
The device will display "Connecting..." while establishing the connection. This typically takes 5-10 seconds.
|
||||||
|
|
||||||
|
### Saving Credentials
|
||||||
|
|
||||||
|
If this is a new network, you'll be prompted to save the password:
|
||||||
|
|
||||||
|
- Select **Yes** to save credentials for automatic connection next time (NOTE: These are stored in plaintext on the device's SD card. Do not use this for sensitive networks.)
|
||||||
|
- Select **No** to connect without saving
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 3: Connection Success
|
||||||
|
|
||||||
|
Once connected, the screen will display:
|
||||||
|
|
||||||
|
- **Network name** (SSID)
|
||||||
|
- **IP Address** (e.g., `192.168.1.102`)
|
||||||
|
- **Web server URL** (e.g., `http://192.168.1.102/`)
|
||||||
|
|
||||||
|
<img src="./images/wifi/wifi_connected.jpeg" height="500">
|
||||||
|
|
||||||
|
**Important:** Make note of the IP address - you'll need this to access the web interface from your computer or phone.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 4: Accessing the Web Interface
|
||||||
|
|
||||||
|
### From a Computer
|
||||||
|
|
||||||
|
1. Ensure your computer is connected to the **same WiFi network** as your CrossPoint Reader
|
||||||
|
2. Open any web browser (Chrome is recommended)
|
||||||
|
3. Type the IP address shown on your device into the browser's address bar
|
||||||
|
- Example: `http://192.168.1.102/`
|
||||||
|
4. Press Enter
|
||||||
|
|
||||||
|
### From a Phone or Tablet
|
||||||
|
|
||||||
|
1. Ensure your phone/tablet is connected to the **same WiFi network** as your CrossPoint Reader
|
||||||
|
2. Open your mobile browser (Safari, Chrome, etc.)
|
||||||
|
3. Type the IP address into the address bar
|
||||||
|
- Example: `http://192.168.1.102/`
|
||||||
|
4. Tap Go
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 5: Using the Web Interface
|
||||||
|
|
||||||
|
### Home Page
|
||||||
|
|
||||||
|
The home page displays:
|
||||||
|
|
||||||
|
- Device status and version information
|
||||||
|
- WiFi connection status
|
||||||
|
- Current IP address
|
||||||
|
- Available memory
|
||||||
|
|
||||||
|
Navigation links:
|
||||||
|
|
||||||
|
- **Home** - Returns to the status page
|
||||||
|
- **File Manager** - Access file management features
|
||||||
|
|
||||||
|
<img src="./images/wifi/webserver_homepage.png" width="600">
|
||||||
|
|
||||||
|
### File Manager
|
||||||
|
|
||||||
|
Click **File Manager** to access file management features.
|
||||||
|
|
||||||
|
#### Browsing Files
|
||||||
|
|
||||||
|
- The file manager displays all files and folders on your SD card
|
||||||
|
- **Folders** are highlighted in yellow with a 📁 icon
|
||||||
|
- **EPUB files** are highlighted in green with a 📗 icon
|
||||||
|
- Click on a folder name to navigate into it
|
||||||
|
- Use the breadcrumb navigation at the top to go back to parent folders
|
||||||
|
|
||||||
|
<img src="./images/wifi/webserver_files.png" width="600">
|
||||||
|
|
||||||
|
#### Uploading EPUB Files
|
||||||
|
|
||||||
|
1. Click the **+ Add** button in the top-right corner
|
||||||
|
2. Select **Upload eBook** from the dropdown menu
|
||||||
|
3. Click **Choose File** and select an `.epub` file from your device
|
||||||
|
4. Click **Upload**
|
||||||
|
5. A progress bar will show the upload status
|
||||||
|
6. The page will automatically refresh when the upload is complete
|
||||||
|
|
||||||
|
**Note:** Only `.epub` files are accepted. Other file types will be rejected.
|
||||||
|
|
||||||
|
<img src="./images/wifi/webserver_upload.png" width="600">
|
||||||
|
|
||||||
|
#### Creating Folders
|
||||||
|
|
||||||
|
1. Click the **+ Add** button in the top-right corner
|
||||||
|
2. Select **New Folder** from the dropdown menu
|
||||||
|
3. Enter a folder name (must not contain characters \" * : < > ? / \\ | and must not be . or ..)
|
||||||
|
4. Click **Create Folder**
|
||||||
|
|
||||||
|
This is useful for organizing your ebooks by genre, author, or series.
|
||||||
|
|
||||||
|
#### Deleting Files and Folders
|
||||||
|
|
||||||
|
1. Click the **🗑️** (trash) icon next to any file or folder
|
||||||
|
2. Confirm the deletion in the popup dialog
|
||||||
|
3. Click **Delete** to permanently remove the item
|
||||||
|
|
||||||
|
**Warning:** Deletion is permanent and cannot be undone!
|
||||||
|
|
||||||
|
**Note:** Folders must be empty before they can be deleted.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Command Line File Management
|
||||||
|
|
||||||
|
For power users, you can manage files directly from your terminal using `curl` while the device is in File Upload mode a detailed documentation can be found [here](./webserver-endpoints.md).
|
||||||
|
|
||||||
|
## Security Notes
|
||||||
|
|
||||||
|
- The web server runs on port 80 (standard HTTP)
|
||||||
|
- **No authentication is required** - anyone on the same network can access the interface
|
||||||
|
- The web server is only accessible while the WiFi screen shows "Connected"
|
||||||
|
- The web server automatically stops when you exit the WiFi screen
|
||||||
|
- For security, only use on trusted private networks
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Technical Details
|
||||||
|
|
||||||
|
- **Supported WiFi:** 2.4GHz networks (802.11 b/g/n)
|
||||||
|
- **Web Server Port:** 80 (HTTP)
|
||||||
|
- **Maximum Upload Size:** Limited by available SD card space
|
||||||
|
- **Supported File Format:** `.epub` only
|
||||||
|
- **Browser Compatibility:** All modern browsers (Chrome, Firefox, Safari, Edge)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tips and Best Practices
|
||||||
|
|
||||||
|
1. **Organize with folders** - Create folders before uploading to keep your library organized
|
||||||
|
2. **Check signal strength** - Stronger signals (`|||` or `||||`) provide faster, more reliable uploads
|
||||||
|
3. **Upload multiple files** - You can upload files one at a time; the page refreshes after each upload
|
||||||
|
4. **Use descriptive names** - Name your folders clearly (e.g., "SciFi", "Mystery", "Non-Fiction")
|
||||||
|
5. **Keep credentials saved** - Save your WiFi password for quick reconnection in the future
|
||||||
|
6. **Exit when done** - Press **Back** to exit the WiFi screen and save battery
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Exiting WiFi Mode
|
||||||
|
|
||||||
|
When you're finished uploading files:
|
||||||
|
|
||||||
|
1. Press the **Back** button on your CrossPoint Reader
|
||||||
|
2. The web server will automatically stop
|
||||||
|
3. WiFi will disconnect to conserve battery
|
||||||
|
4. You'll return to the previous screen
|
||||||
|
|
||||||
|
Your uploaded files will be immediately available in the file browser!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- [User Guide](../USER_GUIDE.md) - General device operation
|
||||||
|
- [Troubleshooting](./troubleshooting.md) - Troubleshooting
|
||||||
|
- [README](../README.md) - Project overview and features
|
||||||
@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
#include <Utf8.h>
|
#include <Utf8.h>
|
||||||
|
|
||||||
inline int min(const int a, const int b) { return a < b ? a : b; }
|
#include <algorithm>
|
||||||
inline int max(const int a, const int b) { return a < b ? b : a; }
|
|
||||||
|
|
||||||
void EpdFont::getTextBounds(const char* string, const int startX, const int startY, int* minX, int* minY, int* maxX,
|
void EpdFont::getTextBounds(const char* string, const int startX, const int startY, int* minX, int* minY, int* maxX,
|
||||||
int* maxY) const {
|
int* maxY) const {
|
||||||
@ -23,8 +22,7 @@ void EpdFont::getTextBounds(const char* string, const int startX, const int star
|
|||||||
const EpdGlyph* glyph = getGlyph(cp);
|
const EpdGlyph* glyph = getGlyph(cp);
|
||||||
|
|
||||||
if (!glyph) {
|
if (!glyph) {
|
||||||
// TODO: Replace with fallback glyph property?
|
glyph = getGlyph(REPLACEMENT_GLYPH);
|
||||||
glyph = getGlyph('?');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!glyph) {
|
if (!glyph) {
|
||||||
@ -32,10 +30,10 @@ void EpdFont::getTextBounds(const char* string, const int startX, const int star
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
*minX = min(*minX, cursorX + glyph->left);
|
*minX = std::min(*minX, cursorX + glyph->left);
|
||||||
*maxX = max(*maxX, cursorX + glyph->left + glyph->width);
|
*maxX = std::max(*maxX, cursorX + glyph->left + glyph->width);
|
||||||
*minY = min(*minY, cursorY + glyph->top - glyph->height);
|
*minY = std::min(*minY, cursorY + glyph->top - glyph->height);
|
||||||
*maxY = max(*maxY, cursorY + glyph->top);
|
*maxY = std::max(*maxY, cursorY + glyph->top);
|
||||||
cursorX += glyph->advanceX;
|
cursorX += glyph->advanceX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,14 +57,28 @@ bool EpdFont::hasPrintableChars(const char* string) const {
|
|||||||
|
|
||||||
const EpdGlyph* EpdFont::getGlyph(const uint32_t cp) const {
|
const EpdGlyph* EpdFont::getGlyph(const uint32_t cp) const {
|
||||||
const EpdUnicodeInterval* intervals = data->intervals;
|
const EpdUnicodeInterval* intervals = data->intervals;
|
||||||
for (int i = 0; i < data->intervalCount; i++) {
|
const int count = data->intervalCount;
|
||||||
const EpdUnicodeInterval* interval = &intervals[i];
|
|
||||||
if (cp >= interval->first && cp <= interval->last) {
|
if (count == 0) return nullptr;
|
||||||
|
|
||||||
|
// Binary search for O(log n) lookup instead of O(n)
|
||||||
|
// Critical for Korean fonts with many unicode intervals
|
||||||
|
int left = 0;
|
||||||
|
int right = count - 1;
|
||||||
|
|
||||||
|
while (left <= right) {
|
||||||
|
const int mid = left + (right - left) / 2;
|
||||||
|
const EpdUnicodeInterval* interval = &intervals[mid];
|
||||||
|
|
||||||
|
if (cp < interval->first) {
|
||||||
|
right = mid - 1;
|
||||||
|
} else if (cp > interval->last) {
|
||||||
|
left = mid + 1;
|
||||||
|
} else {
|
||||||
|
// Found: cp >= interval->first && cp <= interval->last
|
||||||
return &data->glyph[interval->offset + (cp - interval->first)];
|
return &data->glyph[interval->offset + (cp - interval->first)];
|
||||||
}
|
}
|
||||||
if (cp < interval->first) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,37 +1,33 @@
|
|||||||
#include "EpdFontFamily.h"
|
#include "EpdFontFamily.h"
|
||||||
|
|
||||||
const EpdFont* EpdFontFamily::getFont(const EpdFontStyle style) const {
|
const EpdFont* EpdFontFamily::getFont(const Style style) const {
|
||||||
if (style == BOLD && bold) {
|
// Extract font style bits (ignore UNDERLINE bit for font selection)
|
||||||
|
const bool hasBold = (style & BOLD) != 0;
|
||||||
|
const bool hasItalic = (style & ITALIC) != 0;
|
||||||
|
|
||||||
|
if (hasBold && hasItalic) {
|
||||||
|
if (boldItalic) return boldItalic;
|
||||||
|
if (bold) return bold;
|
||||||
|
if (italic) return italic;
|
||||||
|
} else if (hasBold && bold) {
|
||||||
return bold;
|
return bold;
|
||||||
}
|
} else if (hasItalic && italic) {
|
||||||
if (style == ITALIC && italic) {
|
|
||||||
return italic;
|
return italic;
|
||||||
}
|
}
|
||||||
if (style == BOLD_ITALIC) {
|
|
||||||
if (boldItalic) {
|
|
||||||
return boldItalic;
|
|
||||||
}
|
|
||||||
if (bold) {
|
|
||||||
return bold;
|
|
||||||
}
|
|
||||||
if (italic) {
|
|
||||||
return italic;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return regular;
|
return regular;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EpdFontFamily::getTextDimensions(const char* string, int* w, int* h, const EpdFontStyle style) const {
|
void EpdFontFamily::getTextDimensions(const char* string, int* w, int* h, const Style style) const {
|
||||||
getFont(style)->getTextDimensions(string, w, h);
|
getFont(style)->getTextDimensions(string, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EpdFontFamily::hasPrintableChars(const char* string, const EpdFontStyle style) const {
|
bool EpdFontFamily::hasPrintableChars(const char* string, const Style style) const {
|
||||||
return getFont(style)->hasPrintableChars(string);
|
return getFont(style)->hasPrintableChars(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
const EpdFontData* EpdFontFamily::getData(const EpdFontStyle style) const { return getFont(style)->data; }
|
const EpdFontData* EpdFontFamily::getData(const Style style) const { return getFont(style)->data; }
|
||||||
|
|
||||||
const EpdGlyph* EpdFontFamily::getGlyph(const uint32_t cp, const EpdFontStyle style) const {
|
const EpdGlyph* EpdFontFamily::getGlyph(const uint32_t cp, const Style style) const {
|
||||||
return getFont(style)->getGlyph(cp);
|
return getFont(style)->getGlyph(cp);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,24 +1,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "EpdFont.h"
|
#include "EpdFont.h"
|
||||||
|
|
||||||
enum EpdFontStyle { REGULAR, BOLD, ITALIC, BOLD_ITALIC };
|
|
||||||
|
|
||||||
class EpdFontFamily {
|
class EpdFontFamily {
|
||||||
|
public:
|
||||||
|
enum Style : uint8_t { REGULAR = 0, BOLD = 1, ITALIC = 2, BOLD_ITALIC = 3, UNDERLINE = 4 };
|
||||||
|
|
||||||
|
explicit EpdFontFamily(const EpdFont* regular, const EpdFont* bold = nullptr, const EpdFont* italic = nullptr,
|
||||||
|
const EpdFont* boldItalic = nullptr)
|
||||||
|
: regular(regular), bold(bold), italic(italic), boldItalic(boldItalic) {}
|
||||||
|
~EpdFontFamily() = default;
|
||||||
|
void getTextDimensions(const char* string, int* w, int* h, Style style = REGULAR) const;
|
||||||
|
bool hasPrintableChars(const char* string, Style style = REGULAR) const;
|
||||||
|
const EpdFontData* getData(Style style = REGULAR) const;
|
||||||
|
const EpdGlyph* getGlyph(uint32_t cp, Style style = REGULAR) const;
|
||||||
|
|
||||||
|
private:
|
||||||
const EpdFont* regular;
|
const EpdFont* regular;
|
||||||
const EpdFont* bold;
|
const EpdFont* bold;
|
||||||
const EpdFont* italic;
|
const EpdFont* italic;
|
||||||
const EpdFont* boldItalic;
|
const EpdFont* boldItalic;
|
||||||
|
|
||||||
const EpdFont* getFont(EpdFontStyle style) const;
|
const EpdFont* getFont(Style style) const;
|
||||||
|
|
||||||
public:
|
|
||||||
explicit EpdFontFamily(const EpdFont* regular, const EpdFont* bold = nullptr, const EpdFont* italic = nullptr,
|
|
||||||
const EpdFont* boldItalic = nullptr)
|
|
||||||
: regular(regular), bold(bold), italic(italic), boldItalic(boldItalic) {}
|
|
||||||
~EpdFontFamily() = default;
|
|
||||||
void getTextDimensions(const char* string, int* w, int* h, EpdFontStyle style = REGULAR) const;
|
|
||||||
bool hasPrintableChars(const char* string, EpdFontStyle style = REGULAR) const;
|
|
||||||
|
|
||||||
const EpdFontData* getData(EpdFontStyle style = REGULAR) const;
|
|
||||||
const EpdGlyph* getGlyph(uint32_t cp, EpdFontStyle style = REGULAR) const;
|
|
||||||
};
|
};
|
||||||
|
|||||||
55
lib/EpdFont/builtinFonts/all.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <builtinFonts/bookerly_12_bold.h>
|
||||||
|
#include <builtinFonts/bookerly_12_bolditalic.h>
|
||||||
|
#include <builtinFonts/bookerly_12_italic.h>
|
||||||
|
#include <builtinFonts/bookerly_12_regular.h>
|
||||||
|
#include <builtinFonts/bookerly_14_bold.h>
|
||||||
|
#include <builtinFonts/bookerly_14_bolditalic.h>
|
||||||
|
#include <builtinFonts/bookerly_14_italic.h>
|
||||||
|
#include <builtinFonts/bookerly_14_regular.h>
|
||||||
|
#include <builtinFonts/bookerly_16_bold.h>
|
||||||
|
#include <builtinFonts/bookerly_16_bolditalic.h>
|
||||||
|
#include <builtinFonts/bookerly_16_italic.h>
|
||||||
|
#include <builtinFonts/bookerly_16_regular.h>
|
||||||
|
#include <builtinFonts/bookerly_18_bold.h>
|
||||||
|
#include <builtinFonts/bookerly_18_bolditalic.h>
|
||||||
|
#include <builtinFonts/bookerly_18_italic.h>
|
||||||
|
#include <builtinFonts/bookerly_18_regular.h>
|
||||||
|
#include <builtinFonts/notosans_8_regular.h>
|
||||||
|
#include <builtinFonts/notosans_12_bold.h>
|
||||||
|
#include <builtinFonts/notosans_12_bolditalic.h>
|
||||||
|
#include <builtinFonts/notosans_12_italic.h>
|
||||||
|
#include <builtinFonts/notosans_12_regular.h>
|
||||||
|
#include <builtinFonts/notosans_14_bold.h>
|
||||||
|
#include <builtinFonts/notosans_14_bolditalic.h>
|
||||||
|
#include <builtinFonts/notosans_14_italic.h>
|
||||||
|
#include <builtinFonts/notosans_14_regular.h>
|
||||||
|
#include <builtinFonts/notosans_16_bold.h>
|
||||||
|
#include <builtinFonts/notosans_16_bolditalic.h>
|
||||||
|
#include <builtinFonts/notosans_16_italic.h>
|
||||||
|
#include <builtinFonts/notosans_16_regular.h>
|
||||||
|
#include <builtinFonts/notosans_18_bold.h>
|
||||||
|
#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>
|
||||||
4086
lib/EpdFont/builtinFonts/bookerly_12_bold.h
Normal file
4168
lib/EpdFont/builtinFonts/bookerly_12_bolditalic.h
Normal file
3933
lib/EpdFont/builtinFonts/bookerly_12_italic.h
Normal file
3824
lib/EpdFont/builtinFonts/bookerly_12_regular.h
Normal file
5087
lib/EpdFont/builtinFonts/bookerly_14_bold.h
Normal file
5276
lib/EpdFont/builtinFonts/bookerly_14_bolditalic.h
Normal file
4950
lib/EpdFont/builtinFonts/bookerly_14_italic.h
Normal file
4812
lib/EpdFont/builtinFonts/bookerly_14_regular.h
Normal file
6236
lib/EpdFont/builtinFonts/bookerly_16_bold.h
Normal file
6448
lib/EpdFont/builtinFonts/bookerly_16_bolditalic.h
Normal file
6064
lib/EpdFont/builtinFonts/bookerly_16_italic.h
Normal file
5901
lib/EpdFont/builtinFonts/bookerly_16_regular.h
Normal file
7964
lib/EpdFont/builtinFonts/bookerly_18_bold.h
Normal file
8172
lib/EpdFont/builtinFonts/bookerly_18_bolditalic.h
Normal file
7685
lib/EpdFont/builtinFonts/bookerly_18_italic.h
Normal file
7507
lib/EpdFont/builtinFonts/bookerly_18_regular.h
Normal file
4090
lib/EpdFont/builtinFonts/notosans_12_bold.h
Normal file
4297
lib/EpdFont/builtinFonts/notosans_12_bolditalic.h
Normal file
4010
lib/EpdFont/builtinFonts/notosans_12_italic.h
Normal file
3807
lib/EpdFont/builtinFonts/notosans_12_regular.h
Normal file
5212
lib/EpdFont/builtinFonts/notosans_14_bold.h
Normal file
5479
lib/EpdFont/builtinFonts/notosans_14_bolditalic.h
Normal file
5078
lib/EpdFont/builtinFonts/notosans_14_italic.h
Normal file
4828
lib/EpdFont/builtinFonts/notosans_14_regular.h
Normal file
6470
lib/EpdFont/builtinFonts/notosans_16_bold.h
Normal file
6821
lib/EpdFont/builtinFonts/notosans_16_bolditalic.h
Normal file
6281
lib/EpdFont/builtinFonts/notosans_16_italic.h
Normal file
5933
lib/EpdFont/builtinFonts/notosans_16_regular.h
Normal file
7823
lib/EpdFont/builtinFonts/notosans_18_bold.h
Normal file
8278
lib/EpdFont/builtinFonts/notosans_18_bolditalic.h
Normal file
7629
lib/EpdFont/builtinFonts/notosans_18_italic.h
Normal file
7210
lib/EpdFont/builtinFonts/notosans_18_regular.h
Normal file
1622
lib/EpdFont/builtinFonts/notosans_8_regular.h
Normal file
3518
lib/EpdFont/builtinFonts/opendyslexic_10_bold.h
Normal file
4092
lib/EpdFont/builtinFonts/opendyslexic_10_bolditalic.h
Normal file
3656
lib/EpdFont/builtinFonts/opendyslexic_10_italic.h
Normal file
3188
lib/EpdFont/builtinFonts/opendyslexic_10_regular.h
Normal file
4685
lib/EpdFont/builtinFonts/opendyslexic_12_bold.h
Normal file
5506
lib/EpdFont/builtinFonts/opendyslexic_12_bolditalic.h
Normal file
4778
lib/EpdFont/builtinFonts/opendyslexic_12_italic.h
Normal file
4173
lib/EpdFont/builtinFonts/opendyslexic_12_regular.h
Normal file
6049
lib/EpdFont/builtinFonts/opendyslexic_14_bold.h
Normal file
7095
lib/EpdFont/builtinFonts/opendyslexic_14_bolditalic.h
Normal file
6144
lib/EpdFont/builtinFonts/opendyslexic_14_italic.h
Normal file
5247
lib/EpdFont/builtinFonts/opendyslexic_14_regular.h
Normal file
2591
lib/EpdFont/builtinFonts/opendyslexic_8_bold.h
Normal file
2924
lib/EpdFont/builtinFonts/opendyslexic_8_bolditalic.h
Normal file
2691
lib/EpdFont/builtinFonts/opendyslexic_8_italic.h
Normal file
2372
lib/EpdFont/builtinFonts/opendyslexic_8_regular.h
Normal file
@ -1,184 +0,0 @@
|
|||||||
/**
|
|
||||||
* generated by fontconvert.py
|
|
||||||
* name: pixelarial14
|
|
||||||
* size: 8
|
|
||||||
* mode: 1-bit
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#include "EpdFontData.h"
|
|
||||||
|
|
||||||
static const uint8_t pixelarial14Bitmaps[1145] = {
|
|
||||||
0xFF, 0xFF, 0xFA, 0xC0, 0xFF, 0xFF, 0xFB, 0x18, 0x63, 0x0C, 0x63, 0x98, 0xCF, 0xFF, 0xFF, 0x9C, 0xE3, 0x18, 0xFF,
|
|
||||||
0xFF, 0xFB, 0x9C, 0x63, 0x0C, 0x60, 0x30, 0xF3, 0xF7, 0xBF, 0x1F, 0x1F, 0x9B, 0x37, 0xEF, 0xFB, 0xC3, 0x00, 0x70,
|
|
||||||
0x67, 0xCE, 0x36, 0x61, 0xB3, 0x0D, 0xB0, 0x7D, 0x81, 0xDD, 0xC0, 0xDE, 0x07, 0x98, 0xEC, 0xC6, 0x66, 0x33, 0xF3,
|
|
||||||
0x07, 0x00, 0x3E, 0x0F, 0xE1, 0x8C, 0x31, 0x86, 0x60, 0xFC, 0x1E, 0x03, 0xE0, 0xC7, 0x98, 0xF3, 0x0E, 0x7F, 0xE7,
|
|
||||||
0xE6, 0xFF, 0xE0, 0x37, 0x66, 0xCC, 0xCC, 0xCC, 0xCC, 0xC6, 0x67, 0x30, 0xCE, 0x66, 0x33, 0x33, 0x33, 0x33, 0x36,
|
|
||||||
0x6E, 0xC0, 0x6F, 0xF6, 0xFB, 0x08, 0x0C, 0x06, 0x03, 0x0F, 0xFF, 0xFC, 0x60, 0x30, 0x18, 0x04, 0x00, 0xBF, 0xC0,
|
|
||||||
0x03, 0xEF, 0x80, 0xB0, 0x18, 0x61, 0x8C, 0x30, 0xC7, 0x18, 0x61, 0x8E, 0x30, 0xC0, 0x7E, 0xFF, 0xC3, 0xC3, 0xC3,
|
|
||||||
0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0x7E, 0x37, 0xFF, 0x33, 0x33, 0x33, 0x33, 0x30, 0x7E, 0xFF, 0xC3, 0xC3,
|
|
||||||
0x03, 0x03, 0x07, 0x06, 0x18, 0x38, 0x70, 0xFF, 0xFF, 0x7E, 0xFF, 0xC3, 0xC3, 0x03, 0x3F, 0x3F, 0x03, 0x03, 0xC3,
|
|
||||||
0xC3, 0xFF, 0x7E, 0x03, 0x03, 0x83, 0xC3, 0x63, 0x31, 0x99, 0xCC, 0xC6, 0xC3, 0x7F, 0xFF, 0xE0, 0x60, 0x30, 0x7F,
|
|
||||||
0x7F, 0xE0, 0xC0, 0xFE, 0xFF, 0xC3, 0x03, 0x03, 0xC3, 0xC7, 0xFE, 0x7E, 0x7E, 0xFF, 0xC3, 0xC0, 0xC0, 0xFE, 0xFF,
|
|
||||||
0xE3, 0xC3, 0xC3, 0xC3, 0xFF, 0x7E, 0xFF, 0xFF, 0x07, 0x06, 0x06, 0x0E, 0x18, 0x18, 0x18, 0x38, 0x30, 0x30, 0x30,
|
|
||||||
0x7E, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0x7E, 0x7E, 0xFF, 0xC3, 0xC3, 0xC3, 0xC7,
|
|
||||||
0xFF, 0x7B, 0x03, 0x03, 0xC7, 0xFE, 0x78, 0xB0, 0x00, 0x2C, 0xB0, 0x00, 0x2F, 0xF0, 0x03, 0x03, 0x1E, 0x7E, 0xF0,
|
|
||||||
0xC0, 0x70, 0x3E, 0x0F, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFE, 0x80, 0xC0, 0x70, 0x7E, 0x0F, 0x03, 0x1E, 0x7C,
|
|
||||||
0xF0, 0xC0, 0x7E, 0xFF, 0xC3, 0xC3, 0x03, 0x07, 0x0E, 0x18, 0x30, 0x30, 0x30, 0x10, 0x30, 0x3F, 0x87, 0xFE, 0xEF,
|
|
||||||
0x7D, 0xF3, 0xF1, 0xBF, 0x1B, 0xF3, 0xBF, 0xFF, 0xDF, 0xE6, 0x00, 0x7F, 0x03, 0xF0, 0x06, 0x00, 0xF0, 0x1B, 0x01,
|
|
||||||
0xB0, 0x1B, 0x03, 0xB8, 0x31, 0x83, 0x18, 0x7F, 0xE7, 0xFE, 0xE0, 0x7C, 0x03, 0xC0, 0x30, 0xFF, 0x7F, 0xF0, 0x78,
|
|
||||||
0x3C, 0x1F, 0xFF, 0xFF, 0x83, 0xC1, 0xE0, 0xF0, 0x7F, 0xFF, 0xF0, 0x3F, 0x0F, 0xF3, 0x87, 0x60, 0x3C, 0x01, 0x80,
|
|
||||||
0x30, 0x06, 0x00, 0xC0, 0x18, 0x0F, 0x87, 0x3F, 0xC3, 0xF0, 0xFF, 0x1F, 0xF3, 0x07, 0x60, 0x3C, 0x07, 0x80, 0xF0,
|
|
||||||
0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x07, 0x7F, 0xCF, 0xF0, 0xFF, 0xFF, 0xF0, 0x18, 0x0C, 0x07, 0xFF, 0xFF, 0x80, 0xC0,
|
|
||||||
0x60, 0x30, 0x1F, 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0x18, 0x0C, 0x07, 0xFB, 0xFD, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C,
|
|
||||||
0x00, 0x3F, 0x87, 0xFE, 0xE0, 0x7C, 0x03, 0xC0, 0x0C, 0x00, 0xC1, 0xFC, 0x1F, 0xC0, 0x3C, 0x03, 0xE0, 0x77, 0xFE,
|
|
||||||
0x3F, 0x80, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1F, 0xFF, 0xFF, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x18, 0xFF, 0xFF,
|
|
||||||
0xFF, 0xC0, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x07, 0x8F, 0x1F, 0xF7, 0x80, 0xC0, 0x78, 0x3B, 0x0E, 0x61,
|
|
||||||
0x8C, 0x61, 0x9C, 0x3F, 0x87, 0xB0, 0xE3, 0x18, 0x63, 0x0E, 0x60, 0xEC, 0x06, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06,
|
|
||||||
0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x1F, 0xFF, 0xF8, 0xC0, 0x3E, 0x07, 0xE0, 0x7E, 0x07, 0xF1, 0xBF, 0x1B, 0xFB,
|
|
||||||
0xBD, 0xB3, 0xDB, 0x3D, 0xB3, 0xCF, 0x3C, 0x63, 0xC6, 0x30, 0xC1, 0xF0, 0xFC, 0x7E, 0x3F, 0x1F, 0xCF, 0x67, 0xBB,
|
|
||||||
0xC7, 0xE3, 0xF1, 0xF8, 0x7C, 0x18, 0x3F, 0x87, 0xFE, 0xE0, 0x7C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0,
|
|
||||||
0x3C, 0x03, 0xE0, 0x77, 0xFE, 0x3F, 0x80, 0xFF, 0x7F, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0xFF, 0xFE, 0xC0, 0x60, 0x30,
|
|
||||||
0x18, 0x0C, 0x00, 0x3F, 0x87, 0xFE, 0xE0, 0x7C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x36, 0xE3,
|
|
||||||
0xE7, 0xFF, 0x3F, 0x70, 0xFF, 0x9F, 0xFF, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xFF, 0xFF, 0xFC, 0xC6, 0x18, 0xE3, 0x0E,
|
|
||||||
0x60, 0xEC, 0x06, 0x7F, 0x7F, 0xF0, 0x78, 0x3C, 0x07, 0xC1, 0xFE, 0x0F, 0x01, 0xE0, 0xF0, 0x7F, 0xF7, 0xF0, 0xFF,
|
|
||||||
0xFF, 0xC6, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC1, 0xE0, 0xF0, 0x78, 0x3C,
|
|
||||||
0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF8, 0xEF, 0xE3, 0xE0, 0xC0, 0x3C, 0x03, 0xE0, 0x76, 0x06, 0x60, 0x67, 0x1C,
|
|
||||||
0x31, 0x83, 0x18, 0x1B, 0x01, 0xB0, 0x0F, 0x00, 0x60, 0x06, 0x00, 0xC1, 0x81, 0xE1, 0xF0, 0xF8, 0xD8, 0xEC, 0x6C,
|
|
||||||
0x66, 0x36, 0x33, 0x1B, 0x19, 0xDD, 0xDC, 0x6C, 0x78, 0x36, 0x3C, 0x1B, 0x1E, 0x0F, 0x8F, 0x03, 0x03, 0x01, 0x81,
|
|
||||||
0x80, 0xC0, 0x7C, 0x39, 0x86, 0x30, 0xC3, 0x30, 0x7E, 0x07, 0x80, 0xF0, 0x33, 0x0E, 0x31, 0x86, 0x70, 0xEC, 0x06,
|
|
||||||
0xC0, 0x3E, 0x07, 0x70, 0xE3, 0x18, 0x31, 0x83, 0xB8, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06,
|
|
||||||
0x00, 0xFF, 0xFF, 0xF8, 0x0E, 0x01, 0x80, 0x30, 0x0E, 0x03, 0x80, 0xC0, 0x30, 0x06, 0x01, 0xC0, 0x7F, 0xEF, 0xFE,
|
|
||||||
0xFF, 0x6D, 0xB6, 0xDB, 0x6D, 0xB7, 0xE0, 0xC3, 0x0E, 0x18, 0x61, 0x87, 0x0C, 0x30, 0xC3, 0x86, 0x18, 0xFD, 0xB6,
|
|
||||||
0xDB, 0x6D, 0xB6, 0xDF, 0xE0, 0x30, 0xF1, 0xE3, 0xC7, 0x9D, 0xF1, 0x80, 0xFF, 0xDF, 0xFC, 0xCE, 0x73, 0x00, 0x7C,
|
|
||||||
0x7E, 0xC3, 0x83, 0x3F, 0x3F, 0x63, 0xC3, 0xC7, 0xFF, 0x7B, 0xC0, 0xC0, 0xDC, 0xFE, 0xE3, 0xE3, 0xC3, 0xC3, 0xC3,
|
|
||||||
0xC3, 0xE3, 0xFF, 0xFE, 0x78, 0xF3, 0x1E, 0x3C, 0x18, 0x30, 0x60, 0xC7, 0xFD, 0xE0, 0x03, 0x03, 0x7B, 0x7B, 0xC7,
|
|
||||||
0xC7, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0xFF, 0x7B, 0x7C, 0x7E, 0xC3, 0xC3, 0xFF, 0xFF, 0xC0, 0xC0, 0xC3, 0xFF, 0x7E,
|
|
||||||
0x39, 0xEF, 0xBE, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x60, 0x7B, 0x7B, 0xC7, 0xC7, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7,
|
|
||||||
0xFF, 0x7B, 0x03, 0xC3, 0xFF, 0x7E, 0xC0, 0xC0, 0xDC, 0xFE, 0xE3, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
|
|
||||||
0xFB, 0xFF, 0xFF, 0xC0, 0x33, 0x13, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xE0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC6, 0xCE,
|
|
||||||
0xF8, 0xF0, 0xF8, 0xCE, 0xC6, 0xC7, 0xC3, 0xFF, 0xFF, 0xFF, 0xC0, 0x98, 0xCF, 0x9E, 0xE7, 0x3E, 0x73, 0xC6, 0x3C,
|
|
||||||
0x63, 0xC6, 0x3C, 0x63, 0xC6, 0x3C, 0x63, 0xC6, 0x30, 0x9C, 0xFE, 0xE3, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
|
|
||||||
0xC3, 0x7C, 0x7E, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0x7E, 0x9C, 0xFE, 0xE3, 0xE3, 0xC3, 0xC3, 0xC3,
|
|
||||||
0xC3, 0xE3, 0xFF, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0x7B, 0x7B, 0xC7, 0xC7, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0xFF, 0x7B,
|
|
||||||
0x03, 0x03, 0x03, 0x03, 0x9B, 0xEE, 0x38, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x00, 0x78, 0xF3, 0x1E, 0x3F, 0x8F, 0x81,
|
|
||||||
0x83, 0xC7, 0xFD, 0xE0, 0x61, 0x8F, 0xBE, 0x61, 0x86, 0x18, 0x61, 0x86, 0x1E, 0x78, 0x83, 0xC3, 0xC3, 0xC3, 0xC3,
|
|
||||||
0xC3, 0xC3, 0xC3, 0xC7, 0xFF, 0x7B, 0x80, 0xE0, 0xF0, 0x7C, 0x76, 0x33, 0x18, 0xD8, 0x6C, 0x3E, 0x0C, 0x06, 0x00,
|
|
||||||
0x84, 0x3C, 0x63, 0xC6, 0x3E, 0xF7, 0x7B, 0x67, 0xB6, 0x7B, 0x67, 0xB6, 0x7B, 0xC3, 0x18, 0x31, 0x80, 0x83, 0xC3,
|
|
||||||
0x66, 0x66, 0x7E, 0x38, 0x38, 0x7E, 0x66, 0xE7, 0xC3, 0x80, 0xE0, 0xF0, 0x7C, 0x76, 0x33, 0x18, 0xD8, 0x6C, 0x36,
|
|
||||||
0x1F, 0x06, 0x03, 0x01, 0x83, 0xC1, 0xC0, 0xFF, 0xFF, 0x06, 0x0E, 0x18, 0x18, 0x30, 0x30, 0x70, 0xFF, 0xFF, 0x37,
|
|
||||||
0x66, 0x66, 0x66, 0xCE, 0x66, 0x66, 0x67, 0x30, 0xFF, 0xFF, 0xFF, 0xC0, 0xCE, 0x66, 0x66, 0x66, 0x37, 0x66, 0x66,
|
|
||||||
0x6E, 0xC0, 0xC3, 0x99, 0xFF, 0xF9, 0xB8, 0x30, 0xDB, 0x66, 0xC0, 0x6D, 0xBD, 0x00, 0x7B, 0xEF, 0x3C, 0xF2, 0xC0,
|
|
||||||
0x79, 0xE7, 0x9E, 0xF2, 0xC0,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const EpdGlyph pixelarial14Glyphs[] = {
|
|
||||||
{0, 0, 4, 0, 0, 0, 0}, //
|
|
||||||
{2, 13, 3, 0, 13, 4, 0}, // !
|
|
||||||
{4, 6, 5, 0, 13, 3, 4}, // "
|
|
||||||
{11, 13, 12, 0, 13, 18, 7}, // #
|
|
||||||
{7, 13, 8, 0, 13, 12, 25}, // $
|
|
||||||
{13, 13, 14, 0, 13, 22, 37}, // %
|
|
||||||
{11, 13, 12, 0, 13, 18, 59}, // &
|
|
||||||
{2, 6, 3, 0, 13, 2, 77}, // '
|
|
||||||
{4, 17, 5, 0, 13, 9, 79}, // (
|
|
||||||
{4, 17, 5, 0, 13, 9, 88}, // )
|
|
||||||
{4, 6, 5, 0, 13, 3, 97}, // *
|
|
||||||
{9, 10, 10, 0, 11, 12, 100}, // +
|
|
||||||
{2, 5, 3, 0, 2, 2, 112}, // ,
|
|
||||||
{6, 3, 6, 0, 6, 3, 114}, // -
|
|
||||||
{2, 2, 3, 0, 2, 1, 117}, // .
|
|
||||||
{6, 13, 6, 0, 13, 10, 118}, // /
|
|
||||||
{8, 13, 9, 0, 13, 13, 128}, // 0
|
|
||||||
{4, 13, 5, 0, 13, 7, 141}, // 1
|
|
||||||
{8, 13, 9, 0, 13, 13, 148}, // 2
|
|
||||||
{8, 13, 9, 0, 13, 13, 161}, // 3
|
|
||||||
{9, 13, 10, 0, 13, 15, 174}, // 4
|
|
||||||
{8, 13, 9, 0, 13, 13, 189}, // 5
|
|
||||||
{8, 13, 9, 0, 13, 13, 202}, // 6
|
|
||||||
{8, 13, 9, 0, 13, 13, 215}, // 7
|
|
||||||
{8, 13, 9, 0, 13, 13, 228}, // 8
|
|
||||||
{8, 13, 9, 0, 13, 13, 241}, // 9
|
|
||||||
{2, 11, 3, 0, 11, 3, 254}, // :
|
|
||||||
{2, 14, 3, 0, 11, 4, 257}, // ;
|
|
||||||
{8, 10, 9, 0, 11, 10, 261}, // <
|
|
||||||
{8, 6, 9, 0, 9, 6, 271}, // =
|
|
||||||
{8, 10, 9, 0, 11, 10, 277}, // >
|
|
||||||
{8, 13, 9, 0, 13, 13, 287}, // ?
|
|
||||||
{12, 12, 13, 0, 9, 18, 300}, // @
|
|
||||||
{12, 13, 13, 0, 13, 20, 318}, // A
|
|
||||||
{9, 13, 10, 0, 13, 15, 338}, // B
|
|
||||||
{11, 13, 12, 0, 13, 18, 353}, // C
|
|
||||||
{11, 13, 12, 0, 13, 18, 371}, // D
|
|
||||||
{9, 13, 10, 0, 13, 15, 389}, // E
|
|
||||||
{9, 13, 10, 0, 13, 15, 404}, // F
|
|
||||||
{12, 13, 13, 0, 13, 20, 419}, // G
|
|
||||||
{9, 13, 10, 0, 13, 15, 439}, // H
|
|
||||||
{2, 13, 3, 0, 13, 4, 454}, // I
|
|
||||||
{7, 13, 8, 0, 13, 12, 458}, // J
|
|
||||||
{11, 13, 12, 0, 13, 18, 470}, // K
|
|
||||||
{9, 13, 10, 0, 13, 15, 488}, // L
|
|
||||||
{12, 13, 13, 0, 13, 20, 503}, // M
|
|
||||||
{9, 13, 10, 0, 13, 15, 523}, // N
|
|
||||||
{12, 13, 13, 0, 13, 20, 538}, // O
|
|
||||||
{9, 13, 10, 0, 13, 15, 558}, // P
|
|
||||||
{12, 13, 13, 0, 13, 20, 573}, // Q
|
|
||||||
{11, 13, 12, 0, 13, 18, 593}, // R
|
|
||||||
{9, 13, 10, 0, 13, 15, 611}, // S
|
|
||||||
{9, 13, 10, 0, 13, 15, 626}, // T
|
|
||||||
{9, 13, 10, 0, 13, 15, 641}, // U
|
|
||||||
{12, 13, 13, 0, 13, 20, 656}, // V
|
|
||||||
{17, 13, 18, 0, 13, 28, 676}, // W
|
|
||||||
{11, 13, 12, 0, 13, 18, 704}, // X
|
|
||||||
{12, 13, 13, 0, 13, 20, 722}, // Y
|
|
||||||
{11, 13, 12, 0, 13, 18, 742}, // Z
|
|
||||||
{3, 17, 4, 0, 13, 7, 760}, // [
|
|
||||||
{6, 13, 6, 0, 13, 10, 767}, // <backslash>
|
|
||||||
{3, 17, 4, 0, 13, 7, 777}, // ]
|
|
||||||
{7, 7, 8, 0, 13, 7, 784}, // ^
|
|
||||||
{11, 2, 12, 0, 2, 3, 791}, // _
|
|
||||||
{4, 5, 5, 0, 13, 3, 794}, // `
|
|
||||||
{8, 11, 9, 0, 11, 11, 797}, // a
|
|
||||||
{8, 13, 9, 0, 13, 13, 808}, // b
|
|
||||||
{7, 11, 8, 0, 11, 10, 821}, // c
|
|
||||||
{8, 13, 9, 0, 13, 13, 831}, // d
|
|
||||||
{8, 11, 9, 0, 11, 11, 844}, // e
|
|
||||||
{6, 13, 6, 0, 13, 10, 855}, // f
|
|
||||||
{8, 15, 9, 0, 11, 15, 865}, // g
|
|
||||||
{8, 13, 9, 0, 13, 13, 880}, // h
|
|
||||||
{2, 13, 3, 0, 13, 4, 893}, // i
|
|
||||||
{4, 17, 5, 0, 13, 9, 897}, // j
|
|
||||||
{8, 13, 9, 0, 13, 13, 906}, // k
|
|
||||||
{2, 13, 3, 0, 13, 4, 919}, // l
|
|
||||||
{12, 11, 13, 0, 11, 17, 923}, // m
|
|
||||||
{8, 11, 9, 0, 11, 11, 940}, // n
|
|
||||||
{8, 11, 9, 0, 11, 11, 951}, // o
|
|
||||||
{8, 15, 9, 0, 11, 15, 962}, // p
|
|
||||||
{8, 15, 9, 0, 11, 15, 977}, // q
|
|
||||||
{6, 11, 6, 0, 11, 9, 992}, // r
|
|
||||||
{7, 11, 8, 0, 11, 10, 1001}, // s
|
|
||||||
{6, 13, 6, 0, 13, 10, 1011}, // t
|
|
||||||
{8, 11, 9, 0, 11, 11, 1021}, // u
|
|
||||||
{9, 11, 10, 0, 11, 13, 1032}, // v
|
|
||||||
{12, 11, 13, 0, 11, 17, 1045}, // w
|
|
||||||
{8, 11, 9, 0, 11, 11, 1062}, // x
|
|
||||||
{9, 15, 10, 0, 11, 17, 1073}, // y
|
|
||||||
{8, 11, 9, 0, 11, 11, 1090}, // z
|
|
||||||
{4, 17, 5, 0, 13, 9, 1101}, // {
|
|
||||||
{2, 13, 3, 0, 13, 4, 1110}, // |
|
|
||||||
{4, 17, 5, 0, 13, 9, 1114}, // }
|
|
||||||
{11, 4, 12, 0, 9, 6, 1123}, // ~
|
|
||||||
{3, 6, 4, 0, 13, 3, 1129}, // ‘
|
|
||||||
{3, 6, 4, 0, 13, 3, 1132}, // ’
|
|
||||||
{6, 6, 6, 0, 13, 5, 1135}, // “
|
|
||||||
{6, 6, 6, 0, 13, 5, 1140}, // ”
|
|
||||||
};
|
|
||||||
|
|
||||||
static const EpdUnicodeInterval pixelarial14Intervals[] = {
|
|
||||||
{0x20, 0x7E, 0x0},
|
|
||||||
{0x2018, 0x2019, 0x5F},
|
|
||||||
{0x201C, 0x201D, 0x61},
|
|
||||||
};
|
|
||||||
|
|
||||||
static const EpdFontData pixelarial14 = {
|
|
||||||
pixelarial14Bitmaps, pixelarial14Glyphs, pixelarial14Intervals, 3, 17, 13, -4, false,
|
|
||||||
};
|
|
||||||
BIN
lib/EpdFont/builtinFonts/source/Bookerly/Bookerly-Bold.ttf
Executable file
BIN
lib/EpdFont/builtinFonts/source/Bookerly/Bookerly-BoldItalic.ttf
Executable file
BIN
lib/EpdFont/builtinFonts/source/Bookerly/Bookerly-Italic.ttf
Executable file
BIN
lib/EpdFont/builtinFonts/source/Bookerly/Bookerly-Regular.ttf
Executable file
BIN
lib/EpdFont/builtinFonts/source/NotoSans/NotoSans-Bold.ttf
Normal file
BIN
lib/EpdFont/builtinFonts/source/NotoSans/NotoSans-BoldItalic.ttf
Normal file
BIN
lib/EpdFont/builtinFonts/source/NotoSans/NotoSans-Italic.ttf
Normal file
BIN
lib/EpdFont/builtinFonts/source/NotoSans/NotoSans-Regular.ttf
Normal file
93
lib/EpdFont/builtinFonts/source/NotoSans/OFL.txt
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic)
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
https://openfontlicense.org
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
94
lib/EpdFont/builtinFonts/source/OpenDyslexic/OFL.txt
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
Copyright (c) 2019-07-29, Abbie Gonzalez (https://abbiecod.es|support@abbiecod.es),
|
||||||
|
with Reserved Font Name OpenDyslexic.
|
||||||
|
Copyright (c) 12/2012 - 2019
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
96
lib/EpdFont/builtinFonts/source/Ubuntu/UFL.txt
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
-------------------------------
|
||||||
|
UBUNTU FONT LICENCE Version 1.0
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
This licence allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely. The fonts, including any derivative works, can be
|
||||||
|
bundled, embedded, and redistributed provided the terms of this licence
|
||||||
|
are met. The fonts and derivatives, however, cannot be released under
|
||||||
|
any other licence. The requirement for fonts to remain under this
|
||||||
|
licence does not require any document created using the fonts or their
|
||||||
|
derivatives to be published under this licence, as long as the primary
|
||||||
|
purpose of the document is not to be a vehicle for the distribution of
|
||||||
|
the fonts.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this licence and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components
|
||||||
|
as received under this licence.
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to
|
||||||
|
a new environment.
|
||||||
|
|
||||||
|
"Copyright Holder(s)" refers to all individuals and companies who have a
|
||||||
|
copyright ownership of the Font Software.
|
||||||
|
|
||||||
|
"Substantially Changed" refers to Modified Versions which can be easily
|
||||||
|
identified as dissimilar to the Font Software by users of the Font
|
||||||
|
Software comparing the Original Version with the Modified Version.
|
||||||
|
|
||||||
|
To "Propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification and with or without charging
|
||||||
|
a redistribution fee), making available to the public, and in some
|
||||||
|
countries other activities as well.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
This licence does not grant any rights under trademark law and all such
|
||||||
|
rights are reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of the Font Software, to propagate the Font Software, subject to
|
||||||
|
the below conditions:
|
||||||
|
|
||||||
|
1) Each copy of the Font Software must contain the above copyright
|
||||||
|
notice and this licence. These can be included either as stand-alone
|
||||||
|
text files, human-readable headers or in the appropriate machine-
|
||||||
|
readable metadata fields within text or binary files as long as those
|
||||||
|
fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
2) The font name complies with the following:
|
||||||
|
(a) The Original Version must retain its name, unmodified.
|
||||||
|
(b) Modified Versions which are Substantially Changed must be renamed to
|
||||||
|
avoid use of the name of the Original Version or similar names entirely.
|
||||||
|
(c) Modified Versions which are not Substantially Changed must be
|
||||||
|
renamed to both (i) retain the name of the Original Version and (ii) add
|
||||||
|
additional naming elements to distinguish the Modified Version from the
|
||||||
|
Original Version. The name of such Modified Versions must be the name of
|
||||||
|
the Original Version, with "derivative X" where X represents the name of
|
||||||
|
the new work, appended to that name.
|
||||||
|
|
||||||
|
3) The name(s) of the Copyright Holder(s) and any contributor to the
|
||||||
|
Font Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except (i) as required by this licence, (ii) to
|
||||||
|
acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with
|
||||||
|
their explicit written permission.
|
||||||
|
|
||||||
|
4) The Font Software, modified or unmodified, in part or in whole, must
|
||||||
|
be distributed entirely under this licence, and must not be distributed
|
||||||
|
under any other licence. The requirement for fonts to remain under this
|
||||||
|
licence does not affect any document created using the Font Software,
|
||||||
|
except any version of the Font Software extracted from a document
|
||||||
|
created using the Font Software may only be distributed under this
|
||||||
|
licence.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This licence becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
||||||
|
COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
|
||||||
|
DEALINGS IN THE FONT SOFTWARE.
|
||||||