Compare commits

...

24 Commits

Author SHA1 Message Date
Dave Allie 3ce11f14ce chore: Cut release 0.15.0 2026-01-22 02:20:22 +11:00
KasyanDiGris 47ef92e8fd fix: OPDS browser OOM (#403)
## Summary

- Rewrite OpdsParser to stream parsing instead of full content
- Fix OOM due to big http xml response

Closes #385 

---

### 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? _**NO**_
2026-01-22 01:43:51 +11:00
Juan Biondi e3d6e32609 docs: Add detailed webserver documentation (#446)
## More detailed documentation

* **What is the goal of this PR?** 
Add more information about the exposed webserver.
* **What changes are included?**
Detailed documentation for the webserver endpoints
(`./docs/webserver-endpoints.md`)
Adding a table of content so it is easier to navigate directly to the
section you're interested on (Almost all `.md` files or at least all
those relevant)

## Additional Context

Not sure if this would get accepted but I thought it might be useful for
those trying to create separate apps that would sync files to the
device. It was at least to me trying to upload files using python as
stated
[here](https://github.com/crosspoint-reader/crosspoint-reader/discussions/434#discussioncomment-15545349)

---

### 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? _**PARTIALLY**_
2026-01-22 00:29:39 +11:00
Logan Garbarini d399afb53d feat: invalidate cache on web uploads and opds downloads and add Clear Cache action (#393)
## Summary

When uploading or downloading an updated ebook from SD/WebUI/OPDS with
same the filename the `.crosspoint` cache is not cleared. This can lead
to issues with the Table of Contents and hangs when switching between
chapters.

I encountered this issue in two places:
- When I need to do further ePub cleaning using Calibre after I load an
ePub and find that some of its formatting should be cleaned up. When I
reprocess the same book and want to place it back in the same location I
need a way to invalidate the cache.
- When syncing RSS feed generated epubs. I generate news ePubs with
filenames like `news-outlet.epub` and so every day when I fetch new news
the crosspoint cache needs to be cleared to load that file.

This change offers the following features:
- On web uploads, if the file already exists, the cache for that file is
cleared
- On OPDS downloads, if the file already exists, the cache for that file
is cleared
- There's now an action for `Clear Cache` in the Settings page which can
clear the cache for all books


Addresses
https://github.com/crosspoint-reader/crosspoint-reader/issues/281

---

### 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? PARTIALLY

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-22 00:06:07 +11:00
Arthur Tazhitdinov 838993259d fix: hard reset via RTS pin after flashing firmware (#437)
## Summary

* Disables going to sleep after uploading new firmware
* Makes developer experience easier

---

### 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? _**< NO >**_

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-21 23:35:23 +11:00
Jonas Diemer cc74039cab fix: Skip negative screen coordinates only after we read the bitmap row. (#431)
Otherwise, we don't crop properly.

Fixes #430 

### AI Usage

Did you use AI tools to help write this code? _**< NO >**_
2026-01-21 23:27:41 +11:00
Jonas Diemer 87d6c032a5 Reclaim space if we don't show battery Percentage (#352)
## Summary

Give space to the chapter title if we don't show battery percentage.

---

### 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? _**NO**_

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-21 12:09:48 +00:00
Dave Allie c9b5462370 feat: Include superscripts and subscripts in fonts (#463)
## Summary

* Include superscripts and subscripts in fonts

## Additional Context

* Original change came from
https://github.com/crosspoint-reader/crosspoint-reader/pull/248

---

### 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? No

---------

Co-authored-by: cor <cor@pruijs.dev>
2026-01-21 22:42:41 +11:00
Kenneth e548bfc0e1 My Library: Tab bar w/ Recent Books + File Browser (#250)
# Summary

This PR introduces a reusable Tab Bar component and combines the Recent
Books and File Browser into a unified tabbed page called "My Library"
accessible from the Home screen.

## Features
### New Tab Bar Component
A flexible, reusable tab bar component added to `ScreenComponents` that
can be used throughout the application.

### New Scroll Indicator Component
A page position indicator for lists that span multiple pages.
**Features:**
- Up/down arrow indicators
- Current page fraction display (e.g., "1/3")
- Only renders when content spans multiple pages

### My Library Activity
A new unified view combining Recent Books and File Browser into a single
tabbed page.

**Tabs:**
- **Recent** - Shows recently opened books
- **Files** - Browse SD card directory structure

**Navigation:**
- Up/Down or Left/Right: Navigate through list items
- Left/Right (when first item selected): Switch between tabs
- Confirm: Open selected book or enter directory
- Back: Go up directory (Files tab) or return home
- Long press Back: Jump to root directory (Files tab)

**UI Elements:**
- Tab bar with selection indicator
- Scroll/page indicator on right side
- Side button hints (up/down arrows)
- Dynamic bottom button labels ("BACK" in subdirectories, "HOME" at
root)

## Tab Bar Usage
The tab bar component is designed to be reusable across different
activities. Here's how to use it:

### Basic Example
```cpp
#include "ScreenComponents.h"
void MyActivity::render() const {
  renderer.clearScreen();
  
  // Define tabs with labels and selection state
  std::vector<TabInfo> tabs = {
    {"Tab One", currentTab == 0},   // Selected when currentTab is 0
    {"Tab Two", currentTab == 1},   // Selected when currentTab is 1
    {"Tab Three", currentTab == 2}  // Selected when currentTab is 2
  };
  
  // Draw tab bar at Y position 15, returns height of the tab bar
  int tabBarHeight = ScreenComponents::drawTabBar(renderer, 15, tabs);
  
  // Position your content below the tab bar
  int contentStartY = 15 + tabBarHeight + 10; // Add some padding
  
  // Draw content based on selected tab
  if (currentTab == 0) {
    renderTabOneContent(contentStartY);
  } else if (currentTab == 1) {
    renderTabTwoContent(contentStartY);
  } else {
    renderTabThreeContent(contentStartY);
  }
  
  renderer.displayBuffer();
}
```
Video Demo: https://share.cleanshot.com/P6NBncFS

<img width="250"
src="https://github.com/user-attachments/assets/07de4418-968e-4a88-9b42-ac5f53d8a832"
/>
<img width="250"
src="https://github.com/user-attachments/assets/e40201ed-dcc8-4568-b008-cd2bf13ebb2a"
/>
<img width="250"
src="https://github.com/user-attachments/assets/73db269f-e629-4696-b8ca-0b8443451a05"
/>

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-21 11:38:38 +00:00
Daniel Poulter 73c30748d8 feat: adding categories to settings screen (#331)
## Summary

* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module, Implements the new feature for
  file uploading.)

As we get more settings, I think it makes sense to do categories for
them. This just allows users to find the settings easier and navigate to
them.

* **What changes are included?**

## Additional Context

* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).

Co-authored-by: dpoulter <daniel@yoco.com>
Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-21 11:13:51 +00:00
GenesiaW 6d68466891 fix: truncate chapter names that are too long (#422)
## Summary

* **What is the goal of this PR?** (e.g., Implements the new feature for
file uploading.)
- Implements a fix to truncate chapter names that exceeds display width
 
* **What changes are included?**
- Implements a fix to truncate chapter names that exceeds display width
## Additional Context

* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks,
  specific areas to focus on).
- Prior to the fix, if the book contains multiple chapters with names
longer than the display width, there is a noticeable delay when
scrolling through the list of chapters.

Serial output of the issue:
```
[25673] [ACT] Entering activity: EpubReaderChapterSelection
[25693] [GFX] !! Outside range (485, 65) -> (65, -6)
[25693] [GFX] !! Outside range (486, 65) -> (65, -7)
[25693] [GFX] !! Outside range (487, 65) -> (65, -8)
[25693] [GFX] !! Outside range (488, 65) -> (65, -9)
[25693] [GFX] !! Outside range (485, 66) -> (66, -6)
[25693] [GFX] !! Outside range (486, 66) -> (66, -7)
[25694] [GFX] !! Outside range (487, 66) -> (66, -8)
[25694] [GFX] !! Outside range (484, 67) -> (67, -5)
[25694] [GFX] !! Outside range (485, 67) -> (67, -6)
[25694] [GFX] !! Outside range (486, 67) -> (67, -7)
[25694] [GFX] !! Outside range (483, 68) -> (68, -4)
[25694] [GFX] !! Outside range (484, 68) -> (68, -5)
[25694] [GFX] !! Outside range (485, 68) -> (68, -6)
``` 


---

### 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? _**NO**_

Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-19 13:01:51 +00:00
Arthur Tazhitdinov 8824c87490 feat: dict based Hyphenation (#305)
## Summary

* Adds (optional) Hyphenation for English, French, German, Russian
languages

## Additional Context

* Included hyphenation dictionaries add approximately 280kb to the flash
usage (German alone takes 200kb)
* Trie encoded dictionaries are adopted from hypher project
(https://github.com/typst/hypher)
* Soft hyphens (and other explicit hyphens) take precedence over
dict-based hyphenation. Overall, the hyphenation rules are quite
aggressive, as I believe it makes more sense on our smaller screen.

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-19 12:56:26 +00:00
Maeve Andrews 5fef99c641 fix: render U+FFFD replacement character instead of ? (#366)
The current behavior of rendering `?` for an unknown Unicode character
can be hard to distinguish from a typo. Use the standard Unicode
"replacement character" instead, that's what it's designed for:

https://en.wikipedia.org/wiki/Specials_(Unicode_block)

I'm making this PR as a draft because I'm not sure I did everything that
was needed to change the character set covered by the fonts. Running
that script is in its own commit. If this is proper, I'll rebase/squash
into one commit and un-draft.

Co-authored-by: Maeve Andrews <maeve@git.mail.maeveandrews.com>
2026-01-19 22:58:43 +11:00
Luke Stein 7a792a5384 fix: Invert colors on home screen cover overlay when recent book is selected (#390)
## Summary

* Fixes #388 

## Additional Context

* Tested on my own device
  * See images at #388 for what home screen looked like before.
* With this PR the home screen shows the following (selected and
unselected recent book × cover image rendered or not)


![Picsew_20260115153419](https://github.com/user-attachments/assets/44193f9d-76b7-4c77-b890-72b0dbae01c4)


---

### 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**

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-01-19 22:57:39 +11:00
Justin Mitchell f69cddf2cc Adds KOReader Sync support (#232)
## Summary

- Adds KOReader progress sync integration, allowing CrossPoint to sync
reading positions with other
KOReader-compatible devices
- Stores credentials securely with XOR obfuscation
- Uses KOReader's partial MD5 document hashing for cross-device book
matching
  - Syncs position via percentage with estimated XPath for compatibility

# Features
- Settings: KOReader Username, Password, and Authenticate options
- Sync from chapters menu: "Sync Progress" option appears when
credentials are configured
- Bidirectional sync: Can apply remote progress or upload local progress

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-19 11:55:35 +00:00
Nathan James 7185e5d287 feat: Change keyboard "caps" to "shift" & Wrap Keyboard (#377)
## Summary

* This PR solves issue
https://github.com/crosspoint-reader/crosspoint-reader/issues/357 in the
first commit
* I then added an additional commit which means when you reach the end
of the keyboard, if you go 'beyond', you wrap back to the other side.
* This replaces existing behaviour, so if you would rather this be
removed, let me know and I'll just do the `caps` -> `shift` change

## Additional Context

### Screenshots for the new shift display

I thought it might not fit and need column size changes, but ended up
fitting fine, see screenshots showing this below:

<img width="573" height="366" alt="image"
src="https://github.com/user-attachments/assets/b8f6a4ec-94f5-4f5e-b9a6-06cc5f250ddb"
/>

<img width="570" height="308" alt="image"
src="https://github.com/user-attachments/assets/7d775518-4784-4120-a20a-a9dc67af8565"
/>


### Gif showing the wrap-around of the text



![IMG_7648](https://github.com/user-attachments/assets/7eec9066-e1cc-49a1-8b6b-a61556038d31)

---

### AI Usage

Did you use AI tools to help write this code? **PARTIALLY** - used to
double check the text wrapping had no edge-cases. (It did also suggest
rewriting the function, but I decided that was too big of a change for a
working part of the codebase, for now!)
2026-01-19 22:50:34 +11:00
Eunchurn Park 12940cc546 fix: XTC 1-bit thumb BMP polarity inversion (#373)
## Summary

* **What is the goal of this PR?** (e.g., Implements the new feature for
file uploading.)
* **What changes are included?**

- Fix inverted colors in Continue Reading cover image for 1-bit XTC
files

## Additional Context

* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks,
  specific areas to focus on).

- Fix `grayValue = pixelBit ? 0 : 255` → `grayValue = pixelBit ? 255 :
0` in `lib/Xtc/Xtc.cpp`
- The thumb BMP generation had inverted polarity compared to cover BMP
generation
- bit=0 should be black, bit=1 should be white (matching the BMP palette
order)
- Update misleading comment about XTC polarity

---

### 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? _**PARTIALLY**_
2026-01-19 22:41:48 +11:00
Luke Stein 21277e03eb docs: Update User Guide to reflect release 0.14.0 (#376) 2026-01-15 23:27:17 +11:00
Luke Stein 4eef2b5793 feat: Add MAC address display to WiFi Networks screen (#381)
## Summary

* Implements #380, allowing the user to see the device's MAC address in
order to register on wifi networks

## Additional Context

* Although @markatlnk suggested showing on the settings screen, I
implemented display at the bottom of the WiFi Networks selection screen
(accessed via "File Transfer" > "Join a Network") since I think it makes
more sense there.
* Tested on my own device


![IMG_2873](https://github.com/user-attachments/assets/b82a20dc-41a0-4b21-81f1-20876aa2c6b0)


---

### 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**_

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-01-15 23:26:39 +11:00
Nathan James 5a55fa1c6e fix: also apply longPressChapterSkip setting to xtc reader (#378)
## Summary

* This builds upon the helpful PR
https://github.com/crosspoint-reader/crosspoint-reader/pull/341, and
adds support for the setting to also apply to the XTC reader, which I
believed has just been missed and was not intentionally left out.
* XTC does not have chapter support yet, but it does skip 10 pages when
long-pressed, and so I think this is useful.

---

### AI Usage

Did you use AI tools to help write this code? No
2026-01-15 23:25:18 +11:00
Maeve Andrews c98ba142e8 fix: draw button hints correctly if orientation is not portrait (#363)
~~Quick~~ fix for
https://github.com/daveallie/crosspoint-reader/issues/362

(this just applies to the chapter selection menu:)

~~If the orientation is portrait, hints as we know them make sense to
draw. If the orientation is inverted, we'd have to change the order of
the labels (along with everything's position), and if it's one of the
landscape choices, we'd have to render the text and buttons vertically.
All those other cases will be more complicated.~~

~~Punt on this for now by only rendering if portrait.~~

Update: this now draws the hints at the physical button position no
matter what the orientation is, by temporarily changing orientation to
portrait.

---------

Co-authored-by: Maeve Andrews <maeve@git.mail.maeveandrews.com>
2026-01-15 23:23:36 +11:00
Jonas Diemer c1c94c0112 Feature: Show img alt text (#168)
Let's start small by showing the ALT text of IMG. This is rudimentary,
but avoids those otherwise completely blank chapters.

I feel we will need this even when we can render images if that
rendering takes >1s - I would then prefer rendering optional and showing
the ALT text first.
2026-01-15 23:21:46 +11:00
Dave Allie eb84bcee7c chore: Pin links2004/WebSockets version 2026-01-15 23:15:30 +11:00
efenner d45f355e87 feat: Add EPUB table omitted placeholder (#372)
## Summary

* **What is the goal of this PR?**: Fix the bug I reported in
https://github.com/daveallie/crosspoint-reader/issues/292
* **What changes are included?**: Instead of silently dropping table
content in EPUBs., replace with an italicized '[Table omitted]' message
where tables appear.

## Additional Context

* 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? _**PARTIALLY **_

---------

Co-authored-by: Evan Fenner <evan@evanfenner.com>
Co-authored-by: Warp <agent@warp.dev>
2026-01-15 23:14:59 +11:00
154 changed files with 63551 additions and 18889 deletions
+2
View File
@@ -4,3 +4,5 @@
.vscode
lib/EpdFont/fontsrc
*.generated.h
build
**/__pycache__/
+28
View File
@@ -2,6 +2,27 @@
Welcome to the **CrossPoint** firmware. This guide outlines the hardware controls, navigation, and reading features of 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)
## 1. Hardware Overview
The device utilises the standard buttons on the Xtink X4 (in the same layout as the manufacturer firmware, by default):
@@ -96,6 +117,10 @@ The Settings screen allows you to configure the device's behavior. There are a f
- Left, Right, Back, Confirm
- Left, Back, Confirm, Right
- **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
@@ -144,6 +169,9 @@ If the **Short Power Button Click** setting is set to "Page Turn", you can also
* **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.
This feature can be disabled in **[Settings](#35-settings)** to help avoid changing chapters by mistake.
### System Navigation
* **Return to Book Selection:** Press **Back** to close the book and return to the **[Book Selection](#32-book-selection)** screen.
* **Return to Home:** Press and **hold** the **Back** button to close the book and return to the **[Home](#31-home-screen)** screen.
+66
View 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 nodes 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
```
+57
View 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
View 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
+2 -83
View File
@@ -172,89 +172,7 @@ This is useful for organizing your ebooks by genre, author, or series.
## 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.
### Uploading a File
To upload a file to the root directory, use the following command:
```bash
curl -F "file=@book.epub" "http://crosspoint.local/upload?path=/"
```
* **`-F "file=@filename"`**: Points to the local file on your computer.
* **`path=/`**: The destination folder on the device SD card.
### Deleting a File
To delete a specific file, provide the full path on the SD card:
```bash
curl -F "path=/folder/file.epub" "http://crosspoint.local/delete"
```
### Advanced Flags
For more reliable transfers of large EPUB files, consider adding these flags:
* `-#`: Shows a simple progress bar.
* `--connect-timeout 30`: Limits how long curl waits to establish a connection (in seconds).
* `--max-time 300`: Sets a maximum duration for the entire transfer (5 minutes).
> [!NOTE]
> 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/`).
---
## Troubleshooting
### 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
---
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
@@ -303,4 +221,5 @@ 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
+1 -2
View File
@@ -22,8 +22,7 @@ void EpdFont::getTextBounds(const char* string, const int startX, const int star
const EpdGlyph* glyph = getGlyph(cp);
if (!glyph) {
// TODO: Replace with fallback glyph property?
glyph = getGlyph('?');
glyph = getGlyph(REPLACEMENT_GLYPH);
}
if (!glyph) {
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+191 -112
View File
@@ -7,7 +7,7 @@
#pragma once
#include "EpdFontData.h"
static const uint8_t bookerly_14_italicBitmaps[64856] = {
static const uint8_t bookerly_14_italicBitmaps[65749] = {
0x00, 0x05, 0x00, 0x0F, 0x80, 0x0B, 0xD0, 0x03, 0xF0, 0x00, 0xF8, 0x00, 0x7D, 0x00, 0x2F, 0x00,
0x0F, 0x80, 0x03, 0xD0, 0x00, 0xF0, 0x00, 0x7C, 0x00, 0x1E, 0x00, 0x0B, 0x40, 0x02, 0xC0, 0x00,
0xF0, 0x00, 0x3C, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x3F, 0x40, 0x0F,
@@ -3681,7 +3681,51 @@ static const uint8_t bookerly_14_italicBitmaps[64856] = {
0x00, 0x00, 0x00, 0x0E, 0x00, 0xD0, 0x2C, 0x03, 0x80, 0x7E, 0x0B, 0xC0, 0xFC, 0x1F, 0x42, 0xF4,
0x3F, 0x07, 0xE0, 0xFD, 0x0F, 0xC2, 0xF8, 0x3F, 0x03, 0xF0, 0xBD, 0x0F, 0xC1, 0xF8, 0x2F, 0x43,
0xE0, 0x7D, 0x0B, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x3D, 0x0B, 0xC0, 0xF4, 0x0F, 0x01, 0xE0, 0x3D,
0x00, 0x40, 0x10, 0x02, 0x00, 0x10, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xD0, 0x07, 0xFF, 0xFF, 0xFD,
0x00, 0x40, 0x10, 0x02, 0x00, 0x10, 0x00, 0x00, 0x2F, 0x80, 0x0B, 0xFF, 0xC0, 0xBD, 0x2F, 0x43,
0xD0, 0x3E, 0x2E, 0x00, 0xB8, 0xF4, 0x03, 0xE7, 0xC0, 0x0F, 0x6E, 0x00, 0x3C, 0xB8, 0x01, 0xF2,
0xE0, 0x0F, 0x4B, 0xC0, 0xBC, 0x1F, 0x9B, 0xC0, 0x2F, 0xFC, 0x00, 0x19, 0x40, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xB8, 0x00, 0x3C, 0xB4, 0x00, 0xF0, 0xF0,
0x03, 0xD0, 0xF0, 0x0F, 0x41, 0xF0, 0x3F, 0xAB, 0xF9, 0x3F, 0xFF, 0xFD, 0x00, 0x03, 0xC0, 0x00,
0x03, 0xC0, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6A, 0xA4, 0x03, 0xFF, 0xE0, 0x1F, 0xAA,
0x00, 0xB4, 0x00, 0x03, 0xD0, 0x00, 0x1F, 0xF8, 0x00, 0x06, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03,
0xC0, 0x00, 0x1F, 0x00, 0x01, 0xF4, 0x05, 0xBF, 0x80, 0xBF, 0xF4, 0x00, 0x54, 0x00, 0x00, 0x00,
0x01, 0xB8, 0x00, 0x1F, 0xF9, 0x00, 0xFE, 0x00, 0x03, 0xF0, 0x00, 0x0B, 0xC0, 0x00, 0x0F, 0xFE,
0x00, 0x2F, 0xAF, 0xD0, 0x3D, 0x02, 0xF0, 0x3C, 0x01, 0xF0, 0x3C, 0x01, 0xF0, 0x3D, 0x03, 0xD0,
0x2F, 0x5F, 0xC0, 0x0B, 0xFE, 0x00, 0x01, 0x50, 0x00, 0x2A, 0xAA, 0x47, 0xFF, 0xFD, 0xB9, 0x5B,
0xCF, 0x00, 0xF0, 0x50, 0x3D, 0x00, 0x0B, 0x80, 0x01, 0xF0, 0x00, 0x3D, 0x00, 0x0B, 0x80, 0x01,
0xF0, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x00, 0x78, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2F, 0x80, 0x07,
0xEF, 0xC0, 0x7C, 0x0F, 0x42, 0xD0, 0x3D, 0x0B, 0x81, 0xF0, 0x0F, 0xAF, 0x00, 0x2F, 0xF0, 0x03,
0xD7, 0xE0, 0x3D, 0x07, 0xC1, 0xF0, 0x0F, 0x47, 0xC0, 0x3C, 0x0F, 0x87, 0xE0, 0x2F, 0xFE, 0x00,
0x05, 0x40, 0x00, 0x00, 0x1F, 0x90, 0x00, 0xFF, 0xF8, 0x03, 0xE0, 0x7C, 0x07, 0xC0, 0x3D, 0x07,
0x80, 0x2D, 0x0B, 0xC0, 0x3D, 0x07, 0xD0, 0x7C, 0x02, 0xFF, 0xFC, 0x00, 0x19, 0xF4, 0x00, 0x03,
0xE0, 0x00, 0x1F, 0xC0, 0x01, 0xFE, 0x00, 0x3F, 0xF4, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01,
0xFD, 0x2F, 0x81, 0xF7, 0xFE, 0x03, 0xE8, 0x78, 0x0F, 0xC2, 0xD0, 0x7C, 0x0F, 0x02, 0xE0, 0x3C,
0x0F, 0x41, 0xE0, 0x3C, 0x0B, 0xB4, 0xF0, 0x3F, 0x81, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x02,
0xFF, 0x40, 0x3F, 0xBF, 0x03, 0xE0, 0x3D, 0x1F, 0x00, 0xF8, 0xF4, 0x02, 0xE3, 0xC0, 0x0F, 0x9F,
0x00, 0x3D, 0xB8, 0x01, 0xF2, 0xE0, 0x0B, 0xCB, 0x80, 0x3D, 0x1F, 0x03, 0xE0, 0x3F, 0xFE, 0x00,
0x7F, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x0F, 0xFD, 0x05, 0xBC, 0x00, 0x7C,
0x00, 0xB8, 0x00, 0xF4, 0x00, 0xF4, 0x00, 0xF0, 0x01, 0xF0, 0x02, 0xE0, 0x03, 0xD0, 0x2F, 0xFC,
0x7F, 0xF8, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x40, 0x7F, 0xBF, 0x03, 0xE0, 0x3D, 0x0E, 0x00, 0xF4,
0x00, 0x07, 0xC0, 0x00, 0x3D, 0x00, 0x07, 0xD0, 0x00, 0x7D, 0x00, 0x0B, 0xC0, 0x00, 0xF8, 0x00,
0x0F, 0x80, 0x00, 0xFF, 0xFF, 0xD1, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFC, 0x07, 0xEB,
0xE0, 0xB0, 0x2E, 0x00, 0x02, 0xE0, 0x00, 0x7C, 0x00, 0x7F, 0x00, 0x3F, 0xF4, 0x01, 0x0B, 0xC0,
0x00, 0x7C, 0x00, 0x0B, 0xC0, 0x02, 0xF4, 0x6B, 0xFD, 0x07, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x02, 0xFC, 0x00, 0x07, 0xF8, 0x00, 0x1E, 0xB8, 0x00, 0x78,
0xF4, 0x01, 0xF0, 0xF0, 0x07, 0xC0, 0xF0, 0x1F, 0x01, 0xE0, 0x3F, 0xFF, 0xFD, 0x2F, 0xFF, 0xFC,
0x00, 0x03, 0xC0, 0x00, 0x07, 0xC0, 0x00, 0x07, 0x40, 0x00, 0xFF, 0xF8, 0x03, 0xFF, 0xD0, 0x2E,
0x00, 0x00, 0xF0, 0x00, 0x03, 0xF8, 0x00, 0x0B, 0xFD, 0x00, 0x00, 0xFC, 0x00, 0x00, 0xF0, 0x00,
0x03, 0xC0, 0x00, 0x2F, 0x00, 0x02, 0xF0, 0x1B, 0xFF, 0x00, 0x7F, 0xD0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0xFD, 0x00, 0x3F, 0x90, 0x01, 0xF8, 0x00, 0x03, 0xD0, 0x00, 0x0F,
0x94, 0x00, 0x1F, 0xFF, 0x80, 0x2E, 0x57, 0xE0, 0x3C, 0x01, 0xF0, 0x3C, 0x01, 0xF0, 0x3C, 0x02,
0xE0, 0x3E, 0x03, 0xD0, 0x1F, 0xFF, 0x80, 0x07, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xD7,
0xFF, 0xFD, 0xB0, 0x0B, 0x8E, 0x01, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x40, 0x02, 0xE0, 0x00, 0x7C,
0x00, 0x0F, 0x40, 0x02, 0xF0, 0x00, 0x3D, 0x00, 0x07, 0xC0, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0xFF, 0x40, 0x3E, 0x6F, 0x02, 0xE0, 0x3D, 0x0B, 0x40, 0xF0, 0x1F, 0x0B,
0x80, 0x2F, 0xF4, 0x00, 0xFF, 0xC0, 0x1F, 0x0F, 0xC0, 0xF0, 0x0F, 0x47, 0x80, 0x3D, 0x1F, 0x01,
0xF0, 0x3F, 0xAF, 0x40, 0x2F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x7F, 0xF0,
0x01, 0xFA, 0xFC, 0x03, 0xD0, 0x3C, 0x07, 0xC0, 0x3D, 0x0B, 0x80, 0x3D, 0x07, 0xC0, 0x3D, 0x03,
0xF9, 0xBC, 0x00, 0xFF, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x07, 0xD0, 0x00, 0x2F, 0x40, 0x1B, 0xFD,
0x00, 0x2F, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xD0, 0x07, 0xFF, 0xFF, 0xFD,
0x00, 0x07, 0xE5, 0x57, 0xD0, 0x00, 0x7D, 0x00, 0x3C, 0x00, 0x0B, 0xC0, 0x03, 0xC0, 0x00, 0xFC,
0x00, 0x10, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x1F, 0x95, 0x64, 0x00,
0x02, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xAA, 0xA0, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x7D, 0x00,
@@ -4061,7 +4105,19 @@ static const uint8_t bookerly_14_italicBitmaps[64856] = {
0xFC, 0x00, 0x06, 0xAA, 0xBF, 0xAA, 0xA6, 0xFF, 0xFF, 0xFF, 0xFE, 0xBF, 0xFF, 0xFF, 0xFF, 0x80,
0x0A, 0x43, 0xFC, 0x3F, 0xC2, 0xF8, 0x00, 0x00, 0x0A, 0x00, 0x01, 0xA0, 0x00, 0x29, 0x0F, 0xF0,
0x01, 0xFD, 0x00, 0x2F, 0xC3, 0xFC, 0x00, 0xBF, 0x80, 0x0F, 0xF0, 0xFD, 0x00, 0x0F, 0xC0, 0x01,
0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF,
0xE0, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x5B, 0xE0, 0x00, 0x00, 0x00, 0x02, 0xC0, 0x02, 0xE0, 0x00,
0x00, 0x00, 0x2E, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x02, 0xFC, 0x69, 0x02, 0xE0, 0x00, 0x00, 0x2F,
0xFF, 0xFF, 0x03, 0xE0, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x0F, 0xE0, 0x00, 0x2F, 0xFF, 0xFF, 0xFC,
0x2F, 0xE0, 0x02, 0xFF, 0xFF, 0xFF, 0xF0, 0xBF, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0x42, 0xFF, 0xE2,
0xFF, 0xFF, 0xFE, 0x40, 0x0F, 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0x03, 0xFF, 0xFF,
0x00, 0x2F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xF0, 0xBF, 0xFF,
0xF0, 0x00, 0x03, 0xFF, 0xD1, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00,
0x03, 0xFF, 0xEF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFC, 0x0F, 0xF0, 0x00, 0x00, 0x00, 0x03, 0xF0,
0x3F, 0x00, 0x00, 0x00, 0x00, 0x03, 0xD2, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
};
static const EpdGlyph bookerly_14_italicGlyphs[] = {
@@ -4716,83 +4772,102 @@ static const EpdGlyph bookerly_14_italicGlyphs[] = {
{ 0, 0, 0, 0, 0, 0, 58775 }, //
{ 0, 0, 0, 0, 0, 0, 58775 }, //
{ 0, 0, 0, 0, 0, 0, 58775 }, //
{ 18, 20, 18, 0, 20, 90, 58775 }, //
{ 19, 22, 18, -1, 21, 105, 58865 }, //
{ 35, 22, 36, 0, 21, 193, 58970 }, //
{ 20, 22, 18, -1, 21, 110, 59163 }, //
{ 17, 12, 29, 6, 16, 51, 59273 }, //
{ 13, 20, 29, 8, 20, 65, 59324 }, //
{ 17, 12, 29, 6, 16, 51, 59389 }, //
{ 13, 20, 29, 8, 20, 65, 59440 }, //
{ 18, 12, 29, 5, 16, 54, 59505 }, //
{ 13, 20, 29, 8, 20, 65, 59559 }, //
{ 13, 20, 29, 8, 20, 65, 59624 }, //
{ 13, 20, 29, 8, 20, 65, 59689 }, //
{ 13, 20, 29, 8, 20, 65, 59754 }, //
{ 17, 14, 29, 6, 17, 60, 59819 }, //
{ 17, 14, 29, 6, 17, 60, 59879 }, //
{ 13, 18, 29, 8, 19, 59, 59939 }, //
{ 17, 14, 29, 6, 17, 60, 59998 }, //
{ 13, 18, 29, 8, 19, 59, 60058 }, //
{ 19, 14, 29, 5, 17, 67, 60117 }, //
{ 19, 22, 29, 5, 21, 105, 60184 }, //
{ 14, 24, 18, 2, 23, 84, 60289 }, //
{ 13, 21, 29, 8, 21, 69, 60373 }, //
{ 23, 24, 29, 3, 22, 138, 60442 }, //
{ 19, 21, 19, 0, 21, 100, 60580 }, //
{ 19, 22, 29, 5, 21, 105, 60680 }, //
{ 19, 21, 29, 5, 21, 100, 60785 }, //
{ 19, 26, 29, 5, 23, 124, 60885 }, //
{ 19, 16, 29, 5, 18, 76, 61009 }, //
{ 19, 21, 29, 5, 21, 100, 61085 }, //
{ 19, 26, 29, 5, 23, 124, 61185 }, //
{ 19, 16, 29, 5, 18, 76, 61309 }, //
{ 22, 26, 23, 1, 21, 143, 61385 }, //
{ 18, 26, 18, 0, 21, 117, 61528 }, //
{ 13, 3, 18, 3, 11, 10, 61645 }, //
{ 17, 23, 14, -1, 21, 98, 61655 }, //
{ 11, 23, 14, 2, 21, 64, 61753 }, //
{ 14, 14, 18, 2, 17, 49, 61817 }, //
{ 10, 10, 18, 4, 15, 25, 61866 }, //
{ 6, 4, 18, 6, 10, 6, 61891 }, //
{ 18, 28, 18, 0, 24, 126, 61897 }, //
{ 14, 11, 18, 2, 15, 39, 62023 }, //
{ 18, 10, 18, 0, 14, 45, 62062 }, //
{ 19, 21, 29, 5, 21, 100, 62107 }, //
{ 21, 21, 29, 3, 21, 111, 62207 }, //
{ 4, 30, 15, 5, 23, 30, 62318 }, //
{ 9, 30, 15, 3, 23, 68, 62348 }, //
{ 19, 21, 29, 5, 21, 100, 62416 }, //
{ 19, 21, 29, 5, 21, 100, 62516 }, //
{ 17, 21, 29, 6, 21, 90, 62616 }, //
{ 17, 22, 29, 6, 21, 94, 62706 }, //
{ 16, 30, 18, 1, 23, 120, 62800 }, //
{ 19, 17, 29, 5, 16, 81, 62920 }, //
{ 19, 17, 29, 5, 16, 81, 63001 }, //
{ 6, 16, 9, 1, 18, 24, 63082 }, //
{ 19, 17, 29, 5, 16, 81, 63106 }, //
{ 17, 5, 29, 6, 11, 22, 63187 }, //
{ 17, 15, 29, 6, 17, 64, 63209 }, //
{ 14, 10, 18, 2, 15, 35, 63273 }, //
{ 17, 10, 29, 6, 13, 43, 63308 }, //
{ 13, 13, 18, 3, 16, 43, 63351 }, //
{ 17, 13, 29, 6, 15, 56, 63394 }, //
{ 14, 18, 18, 2, 18, 63, 63450 }, //
{ 14, 18, 18, 2, 18, 63, 63513 }, //
{ 23, 14, 29, 3, 17, 81, 63576 }, //
{ 23, 14, 29, 3, 17, 81, 63657 }, //
{ 19, 16, 29, 5, 18, 76, 63738 }, //
{ 19, 26, 29, 5, 23, 124, 63814 }, //
{ 19, 26, 29, 5, 23, 124, 63938 }, //
{ 19, 21, 29, 5, 21, 100, 64062 }, //
{ 19, 21, 29, 5, 21, 100, 64162 }, //
{ 21, 22, 29, 4, 21, 116, 64262 }, //
{ 21, 22, 29, 4, 21, 116, 64378 }, //
{ 21, 22, 29, 4, 21, 116, 64494 }, //
{ 21, 22, 29, 4, 21, 116, 64610 }, //
{ 17, 21, 29, 6, 21, 90, 64726 }, //
{ 6, 5, 18, 6, 10, 8, 64816 }, //
{ 25, 5, 29, 2, 10, 32, 64824 }, //
{ 11, 14, 13, 1, 24, 39, 58775 }, //
{ 12, 14, 13, 0, 24, 42, 58814 }, //
{ 11, 14, 13, 1, 24, 39, 58856 }, //
{ 12, 14, 13, 1, 24, 42, 58895 }, //
{ 10, 14, 13, 3, 24, 35, 58937 }, //
{ 11, 14, 13, 1, 24, 39, 58972 }, //
{ 12, 14, 13, 0, 24, 42, 59011 }, //
{ 11, 11, 16, 3, 21, 31, 59053 }, //
{ 11, 15, 13, 1, 10, 42, 59084 }, //
{ 8, 14, 13, 2, 10, 28, 59126 }, //
{ 11, 14, 13, 1, 10, 39, 59154 }, //
{ 10, 15, 13, 1, 10, 38, 59193 }, //
{ 12, 14, 13, 0, 10, 42, 59231 }, //
{ 11, 14, 13, 1, 9, 39, 59273 }, //
{ 12, 15, 13, 1, 10, 45, 59312 }, //
{ 10, 14, 13, 3, 9, 35, 59357 }, //
{ 11, 15, 13, 1, 10, 42, 59392 }, //
{ 12, 15, 13, 0, 10, 45, 59434 }, //
{ 18, 20, 18, 0, 20, 90, 59479 }, //
{ 19, 22, 18, -1, 21, 105, 59569 }, //
{ 35, 22, 36, 0, 21, 193, 59674 }, //
{ 20, 22, 18, -1, 21, 110, 59867 }, //
{ 17, 12, 29, 6, 16, 51, 59977 }, //
{ 13, 20, 29, 8, 20, 65, 60028 }, //
{ 17, 12, 29, 6, 16, 51, 60093 }, //
{ 13, 20, 29, 8, 20, 65, 60144 }, //
{ 18, 12, 29, 5, 16, 54, 60209 }, //
{ 13, 20, 29, 8, 20, 65, 60263 }, //
{ 13, 20, 29, 8, 20, 65, 60328 }, //
{ 13, 20, 29, 8, 20, 65, 60393 }, //
{ 13, 20, 29, 8, 20, 65, 60458 }, //
{ 17, 14, 29, 6, 17, 60, 60523 }, //
{ 17, 14, 29, 6, 17, 60, 60583 }, //
{ 13, 18, 29, 8, 19, 59, 60643 }, //
{ 17, 14, 29, 6, 17, 60, 60702 }, //
{ 13, 18, 29, 8, 19, 59, 60762 }, //
{ 19, 14, 29, 5, 17, 67, 60821 }, //
{ 19, 22, 29, 5, 21, 105, 60888 }, //
{ 14, 24, 18, 2, 23, 84, 60993 }, //
{ 13, 21, 29, 8, 21, 69, 61077 }, //
{ 23, 24, 29, 3, 22, 138, 61146 }, //
{ 19, 21, 19, 0, 21, 100, 61284 }, //
{ 19, 22, 29, 5, 21, 105, 61384 }, //
{ 19, 21, 29, 5, 21, 100, 61489 }, //
{ 19, 26, 29, 5, 23, 124, 61589 }, //
{ 19, 16, 29, 5, 18, 76, 61713 }, //
{ 19, 21, 29, 5, 21, 100, 61789 }, //
{ 19, 26, 29, 5, 23, 124, 61889 }, //
{ 19, 16, 29, 5, 18, 76, 62013 }, //
{ 22, 26, 23, 1, 21, 143, 62089 }, //
{ 18, 26, 18, 0, 21, 117, 62232 }, //
{ 13, 3, 18, 3, 11, 10, 62349 }, //
{ 17, 23, 14, -1, 21, 98, 62359 }, //
{ 11, 23, 14, 2, 21, 64, 62457 }, //
{ 14, 14, 18, 2, 17, 49, 62521 }, //
{ 10, 10, 18, 4, 15, 25, 62570 }, //
{ 6, 4, 18, 6, 10, 6, 62595 }, //
{ 18, 28, 18, 0, 24, 126, 62601 }, //
{ 14, 11, 18, 2, 15, 39, 62727 }, //
{ 18, 10, 18, 0, 14, 45, 62766 }, //
{ 19, 21, 29, 5, 21, 100, 62811 }, //
{ 21, 21, 29, 3, 21, 111, 62911 }, //
{ 4, 30, 15, 5, 23, 30, 63022 }, //
{ 9, 30, 15, 3, 23, 68, 63052 }, //
{ 19, 21, 29, 5, 21, 100, 63120 }, //
{ 19, 21, 29, 5, 21, 100, 63220 }, //
{ 17, 21, 29, 6, 21, 90, 63320 }, //
{ 17, 22, 29, 6, 21, 94, 63410 }, //
{ 16, 30, 18, 1, 23, 120, 63504 }, //
{ 19, 17, 29, 5, 16, 81, 63624 }, //
{ 19, 17, 29, 5, 16, 81, 63705 }, //
{ 6, 16, 9, 1, 18, 24, 63786 }, //
{ 19, 17, 29, 5, 16, 81, 63810 }, //
{ 17, 5, 29, 6, 11, 22, 63891 }, //
{ 17, 15, 29, 6, 17, 64, 63913 }, //
{ 14, 10, 18, 2, 15, 35, 63977 }, //
{ 17, 10, 29, 6, 13, 43, 64012 }, //
{ 13, 13, 18, 3, 16, 43, 64055 }, // ≠
{ 17, 13, 29, 6, 15, 56, 64098 }, // ≡
{ 14, 18, 18, 2, 18, 63, 64154 }, // ≤
{ 14, 18, 18, 2, 18, 63, 64217 }, // ≥
{ 23, 14, 29, 3, 17, 81, 64280 }, // ≪
{ 23, 14, 29, 3, 17, 81, 64361 }, // ≫
{ 19, 16, 29, 5, 18, 76, 64442 }, // ⊃
{ 19, 26, 29, 5, 23, 124, 64518 }, // ⊄
{ 19, 26, 29, 5, 23, 124, 64642 }, // ⊅
{ 19, 21, 29, 5, 21, 100, 64766 }, // ⊆
{ 19, 21, 29, 5, 21, 100, 64866 }, // ⊇
{ 21, 22, 29, 4, 21, 116, 64966 }, // ⊕
{ 21, 22, 29, 4, 21, 116, 65082 }, // ⊖
{ 21, 22, 29, 4, 21, 116, 65198 }, // ⊗
{ 21, 22, 29, 4, 21, 116, 65314 }, // ⊘
{ 17, 21, 29, 6, 21, 90, 65430 }, // ⊥
{ 6, 5, 18, 6, 10, 8, 65520 }, // ⋅
{ 25, 5, 29, 2, 10, 32, 65528 }, // ⋯
{ 27, 28, 29, 1, 24, 189, 65560 }, //
};
static const EpdUnicodeInterval bookerly_14_italicIntervals[] = {
@@ -4825,44 +4900,48 @@ static const EpdUnicodeInterval bookerly_14_italicIntervals[] = {
{ 0x2053, 0x2053, 0x283 },
{ 0x2057, 0x2057, 0x284 },
{ 0x205F, 0x2064, 0x285 },
{ 0x20A3, 0x20A4, 0x28B },
{ 0x20A7, 0x20A7, 0x28D },
{ 0x20AC, 0x20AC, 0x28E },
{ 0x2190, 0x2195, 0x28F },
{ 0x21A8, 0x21A8, 0x295 },
{ 0x21B2, 0x21B3, 0x296 },
{ 0x21B5, 0x21B5, 0x298 },
{ 0x21D0, 0x21D4, 0x299 },
{ 0x2200, 0x2200, 0x29E },
{ 0x2202, 0x2203, 0x29F },
{ 0x2205, 0x220D, 0x2A1 },
{ 0x220F, 0x220F, 0x2AA },
{ 0x2211, 0x2212, 0x2AB },
{ 0x2215, 0x221A, 0x2AD },
{ 0x221D, 0x2220, 0x2B3 },
{ 0x2223, 0x2223, 0x2B7 },
{ 0x2225, 0x2225, 0x2B8 },
{ 0x2227, 0x222B, 0x2B9 },
{ 0x2234, 0x2237, 0x2BE },
{ 0x223C, 0x223C, 0x2C2 },
{ 0x2245, 0x2245, 0x2C3 },
{ 0x2248, 0x2248, 0x2C4 },
{ 0x224D, 0x224D, 0x2C5 },
{ 0x2260, 0x2261, 0x2C6 },
{ 0x2264, 0x2265, 0x2C8 },
{ 0x226A, 0x226B, 0x2CA },
{ 0x2283, 0x2287, 0x2CC },
{ 0x2295, 0x2298, 0x2D1 },
{ 0x22A5, 0x22A5, 0x2D5 },
{ 0x22C5, 0x22C5, 0x2D6 },
{ 0x22EF, 0x22EF, 0x2D7 },
{ 0x2070, 0x2070, 0x28B },
{ 0x2074, 0x2079, 0x28C },
{ 0x207F, 0x2089, 0x292 },
{ 0x20A3, 0x20A4, 0x29D },
{ 0x20A7, 0x20A7, 0x29F },
{ 0x20AC, 0x20AC, 0x2A0 },
{ 0x2190, 0x2195, 0x2A1 },
{ 0x21A8, 0x21A8, 0x2A7 },
{ 0x21B2, 0x21B3, 0x2A8 },
{ 0x21B5, 0x21B5, 0x2AA },
{ 0x21D0, 0x21D4, 0x2AB },
{ 0x2200, 0x2200, 0x2B0 },
{ 0x2202, 0x2203, 0x2B1 },
{ 0x2205, 0x220D, 0x2B3 },
{ 0x220F, 0x220F, 0x2BC },
{ 0x2211, 0x2212, 0x2BD },
{ 0x2215, 0x221A, 0x2BF },
{ 0x221D, 0x2220, 0x2C5 },
{ 0x2223, 0x2223, 0x2C9 },
{ 0x2225, 0x2225, 0x2CA },
{ 0x2227, 0x222B, 0x2CB },
{ 0x2234, 0x2237, 0x2D0 },
{ 0x223C, 0x223C, 0x2D4 },
{ 0x2245, 0x2245, 0x2D5 },
{ 0x2248, 0x2248, 0x2D6 },
{ 0x224D, 0x224D, 0x2D7 },
{ 0x2260, 0x2261, 0x2D8 },
{ 0x2264, 0x2265, 0x2DA },
{ 0x226A, 0x226B, 0x2DC },
{ 0x2283, 0x2287, 0x2DE },
{ 0x2295, 0x2298, 0x2E3 },
{ 0x22A5, 0x22A5, 0x2E7 },
{ 0x22C5, 0x22C5, 0x2E8 },
{ 0x22EF, 0x22EF, 0x2E9 },
{ 0xFFFD, 0xFFFD, 0x2EA },
};
static const EpdFontData bookerly_14_italic = {
bookerly_14_italicBitmaps,
bookerly_14_italicGlyphs,
bookerly_14_italicIntervals,
60,
64,
38,
31,
-8,
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More