ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_rabook_pipeline.c
Go to the documentation of this file.
1
10
11#include "ra8_rabook_pipeline.h"
12
13#include <stddef.h>
14#include <stdint.h>
15#include <string.h>
16
17#include "book.h"
18#include "epub.h"
19#include "ra8_attributes.h"
20#include "ra8_check.h"
21#include "ra8_err.h"
22#include "ra8_fs.h"
23#include "ra8_img_arena.h"
24#include "ra8_log.h"
25#include "ra8_rabook_gray4.h"
27#include "ra8_rabook_xml_shim.h"
28#include "rabook_compile.h"
29#include "reflow_image.h"
30#include "stb_image.h"
31
32/* -------------------------------------------------------------------------- */
33/* Private constants */
34/* -------------------------------------------------------------------------- */
35
41typedef enum : uint16_t {
45
46static_assert((uint16_t)k_pipeline_max_chapters == (uint16_t)k_epub_max_chapters,
47 "pipeline chapter cap must match epub cap");
48static_assert((uint16_t)k_pipeline_max_toc == (uint16_t)k_epub_max_toc,
49 "pipeline toc cap must match epub cap");
50
56typedef enum : uint8_t {
59
60static const char* const s_tag = "ra8_rabook_pipeline";
61
62/* -------------------------------------------------------------------------- */
63/* Private helpers */
64/* -------------------------------------------------------------------------- */
65
66/* The raster image path (stb_image decode + gray4 transcode) is compiled out of a
67 * RA8_RABOOK_NO_RASTER build -- e.g. the Cortex-M33 text/CSS/SVG-only image, which
68 * then links no stb_image. SVG images are stored verbatim and need none of this. */
69#ifndef RA8_RABOOK_NO_RASTER
70
95 const uint8_t* pixels,
96 uint16_t sw,
97 uint16_t sh,
98 uint16_t ow,
99 uint16_t oh)
100{
101 if ((ow == sw) && (oh == sh)) {
102 return pixels;
103 }
104 if (((uint32_t)ow * (uint32_t)oh) > scr->gray_cap) {
105 ra8_log_error(s_tag, "gray scratch too small for downscale");
106 return nullptr;
107 }
108 if (ra8_rabook_gray4_downscale(pixels, sw, sh, scr->gray, ow, oh) != k_ra8_ok) {
109 return nullptr;
110 }
111 return scr->gray;
112}
113
139 const uint8_t* gray_src,
140 uint16_t ow,
141 uint16_t oh,
142 uint32_t* out_size)
143{
144 if (scr->pixel_format == (uint8_t)k_book_pixfmt_gray8) {
145 return ra8_rabook_gray8_encode(gray_src,
146 ow,
147 oh,
148 scr->image_raw,
149 (uint32_t)scr->image_cap,
150 out_size);
151 }
152 return ra8_rabook_gray4_encode(gray_src,
153 ow,
154 oh,
155 scr->image_raw,
156 (uint32_t)scr->image_cap,
157 out_size);
158}
159
185 uint32_t id_off,
186 size_t raw_len)
187{
188 int sw = 0;
189 int sh = 0;
190 int comp = 0;
192 stbi_uc* pixels =
193 stbi_load_from_memory(scr->image_raw, /* alloc-allow: stb backed by ra8_img_arena */
194 (int)raw_len,
195 &sw,
196 &sh,
197 &comp,
198 (int)k_stbi_grey);
199 if (pixels == nullptr) {
201 ra8_log_error(s_tag, "stb_image decode failed");
202 return k_book_nil;
203 }
204
205 /* Downscale is opt-in: max_image_edge == 0 (the default) preserves the
206 * source resolution so zoomable content (manga pages) keeps every pixel. */
207 uint16_t ow = (uint16_t)sw;
208 uint16_t oh = (uint16_t)sh;
209 if (scr->max_image_edge != 0U) {
210 ra8_rabook_gray4_output_dims((uint16_t)sw, (uint16_t)sh, scr->max_image_edge, &ow, &oh);
211 }
212
213 const uint8_t* gray_src =
214 internal_downscale_if_needed(scr, pixels, (uint16_t)sw, (uint16_t)sh, ow, oh);
215 if (gray_src == nullptr) {
216 stbi_image_free(pixels); /* alloc-allow: stb backed by ra8_img_arena */
218 return k_book_nil;
219 }
220
221 uint32_t encoded_size = 0U;
222 ra8_err_t enc_err = internal_encode_gray(scr, gray_src, ow, oh, &encoded_size);
223 stbi_image_free(pixels); /* alloc-allow: stb backed by ra8_img_arena */
225
226 if (enc_err != k_ra8_ok) {
227 return k_book_nil;
228 }
229
230 return ra8_rabook_add_image(ctx,
231 id_off,
232 ow,
233 oh,
234 (uint8_t)k_book_image_gray4,
235 scr->pixel_format,
236 scr->image_raw,
237 encoded_size);
238}
239
240#endif /* RA8_RABOOK_NO_RASTER -- raster transcode helpers */
241
262static const char* internal_chapter_title(const epub_book_t* epub,
263 uint16_t chapter_idx,
264 uint16_t toc_count,
265 epub_toc_entry_t* entry_buf)
266{
267 for (uint16_t ti = 0U; ti < toc_count; ti++) {
268 uint16_t ch_idx = 0U;
269 if ((epub_toc_entry_to_chapter(epub, ti, &ch_idx) == k_ra8_ok) && (ch_idx == chapter_idx)) {
270 if (epub_get_toc_entry(epub, ti, entry_buf) == k_ra8_ok) {
271 return entry_buf->title;
272 }
273 break;
274 }
275 }
276 return "";
277}
278
299 const ra8_rabook_buffers_t* bufs,
301{
302 RA8_CHECK_NULL_PTR(epub, s_tag, "epub");
303 RA8_CHECK_NULL_PTR(bufs, s_tag, "bufs");
304 RA8_CHECK_NULL_PTR(scr, s_tag, "scr");
305 RA8_CHECK_NULL_PTR(scr->xml_workspace, s_tag, "scr->xml_workspace");
306 return k_ra8_ok;
307}
308
335 epub_book_t* epub)
336{
337 const uint16_t count = epub_manifest_count(epub);
338 for (uint16_t i = 0U; i < count; i++) {
339 const epub_manifest_item_t* item = epub_manifest_item(epub, i);
340 if (item == nullptr) {
341 continue;
342 }
343 if (strcmp(item->media_type, "text/css") != 0) {
344 continue;
345 }
346 size_t got = 0U;
347 ra8_err_t err =
348 epub_get_resource(epub, item->href, (uint8_t*)scr->css, scr->css_cap - 1U, &got);
349 if (err == k_ra8_err_not_found) {
350 continue; /* desktop skips a css item absent from the archive */
351 }
352 if (err != k_ra8_ok) {
353 return err;
354 }
355 scr->css[got] = '\0';
356 const uint32_t source_off = ra8_rabook_intern(ctx, scr->css);
357 (void)ra8_rabook_add_stylesheet(ctx, source_off, (uint32_t)k_book_nil);
358 }
359 return k_ra8_ok;
360}
361
389 epub_book_t* epub,
390 const epub_manifest_item_t* item)
391{
392 const char* const img_prefix = "image/";
393 uint8_t fmt = (uint8_t)k_book_image_gray4;
394 if (strcmp(item->media_type, "image/svg+xml") == 0) {
395 fmt = (uint8_t)k_book_image_svg;
396 } else if (strncmp(item->media_type, img_prefix, strlen(img_prefix)) != 0) {
397 return (uint32_t)k_book_nil; /* not an image item */
398 } else {
399 /* All remaining image media types use the raster decode path below. */
400 }
401
402#ifdef RA8_RABOOK_NO_RASTER
403 if (fmt != (uint8_t)k_book_image_svg) {
404 ra8_log_error(s_tag, "raster image skipped (text/CSS/SVG-only build)");
405 return (uint32_t)k_book_nil;
406 }
407#endif
408
409 size_t got = 0U;
410 ra8_err_t err = epub_get_resource(epub, item->href, scr->image_raw, scr->image_cap, &got);
411 if (err != k_ra8_ok) {
412 return (uint32_t)k_book_nil; /* absent / unreadable -> skip, like the desktop */
413 }
414
415 const uint32_t id_off = ra8_rabook_intern(ctx, item->href);
416 if (fmt == (uint8_t)k_book_image_svg) {
417 return ra8_rabook_add_image(ctx,
418 id_off,
419 0U,
420 0U,
421 (uint8_t)k_book_image_svg,
422 (uint8_t)k_book_pixfmt_gray4, /* unused for SVG; store 0 */
423 scr->image_raw,
424 (uint32_t)got);
425 }
426#ifndef RA8_RABOOK_NO_RASTER
427 return internal_transcode_image(ctx, scr, id_off, got);
428#else
429 return (uint32_t)k_book_nil; /* unreachable: raster returned nil above */
430#endif
431}
432
465 epub_book_t* epub,
466 uint32_t* cover_index_out)
467{
468 *cover_index_out = (uint32_t)k_book_nil;
469 if (scr->skip_images) {
470 return k_ra8_ok; /* desktop --no-images: empty image loop, cover stays nil */
471 }
472 const uint16_t count = epub_manifest_count(epub);
473 for (uint16_t i = 0U; i < count; i++) {
474 const epub_manifest_item_t* item = epub_manifest_item(epub, i);
475 if (item == nullptr) {
476 continue;
477 }
478 const uint32_t idx = internal_add_manifest_image(ctx, scr, epub, item);
479 if (idx == (uint32_t)k_book_nil) {
480 continue;
481 }
482 if (strcmp(item->href, epub->cover_path) == 0) {
483 *cover_index_out = idx;
484 }
485 }
486 return k_ra8_ok;
487}
488
511 ra8_rabook_ctx_t* ctx)
512{
513 uint16_t chapter_count = 0U;
514 ra8_err_t err = epub_get_chapter_count(epub, &chapter_count);
515 if (err != k_ra8_ok) {
516 return err;
517 }
518
519 uint16_t toc_count = 0U;
520 (void)epub_get_toc_count(epub, &toc_count);
521
522 epub_toc_entry_t toc_entry = {};
523
524 for (uint16_t ci = 0U; ci < chapter_count; ci++) {
525 size_t got_len = 0U;
526 err = epub_load_chapter(epub, ci, scr->xhtml, scr->xhtml_cap, &got_len);
527 if (err != k_ra8_ok) {
528 return err;
529 }
530
531 const char* ch_title = internal_chapter_title(epub, ci, toc_count, &toc_entry);
532 const char* ch_href = epub->chapter_paths[ci];
533
534 err =
535 ra8_rabook_xml_parse_chapter(scr->xhtml, got_len, ctx, ch_href, ch_title, scr->xml_workspace);
536 if (err != k_ra8_ok) {
537 return err;
538 }
539 }
540 return k_ra8_ok;
541}
542
564static ra8_err_t
565internal_compile_metadata(ra8_rabook_ctx_t* ctx, epub_book_t* epub, uint32_t cover_image_index)
566{
567 epub_metadata_t meta = {};
568 ra8_err_t err = epub_get_metadata(epub, &meta);
569 if (err != k_ra8_ok) {
570 return err;
571 }
572 const uint32_t title_off = ra8_rabook_intern(ctx, meta.title);
573 const uint32_t author_off = ra8_rabook_intern(ctx, meta.author);
574 const uint32_t language_off = ra8_rabook_intern(ctx, meta.language);
575 const uint32_t identifier_off = ra8_rabook_intern(ctx, meta.identifier);
576 return ra8_rabook_set_metadata(ctx,
577 title_off,
578 author_off,
579 language_off,
580 identifier_off,
581 cover_image_index);
582}
583
608 const ra8_rabook_buffers_t* bufs,
610 const void** out_blob,
611 uint32_t* out_len)
612{
613 ra8_rabook_ctx_t ctx = {};
614 ra8_err_t err = rabook_compile_init(&ctx, bufs);
615 if (err != k_ra8_ok) {
616 return err;
617 }
618 /* Emit in the desktop epub_compile.py order so the blob is byte-identical:
619 * stylesheets, images (cover resolved within), chapters, metadata interned LAST. */
620 err = internal_compile_stylesheets(&ctx, scr, epub);
621 if (err != k_ra8_ok) {
622 return err;
623 }
624 uint32_t cover_image_index = (uint32_t)k_book_nil;
625 err = internal_compile_images(&ctx, scr, epub, &cover_image_index);
626 if (err != k_ra8_ok) {
627 return err;
628 }
629 err = internal_compile_chapters(epub, scr, &ctx);
630 if (err != k_ra8_ok) {
631 return err;
632 }
633 err = internal_compile_metadata(&ctx, epub, cover_image_index);
634 if (err != k_ra8_ok) {
635 return err;
636 }
637 return ra8_rabook_finalize(&ctx, out_blob, out_len);
638}
639
640/* -------------------------------------------------------------------------- */
641/* Public API */
642/* -------------------------------------------------------------------------- */
643
645 const ra8_rabook_buffers_t* bufs,
647 const void** out_blob,
648 uint32_t* out_len)
649{
650 ra8_err_t err = priv_rabook_pipeline_check_common(epub, bufs, scr);
651 if (err != k_ra8_ok) {
652 return err;
653 }
654 RA8_CHECK_NULL_PTR(out_blob, s_tag, "out_blob");
655 RA8_CHECK_NULL_PTR(out_len, s_tag, "out_len");
656 return internal_compile_to_blob(epub, bufs, scr, out_blob, out_len);
657}
Flat, execute-in-place container for a build-time "compiled" e-book.
@ k_book_nil
Absent index / "applies to all chapters".
Definition book.h:129
@ k_book_image_svg
Verbatim UTF-8 SVG source (vector; on-device rasterized).
Definition book.h:176
@ k_book_image_gray4
4bpp gray, 2px/byte; pixel (x,y) is at flat index y*width + x.
Definition book.h:175
@ k_book_pixfmt_gray4
4bpp packed grayscale, 2px/byte (default; every pre-field blob).
Definition book.h:213
@ k_book_pixfmt_gray8
8bpp grayscale, 1px/byte (lossless against any grey panel).
Definition book.h:215
EPUB (.epub) reader and chapter iterator for ra8-firmware.
uint16_t epub_manifest_count(const epub_book_t *book)
Number of <manifest> <item> entries retained (#151).
const epub_manifest_item_t * epub_manifest_item(const epub_book_t *book, uint16_t index)
Borrow the manifest item at index (OPF document order, #151).
ra8_err_t epub_toc_entry_to_chapter(const epub_book_t *book, uint16_t toc_idx, uint16_t *out_chapter_idx)
Resolve a TOC entry to the spine chapter index it points into.
ra8_err_t epub_get_metadata(const epub_book_t *book, epub_metadata_t *out_meta)
Return Dublin Core metadata strings.
ra8_err_t epub_load_chapter(epub_book_t *book, uint16_t idx, uint8_t *out_xhtml, size_t max_len, size_t *got_len)
Extract the raw XHTML bytes of one chapter into the caller's buffer.
@ k_epub_max_toc
Max table-of-contents entries we keep.
Definition epub.h:88
@ k_epub_max_chapters
Max spine length we accept.
Definition epub.h:87
ra8_err_t epub_get_toc_entry(const epub_book_t *book, uint16_t idx, epub_toc_entry_t *out_entry)
Copy one table-of-contents entry into the caller's struct.
ra8_err_t epub_get_chapter_count(const epub_book_t *book, uint16_t *out_count)
Report how many chapters the spine contains.
ra8_err_t epub_get_toc_count(const epub_book_t *book, uint16_t *out_count)
Report how many table-of-contents entries the book exposes.
ra8_err_t epub_get_resource(epub_book_t *book, const char *path, uint8_t *out_buf, size_t max_len, size_t *got_len)
Copy the raw bytes of an arbitrary archive resource into the caller's buffer (#140 external styleshee...
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_not_found
Requested item not found (lookup / search missed).
Definition ra8_err.h:173
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
int strncmp(const char *s1, const char *s2, size_t n)
Compare two strings up to a specified length.
int strcmp(const char *s1, const char *s2)
Compare two null-terminated strings.
size_t strlen(const char *s)
Calculate string length.
Minimal FAT12/FAT16/FAT32 filesystem adapter (read + write).
Heap-free scratch allocator hooks for the stb_image single-TU build.
void ra8_img_arena_bind(ra8_img_arena_t *arena)
Bind arena as the active scratch for subsequent decode allocations.
void ra8_img_arena_unbind(void)
Unbind the active arena; subsequent allocation hooks fail with nullptr.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
Grayscale image transcode stage (4-bpp / 8-bpp) for the on-device EPUB compiler (#149).
ra8_err_t ra8_rabook_gray4_encode(const uint8_t *gray_pixels, uint16_t w, uint16_t h, uint8_t *out, uint32_t out_cap, uint32_t *out_size)
Quantise a grayscale buffer to 16 levels and pack as 4-bpp nibbles.
ra8_err_t ra8_rabook_gray4_downscale(const uint8_t *src, uint16_t src_w, uint16_t src_h, uint8_t *dst, uint16_t dst_w, uint16_t dst_h)
Bilinear-interpolate a grayscale image from (src_w x src_h) to (dst_w x dst_h).
ra8_err_t ra8_rabook_gray8_encode(const uint8_t *gray_pixels, uint16_t w, uint16_t h, uint8_t *out, uint32_t out_cap, uint32_t *out_size)
Copy a grayscale buffer out verbatim as 8-bpp (one byte per pixel).
void ra8_rabook_gray4_output_dims(uint16_t src_w, uint16_t src_h, uint16_t max_edge, uint16_t *out_w, uint16_t *out_h)
Compute scaled output dimensions keeping the longer edge within max_edge.
static ra8_err_t internal_encode_gray(const ra8_rabook_pipeline_scratch_t *scr, const uint8_t *gray_src, uint16_t ow, uint16_t oh, uint32_t *out_size)
Encode gray_src into scr->image_raw at the device-profile depth.
static ra8_err_t internal_compile_images(ra8_rabook_ctx_t *ctx, const ra8_rabook_pipeline_scratch_t *scr, epub_book_t *epub, uint32_t *cover_index_out)
Compile every manifest image into the builder, resolving the cover.
ra8_pipeline_stbi_t
stb_image channel-count selector (no magic literals).
@ k_stbi_grey
Request 8-bit grayscale output from stb_image.
static const char * internal_chapter_title(const epub_book_t *epub, uint16_t chapter_idx, uint16_t toc_count, epub_toc_entry_t *entry_buf)
Find the TOC title for one spine chapter (first-entry-wins).
ra8_err_t rabook_compile_from_epub_to_buffer(epub_book_t *epub, const ra8_rabook_buffers_t *bufs, const ra8_rabook_pipeline_scratch_t *scr, const void **out_blob, uint32_t *out_len)
Compile an open EPUB into a RABOOK1 blob left in bufs->out, with no filesystem write.
ra8_pipeline_limits_t
Static bounds used for NASA Rule 2 loop annotations.
@ k_pipeline_max_toc
== k_epub_max_toc (cross-check).
@ k_pipeline_max_chapters
== k_epub_max_chapters (cross-check).
static uint32_t internal_transcode_image(ra8_rabook_ctx_t *ctx, const ra8_rabook_pipeline_scratch_t *scr, uint32_t id_off, size_t raw_len)
Decode one raw image, transcode to the profile's gray depth, add to builder.
static ra8_err_t internal_compile_chapters(epub_book_t *epub, const ra8_rabook_pipeline_scratch_t *scr, ra8_rabook_ctx_t *ctx)
Parse every spine chapter into the builder DOM.
static const uint8_t * internal_downscale_if_needed(const ra8_rabook_pipeline_scratch_t *scr, const uint8_t *pixels, uint16_t sw, uint16_t sh, uint16_t ow, uint16_t oh)
Resolve the gray source buffer for the encode, downscaling if required.
static ra8_err_t internal_compile_to_blob(epub_book_t *epub, const ra8_rabook_buffers_t *bufs, const ra8_rabook_pipeline_scratch_t *scr, const void **out_blob, uint32_t *out_len)
Run the compile stages and finalize the RABOOK1 blob in bufs->out.
static uint32_t internal_add_manifest_image(ra8_rabook_ctx_t *ctx, const ra8_rabook_pipeline_scratch_t *scr, epub_book_t *epub, const epub_manifest_item_t *item)
Add one manifest item to the builder if it is an image.
ra8_err_t priv_rabook_pipeline_check_common(const epub_book_t *epub, const ra8_rabook_buffers_t *bufs, const ra8_rabook_pipeline_scratch_t *scr)
Reject any NULL among the three arguments common to both compile entry points (rabook_compile_from_ep...
static ra8_err_t internal_compile_metadata(ra8_rabook_ctx_t *ctx, epub_book_t *epub, uint32_t cover_image_index)
Intern the Dublin Core metadata and record it (the final emit stage).
static ra8_err_t internal_compile_stylesheets(ra8_rabook_ctx_t *ctx, const ra8_rabook_pipeline_scratch_t *scr, epub_book_t *epub)
Emit each text/css manifest item as a stylesheet, in OPF order.
End-to-end EPUB -> RABOOK1 compile pipeline (#149).
Private validation seam shared by RABOOK pipeline entry points.
Bounded XHTML-to-RABOOK streaming builder.
ra8_err_t ra8_rabook_xml_parse_chapter(const uint8_t *xhtml_bytes, size_t xhtml_len, ra8_rabook_ctx_t *ctx, const char *chapter_href, const char *chapter_title, ra8_rabook_xml_workspace_t *workspace)
Parse one XHTML chapter and append it to ctx.
Zero-heap builder that emits a RABOOK1 blob (the #149 compiler back-end).
ra8_err_t ra8_rabook_finalize(ra8_rabook_ctx_t *ctx, const void **out_blob, uint32_t *out_len)
Lay out the tables and pools, fill the header, CRC, and emit the blob.
uint32_t ra8_rabook_intern(ra8_rabook_ctx_t *ctx, const char *str)
Intern a NUL-terminated UTF-8 string into the pool, de-duplicated.
uint32_t ra8_rabook_add_image(ra8_rabook_ctx_t *ctx, uint32_t id_off, uint16_t width, uint16_t height, uint8_t format, uint8_t pixel_format, const uint8_t *data, uint32_t data_size)
Append an image descriptor and copy its pixel/SVG bytes into the pool.
ra8_err_t ra8_rabook_set_metadata(ra8_rabook_ctx_t *ctx, uint32_t title_off, uint32_t author_off, uint32_t language_off, uint32_t identifier_off, uint32_t cover_image_index)
Record the book metadata offsets that land in the blob header.
uint32_t ra8_rabook_add_stylesheet(ra8_rabook_ctx_t *ctx, uint32_t source_off, uint32_t scope_chapter)
Append a preserved stylesheet; return its stylesheet index.
ra8_err_t rabook_compile_init(ra8_rabook_ctx_t *ctx, const ra8_rabook_buffers_t *buf)
Bind a builder context to its caller-provided arenas.
Zero-heap raster image decode + scale + blit for reflow (#106).
Opened EPUB book.
Definition epub.h:286
char chapter_paths[k_epub_max_chapters][k_epub_max_path_len]
Manifest hrefs (relative to OPF dir).
Definition epub.h:323
char cover_path[k_epub_max_path_len]
Path to cover image (or empty).
Definition epub.h:332
One <manifest> <item> entry, retained in OPF document order.
Definition epub.h:260
char media_type[k_epub_media_len]
Item media-type (or "" if absent).
Definition epub.h:263
char href[k_epub_max_path_len]
Item href (relative to the OPF dir).
Definition epub.h:262
Dublin Core metadata bundle returned by epub_get_metadata().
Definition epub.h:370
const char * identifier
NUL-terminated unique id; "" if absent.
Definition epub.h:374
const char * author
NUL-terminated creator; "" if absent.
Definition epub.h:372
const char * title
NUL-terminated title; "" if absent.
Definition epub.h:371
const char * language
NUL-terminated language tag; "" if absent.
Definition epub.h:373
One titled entry in the table of contents.
Definition epub.h:142
char title[k_epub_meta_len]
Navigation label text ("" if none).
Definition epub.h:143
Caller-owned, fixed-capacity arenas the builder appends into (no heap).
Builder state: the arenas plus running counts and a sticky-fail flag.
Caller-owned temporary buffers the pipeline stage needs.
uint16_t max_image_edge
Opt-in downscale clamp on the longer edge in pixels; 0 (the zero-init default) preserves source resol...
uint8_t pixel_format
Device profile: raster depth to emit, book_image_pixfmt_t.
uint32_t gray_cap
Capacity of gray in pixels (bytes).
uint8_t * gray
Intermediate gray-pixel downscale buffer.
char * css
Stylesheet load scratch (NUL-terminated).
size_t xhtml_cap
Capacity of xhtml in bytes.
uint8_t * image_raw
Raw encoded cover/image byte buffer.
ra8_rabook_xml_workspace_t * xml_workspace
Caller-owned XHTML parser state.
bool skip_images
Drop all images (text/CSS-only).
size_t image_cap
Capacity of image_raw in bytes.
size_t css_cap
Capacity of css in bytes.
ra8_img_arena_t * img_arena
stb_image bump arena (caller-sized scratch).
uint8_t * xhtml
Chapter XHTML scratch buffer.