这篇文档由AI生成,具体细节可能有问题,遇到问题可以继续沟通。 This document is generated by AI, and there may be issues with the specific details. If you encounter any problems, please continue to communicate.
- Version: 1.0
- Date: 2025-01-XX
- Purpose: Public technical specification for format conversion
- Target Platform: ESP32 E-Paper Display Devices
Four proprietary file formats designed for ESP32 e-paper displays:
| Format | Extension | Purpose | Description |
|---|---|---|---|
| XTG | .xtg |
Monochrome Image | 1-bit per pixel bitmap |
| XTH | .xth |
4-Level Grayscale Image | 2-bit per pixel bitmap |
| XTC | .xtc |
Comic Container | Container format with multiple XTG pages |
| XTCH | .xtch |
Comic Container Variant | Variant of XTC format |
All multi-byte values are stored in Little-Endian format.
- Little-Endian: Least significant byte at lowest address
- Example:
uint16_t 0x1234→[0x34, 0x12] - Example:
uint32_t 0x12345678→[0x78, 0x56, 0x34, 0x12]
XTG stores 1-bit per pixel monochrome bitmaps optimized for e-paper displays.
| Offset | Size | Type | Field | Description | Value |
|---|---|---|---|---|---|
| 0x00 | 4 | uint32_t | mark | File identifier | 0x00475458 ("XTG\0") |
| 0x04 | 2 | uint16_t | width | Image width (pixels) | 1-65535 |
| 0x06 | 2 | uint16_t | height | Image height (pixels) | 1-65535 |
| 0x08 | 1 | uint8_t | colorMode | Color mode | 0=monochrome |
| 0x09 | 1 | uint8_t | compression | Compression | 0=uncompressed |
| 0x0A | 4 | uint32_t | dataSize | Image data size (bytes) | Calculated |
| 0x0E | 8 | uint64_t | md5 | MD5 checksum (first 8 bytes) | Optional |
- Location: After header (offset 22 bytes)
- Format: Bitmap data, 1 bit per pixel
- Data Size Calculation:
dataSize = ((width + 7) / 8) * height - Pixel Storage:
- Rows stored top to bottom
- Each row stored left to right
- 8 pixels per byte (MSB first)
- Bit order: bit 7 (MSB) = leftmost pixel, bit 0 (LSB) = rightmost pixel
| Bit Value | Display Color |
|---|---|
| 0 | Black |
| 1 | White |
Note: When using inverted bitmap drawing, the display may invert these values (1=black, 0=white).
XTH stores 2-bit per pixel grayscale bitmaps for 4-level grayscale e-paper displays.
Same structure as XTG, but with different file identifier:
| Offset | Size | Type | Field | Description | Value |
|---|---|---|---|---|---|
| 0x00 | 4 | uint32_t | mark | File identifier | 0x00485458 ("XTH\0") |
| 0x04 | 2 | uint16_t | width | Image width (pixels) | 1-65535 |
| 0x06 | 2 | uint16_t | height | Image height (pixels) | 1-65535 |
| 0x08 | 1 | uint8_t | colorMode | Color mode | 0=monochrome |
| 0x09 | 1 | uint8_t | compression | Compression | 0=uncompressed |
| 0x0A | 4 | uint32_t | dataSize | Image data size (bytes) | Calculated |
| 0x0E | 8 | uint64_t | md5 | MD5 checksum (first 8 bytes) | Optional |
- Location: After header (offset 22 bytes)
- Format: Two bit planes, 2 bits per pixel total
- Data Size Calculation:
dataSize = ((width * height + 7) / 8) * 2(rounded up to bytes) - Storage:
- First bit plane: offset 22, size
(width * height + 7) / 8bytes (rounded up) - Second bit plane: immediately after first plane, same size
- Each bit plane stores pixels sequentially (all pixels' Bit1, then all pixels' Bit2)
- Pixels packed 8 per byte (MSB first), stored in row-major order (left to right, top to bottom)
- First bit plane: offset 22, size
| Pixel Value | Binary | Bit1 | Bit2 | LUT Level | Display Color |
|---|---|---|---|---|---|
| 0 | 00 |
0 | 0 | L0 | White |
| 1 | 01 |
0 | 1 | L1 | Light Grey |
| 2 | 10 |
1 | 0 | L2 | Dark Grey |
| 3 | 11 |
1 | 1 | L3 | Black |
Bit Plane Usage:
- Bit1 (first plane): Sent via command
0x24 - Bit2 (second plane): Sent via command
0x26
Pixel Value Calculation: pixelValue = (bit1 << 1) | bit2
XTC is a container format storing multiple XTG-format pages for comic/PDF reading.
| Offset | Size | Type | Field | Description | Value |
|---|---|---|---|---|---|
| 0x00 | 4 | uint32_t | mark | File identifier | 0x00435458 ("XTC\0") |
| 0x04 | 2 | uint16_t | version | Version number | 0x0100 (v1.0) |
| 0x06 | 2 | uint16_t | pageCount | Total pages | 1-65535 |
| 0x08 | 1 | uint8_t | readDirection | Reading direction | 0-2 |
| 0x09 | 1 | uint8_t | hasMetadata | Has metadata | 0-1 |
| 0x0A | 1 | uint8_t | hasThumbnails | Has thumbnails | 0-1 |
| 0x0B | 1 | uint8_t | hasChapters | Has chapters | 0-1 |
| 0x0C | 4 | uint32_t | currentPage | Current page (1-based) | 0-65535 |
| 0x10 | 8 | uint64_t | metadataOffset | Metadata offset | Byte offset |
| 0x18 | 8 | uint64_t | indexOffset | Index table offset | Byte offset |
| 0x20 | 8 | uint64_t | dataOffset | Data area offset | Byte offset |
| 0x28 | 8 | uint64_t | thumbOffset | Thumbnail offset | Byte offset |
| Value | Direction | Description |
|---|---|---|
| 0 | L→R | Left to right (normal) |
| 1 | R→L | Right to left (Japanese manga) |
| 2 | Top→Bottom | Top to bottom (vertical) |
If hasMetadata == 1, stored at metadataOffset:
| Offset | Size | Type | Field | Description |
|---|---|---|---|---|
| 0x00 | 128 | char[] | title | Title (UTF-8, null-terminated) |
| 0x80 | 64 | char[] | author | Author (UTF-8, null-terminated) |
| 0xC0 | 32 | char[] | publisher | Publisher/source (UTF-8, null-terminated) |
| 0xE0 | 16 | char[] | language | Language code (e.g., "zh-CN", "en-US") |
| 0xF0 | 4 | uint32_t | createTime | Creation time (Unix timestamp) |
| 0xF4 | 2 | uint16_t | coverPage | Cover page (0-based, 0xFFFF=none) |
| 0xF6 | 2 | uint16_t | chapterCount | Number of chapters |
| 0xF8 | 8 | uint64_t | reserved | Reserved (zero-filled) |
If hasChapters == 1, stored after metadata:
| Offset | Size | Type | Field | Description |
|---|---|---|---|---|
| 0x00 | 80 | char[] | chapterName | Chapter name (UTF-8, null-terminated) |
| 0x50 | 2 | uint16_t | startPage | Start page (0-based) |
| 0x52 | 2 | uint16_t | endPage | End page (0-based, inclusive) |
| 0x54 | 4 | uint32_t | reserved | Reserved (zero-filled) |
Number of chapters specified by XtcMetadata.chapterCount.
Stored at indexOffset, one entry per page:
| Offset | Size | Type | Field | Description |
|---|---|---|---|---|
| 0x00 | 8 | uint64_t | offset | XTG image offset (relative to dataOffset) |
| 0x08 | 4 | uint32_t | size | XTG image size (bytes) |
| 0x0C | 2 | uint16_t | width | Image width (pixels) |
| 0x0E | 2 | uint16_t | height | Image height (pixels) |
Total index table size: pageCount * 16 bytes.
All XTG page images stored starting at dataOffset. Each page's XTG data is stored contiguously, with position specified by the index table's offset field (relative to dataOffset).
If hasThumbnails == 1, thumbnails stored at thumbOffset. Thumbnails are also in XTG format with the same index structure.
[Header: 48 bytes]
[Metadata: 256 bytes] (optional)
[Chapters: N × 96 bytes] (optional)
[Page Index Table: pageCount × 16 bytes]
[Data Area: All XTG page data]
[Thumbnail Area] (optional)
XTCH is identical to XTC in all aspects except the file identifier.
Same structure as XTC, only mark field differs:
| Offset | Size | Type | Field | Description | Value |
|---|---|---|---|---|---|
| 0x00 | 4 | uint32_t | mark | File identifier | 0x48435458 ("XTCH") |
| Format | Identifier (Little-Endian) | ASCII |
|---|---|---|
| XTC | 0x00435458 | "XTC\0" |
| XTCH | 0x48435458 | "XTCH" |
All other structures, fields, and data formats are identical to XTC.
- All string fields use UTF-8 encoding
- Strings are null-terminated (
\0) - Remaining space in fixed-size string fields is zero-filled
- Rows: top to bottom
- Pixels per row: left to right
- 8 pixels per byte
- Bit order: MSB (bit 7) = leftmost pixel, LSB (bit 0) = rightmost pixel
Example: 10-pixel wide image
- 2 bytes per row (rounded up)
- Byte 1: pixels 0-7 (bit 7 = pixel 0, bit 0 = pixel 7)
- Byte 2: pixels 8-9 (bit 7 = pixel 8, bit 6 = pixel 9, unused bits = 0)
- Two bit planes stored sequentially
- First plane: All pixels' Bit1 (pixel value bit 1), packed 8 pixels per byte
- Second plane: All pixels' Bit2 (pixel value bit 0), packed 8 pixels per byte
- Pixels stored in row-major order (left to right, top to bottom) within each plane
- Each byte contains 8 pixels, MSB (bit 7) = leftmost pixel, LSB (bit 0) = rightmost pixel
Pixel Value Calculation: pixelValue = (bit1 << 1) | bit2
Example: 10×100 pixel image
- Total pixels: 1000
- Each bit plane:
(1000 + 7) / 8 = 125bytes (rounded up) - First plane: offset 22, size 125 bytes (contains Bit1 for all 1000 pixels)
- Second plane: offset 22 + 125 = 147, size 125 bytes (contains Bit2 for all 1000 pixels)
- Total data size: 250 bytes
-
Prepare Source Image:
- Convert to grayscale
- Resize to target resolution
- For XTG: Apply threshold/binarization
- For XTH: Map grayscale to 4 levels (0-3)
-
Generate Bitmap Data:
- XTG: Pack 1 bit per pixel, calculate
dataSize = ((width + 7) / 8) * height - XTH: Generate two bit planes, calculate
dataSize = ((width * height + 7) / 8) * 2
- XTG: Pack 1 bit per pixel, calculate
-
Write File:
- Write header with correct file identifier
- Write bitmap data
- Ensure Little-Endian byte order for all multi-byte values
- Read header to get page count and offsets
- Read page index table to locate each page
- Extract XTG data for each page from data area
- Convert each XTG page using XTG conversion process
| Format | Little-Endian uint32_t | Byte Sequence | ASCII |
|---|---|---|---|
| XTG | 0x00475458 | [0x58, 0x54, 0x47, 0x00] |
"XTG\0" |
| XTH | 0x00485458 | [0x58, 0x54, 0x48, 0x00] |
"XTH\0" |
| XTC | 0x00435458 | [0x58, 0x54, 0x43, 0x00] |
"XTC\0" |
| XTCH | 0x48435458 | [0x58, 0x54, 0x43, 0x48] |
"XTCH" |
- All offsets are byte offsets from the start of the file
- Page numbers in XTC/XTCH are 1-based for display, but 0-based in internal structures
- Reserved fields should be zero-filled
- MD5 checksum field is optional and may be zero
- Compression is currently not implemented (compression field = 0)