ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
jof.h File Reference

JOF band-tile atlas: the display-native normalized image format (#231, shared with the longstrip scroll #289 and codec policy #290). More...

#include <stddef.h>
#include <stdint.h>
#include "ra8_err.h"
Include dependency graph for jof.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  jof_info_t
 Parsed + validated geometry of one JOF atlas. More...
struct  jof_memstore_t
 Append-only memory store: the simplest atlas backing (RAM/SDRAM). More...

Typedefs

typedef ra8_err_t(* jof_pread_fn) (void *ctx, uint64_t offset, uint8_t *buf, size_t len, size_t *got)
 Positioned-read seam over an atlas backing store (DIP).

Enumerations

enum  jof_layout_t : uint8_t {
  k_jof_hdr_bytes = 32U ,
  k_jof_footer_bytes = 16U ,
  k_jof_index_entry = 8U ,
  k_jof_magic_len = 4U ,
  k_jof_ofs_magic = 0U ,
  k_jof_ofs_width = 4U ,
  k_jof_ofs_height = 6U ,
  k_jof_ofs_tile_w = 8U ,
  k_jof_ofs_tile_h = 10U ,
  k_jof_ofs_bpp = 12U ,
  k_jof_ofs_codec = 13U ,
  k_jof_ofs_reserved = 14U ,
  k_jof_ofs_tile_count = 16U ,
  k_jof_ofs_reserved2 = 20U ,
  k_jof_ftr_index_off = 0U ,
  k_jof_ftr_tile_count = 4U ,
  k_jof_ftr_total_size = 8U ,
  k_jof_ftr_magic = 12U ,
  k_jof_idx_ofs_offset = 0U ,
  k_jof_idx_ofs_length = 4U
}
 Fixed byte sizes and offsets of the JOF on-disk structures. More...
enum  jof_limits_t : uint32_t {
  k_jof_max_dim = 32768U ,
  k_jof_max_tiles = 65536U ,
  k_jof_bpp_max = 4U
}
 Hard caps every JOF atlas must satisfy (fail-closed validation). More...
enum  jof_codec_t : uint8_t {
  k_jof_codec_raw = 0U ,
  k_jof_codec_deflate = 1U
}
 Per-atlas tile codec selector (header byte 13). More...

Functions

ra8_err_t jof_memstore_sink (void *ctx, const uint8_t *buf, size_t len)
 Append len bytes to a jof_memstore_t (producer sink).
ra8_err_t jof_memstore_pread (void *ctx, uint64_t offset, uint8_t *buf, size_t len, size_t *got)
 Positioned read from a jof_memstore_t (reader seam).
ra8_err_t jof_parse (jof_pread_fn pread, void *pread_ctx, uint64_t total_size, jof_info_t *out_info)
 Parse + validate a JOF atlas's header, footer and index bounds.
ra8_err_t jof_tile_dims (const jof_info_t *info, uint16_t tile_x, uint16_t tile_y, uint16_t *out_w, uint16_t *out_h)
 Report the true (edge-clamped) pixel dimensions of one tile.
uint32_t jof_stored_bound (uint32_t raw_bytes)
 Worst-case stored-tile byte bound for scratch/cell sizing.
ra8_err_t jof_read_tile (jof_pread_fn pread, void *pread_ctx, const jof_info_t *info, uint16_t tile_x, uint16_t tile_y, uint8_t *scratch, uint32_t scratch_cap, uint8_t *out_px, uint32_t out_cap, uint16_t *out_w, uint16_t *out_h)
 Read + decode one tile into caller pixels, in bounded RAM.

Detailed Description

JOF band-tile atlas: the display-native normalized image format (#231, shared with the longstrip scroll #289 and codec policy #290).

Tag
[Ring 4 / Domain] {World: NS}

A huge raster (a manga page or longstrip slice whose decoded size exceeds the ~10 MB SDRAM working set) cannot be decoded whole on this device, and JPEG/PNG offer no random access. JOF – the Jump-Offset Format, named for the access pattern below – solves both at import time: the source image is transcoded once (jof_produce()) into a grid of independently decodable tiles plus a per-tile byte index, so any tile pages in later with one bounded read + one bounded inflate. A reader parses the fixed-size footer, jumps to the index, reads the wanted tile's byte offset, and jumps straight there – hence jump-offset: O(1) random access at full resolution, never a downscale.

One format serves three consumers:

  • **#231** full-resolution in-EPUB manga pages: 2-D tile grids paged through ra8_tile_cache via the epub_img_tiles binder.
  • **#289** longstrip band-scroll: a band-tile is simply a tile the full image width (tile_w == width, one tile column); the tile index THEN IS the band index (byte offset + length per band), giving O(1) seek to any scroll position.
  • **#290** normalized on-device representation: every source codec (JPEG/PNG/...) converges on this one well-understood format at import, so render time touches a single decode path.

On-disk layout (JOF, all integers little-endian)

[ header | 32 bytes ] at offset 0
[ tile 0 | index[0].length bytes ] tile streams, back-to-back
[ ... ]
[ tile N-1 ]
[ index | tile_count * 8 bytes ] at footer.index_offset
[ footer | 16 bytes ] last 16 bytes of the atlas

Header (32 bytes)

Offset Size Field
0 4 magic "JOF1"
4 2 u16 image width, pixels (1..32768)
6 2 u16 image height, pixels (1..32768)
8 2 u16 tile width, pixels (1..width cap)
10 2 u16 tile height, pixels (1..height cap)
12 1 u8 bytes per pixel: 1=gray8, 3=RGB888, 4=RGBA8888
13 1 u8 tile codec: 0=raw, 1=raw DEFLATE (RFC 1951)
14 2 u16 reserved, must be 0
16 4 u32 tile count, must equal tile_cols * tile_rows
20 12 reserved, must be 0

Tile streams

Tile n (n = tile_y * tile_cols + tile_x, row-major) occupies [index[n].offset, index[n].offset + index[n].length). Edge tiles carry their true clamped dimensions; a tile's decoded payload is exactly tw * th * bpp bytes of tightly packed row-major pixels, where tw = min(tile_w, width - tile_x * tile_w) and likewise for th.

  • codec 0 (raw): the stream is the payload verbatim.
  • codec 1 (deflate): the stream is one standalone raw-DEFLATE stream (RFC 1951, no zlib/gzip wrapper – ra8_compress() output) that inflates to exactly the payload. Each tile is a self-contained ("intra-coded") stream: no cross-tile state, so any tile decodes without touching any other.

Index (tile_count entries of 8 bytes, at footer.index_offset)

Offset Size Field
0 4 u32 tile byte offset (absolute, from atlas byte 0)
4 4 u32 tile byte length

Footer (last 16 bytes)

Offset Size Field
0 4 u32 index_offset (absolute)
4 4 u32 tile count, must equal the header field
8 4 u32 total atlas size in bytes (self-check)
12 4 magic "JOFE"

The index trails the tile streams so a producer can emit the whole atlas through an append-only sink (SD file write, ZIP store) in one forward pass; a reader locates the index via the footer. Atlases are capped at 4 GiB (u32 offsets) and 65536 tiles.

Why DEFLATE and not JPEG for the tile codec (#290 resolution)

Re-encoding tiles as JPEG would stack a second lossy generation on the source image, which the no-quality-loss rule forbids; DEFLATE is lossless, already in-tree (miniz, reused via ra8_compress/ra8_decompress), decodes a 64 KiB tile in bounded RAM with zero heap, and compresses manga/longstrip line art well. Raw (codec 0) remains for zero-decode paging of already-tiny atlases.

Validation model

Atlases arrive from untrusted EPUB content. jof_parse() and jof_read_tile() are fail-closed: every geometry field, both magics, the reserved bytes, the tile-count cross-checks, the index window and every per-tile offset/length/decoded-size are validated before any pixel is trusted.

See also
JOF – The Jump-Offset Band-Tile Atlas – the full JOF wire-format specification (rationale, algorithms, worked example, failure modes).
jof_produce.h Import-time transcode producer.
epub_img_tiles.h EPUB tile-cache binder over this format.
Since
0.1.0

Definition in file jof.h.

Typedef Documentation

◆ jof_pread_fn

typedef ra8_err_t( * jof_pread_fn) (void *ctx, uint64_t offset, uint8_t *buf, size_t len, size_t *got)

Positioned-read seam over an atlas backing store (DIP).

The reader never assumes what holds the atlas bytes: a stored ZIP entry (epub_entry_pread), an SD file, or a RAM region all plug in behind this signature. A short read (*got < len) at the backing's tail is legal; reads past the end report *got == 0.

Parameters
[in]ctxBacking-specific context.
[in]offsetByte offset into the atlas.
[out]bufDestination buffer (len writable bytes).
[in]lenBytes requested.
[out]gotBytes actually read.
Returns
k_ra8_ok on success (short reads included); any error aborts the caller's operation with that code.
Since
0.1.0

Definition at line 240 of file jof.h.

Enumeration Type Documentation

◆ jof_codec_t

enum jof_codec_t : uint8_t

Per-atlas tile codec selector (header byte 13).

Every tile in one atlas shares one codec. Both codecs are intra-coded: a tile decodes with no reference to any other tile.

Since
0.1.0
Enumerator
k_jof_codec_raw 

Tile stream is the packed pixels.

k_jof_codec_deflate 

Tile stream is one raw-DEFLATE run.

Definition at line 190 of file jof.h.

◆ jof_layout_t

enum jof_layout_t : uint8_t

Fixed byte sizes and offsets of the JOF on-disk structures.

Byte offsets are relative to the region they index (header fields from atlas byte 0, footer fields from the footer start). See the file comment for the authoritative layout tables.

Since
0.1.0
Enumerator
k_jof_hdr_bytes 

Header length.

k_jof_footer_bytes 

Footer length.

k_jof_index_entry 

Bytes per tile-index entry.

k_jof_magic_len 

Magic string length (both ends).

k_jof_ofs_magic 

Header: magic "JOF1".

k_jof_ofs_width 

Header: u16 image width.

k_jof_ofs_height 

Header: u16 image height.

k_jof_ofs_tile_w 

Header: u16 tile width.

k_jof_ofs_tile_h 

Header: u16 tile height.

k_jof_ofs_bpp 

Header: u8 bytes per pixel.

k_jof_ofs_codec 

Header: u8 tile codec.

k_jof_ofs_reserved 

Header: first reserved byte.

k_jof_ofs_tile_count 

Header: u32 tile count.

k_jof_ofs_reserved2 

Header: second reserved run.

k_jof_ftr_index_off 

Footer: u32 index offset.

k_jof_ftr_tile_count 

Footer: u32 tile count.

k_jof_ftr_total_size 

Footer: u32 total atlas size.

k_jof_ftr_magic 

Footer: magic "JOFE".

k_jof_idx_ofs_offset 

Index entry: u32 tile offset.

k_jof_idx_ofs_length 

Index entry: u32 tile length.

Definition at line 142 of file jof.h.

◆ jof_limits_t

enum jof_limits_t : uint32_t

Hard caps every JOF atlas must satisfy (fail-closed validation).

The dimension cap bounds every producer/reader loop (NASA Rule 2); the tile-count cap bounds the index (512 KiB at 8 bytes/entry). k_jof_bpp_max is the largest legal bytes-per-pixel.

Since
0.1.0
Enumerator
k_jof_max_dim 

Max image width/height, pixels.

k_jof_max_tiles 

Max tiles per atlas.

k_jof_bpp_max 

Max bytes per pixel.

Definition at line 175 of file jof.h.

Function Documentation

◆ jof_memstore_pread()

ra8_err_t jof_memstore_pread ( void * ctx,
uint64_t offset,
uint8_t * buf,
size_t len,
size_t * got )
nodiscard

Positioned read from a jof_memstore_t (reader seam).

Matching jof_pread_fn: bind with ctx = &store. Reads clamp at store->len; a read at/after the end reports *got == 0 without error, mirroring epub_entry_pread.

Parameters
[in]ctxStore to read from (a jof_memstore_t*).
[in]offsetByte offset into the stored atlas.
[out]bufDestination buffer.
[in]lenBytes requested.
[out]gotBytes actually copied (possibly short at the tail).
Returns
ra8_err_t
Return values
k_ra8_okWindow read (short reads included).
k_ra8_err_null_ptrctx, store->buf, buf, or got is NULL.
Precondition
ctx points at a store previously filled through the sink.
buf holds len writable bytes.
Postcondition
*got <= len bytes were copied into buf.
On any error *got == 0.
Note
Not thread-safe.
Since
0.1.0

Definition at line 177 of file jof.c.

References jof_memstore_t::buf, k_ra8_ok, jof_memstore_t::len, memcpy(), RA8_CHECK_NULL_PTR, and s_tag.

Referenced by ls_open_strip(), mg_build_atlas(), and mg_setup_cache().

◆ jof_memstore_sink()

ra8_err_t jof_memstore_sink ( void * ctx,
const uint8_t * buf,
size_t len )
nodiscard

Append len bytes to a jof_memstore_t (producer sink).

Matching jof_sink_fn shape (see the producer header): bind with ctx = &store. Fails closed when the store is full so a hostile source can never write past cap.

Parameters
[in]ctxStore to append to (a jof_memstore_t*).
[in]bufBytes to append.
[in]lenByte count (0 is a no-op).
Returns
ra8_err_t
Return values
k_ra8_okBytes appended; store->len advanced.
k_ra8_err_null_ptrctx, store->buf, or buf is NULL.
k_ra8_err_no_memThe append would exceed store->cap.
Precondition
ctx points at an initialised store (buf/cap set).
buf holds len readable bytes.
Postcondition
On success exactly len bytes were copied at the old len.
On any error the store is unchanged.
Note
Not thread-safe.
Since
0.1.0

Definition at line 163 of file jof.c.

References jof_memstore_t::buf, jof_memstore_t::cap, k_ra8_err_no_mem, k_ra8_ok, jof_memstore_t::len, memcpy(), RA8_CHECK_NULL_PTR, and s_tag.

Referenced by mg_build_atlas().

◆ jof_parse()

ra8_err_t jof_parse ( jof_pread_fn pread,
void * pread_ctx,
uint64_t total_size,
jof_info_t * out_info )
nodiscard

Parse + validate a JOF atlas's header, footer and index bounds.

Reads the 32-byte header at offset 0 and the 16-byte footer at total_size - 16, then cross-checks every field fail-closed: both magics, non-zero geometry within jof_limits_t, legal bpp/codec, zeroed reserved bytes, tile_count == cols * rows in both header and footer, the footer's total_size against the caller-supplied backing size, and the index window [index_off, index_off + 8 * tile_count + 16] == total_size. Per-tile offset/length windows are validated later, per read, by jof_read_tile() (the index itself may be larger than any bounded parse buffer).

Parameters
[in]preadBacking read seam (non-NULL).
[in]pread_ctxContext for pread.
[in]total_sizeBacking size in bytes (entry/file/store length).
[out]out_infoReceives the validated geometry.
Returns
ra8_err_t
Return values
k_ra8_okAtlas structurally valid; info filled.
k_ra8_err_null_ptrpread or out_info is NULL.
k_ra8_err_invalid_sizetotal_size cannot hold header+footer or exceeds the u32 format cap.
k_ra8_err_validation_failedA magic/geometry/cross-check failed.
otherPropagated from pread.
Precondition
pread serves the atlas bytes for [0, total_size).
out_info is writable.
Postcondition
On success *out_info satisfies the documented invariants.
On any error *out_info is unspecified and must not be used.
Note
Thread-safe for distinct outputs (no shared state).
See also
jof_read_tile()
Since
0.1.0

Definition at line 379 of file jof.c.

References internal_check_cross(), internal_parse_header_region(), internal_pread_exact(), internal_rd_u32(), k_jof_footer_bytes, k_jof_ftr_magic, k_jof_hdr_bytes, k_jof_magic_len, k_jof_ofs_tile_count, k_ra8_err_invalid_size, k_ra8_err_validation_failed, k_ra8_ok, memcmp(), RA8_CHECK_NULL_PTR, and s_tag.

Referenced by internal_accept(), internal_require_jof(), internal_verify_jof(), jof_audit(), jof_audit_requirements(), longstrip_open(), mg_build_atlas(), and priv_viewer_open_jof().

◆ jof_read_tile()

ra8_err_t jof_read_tile ( jof_pread_fn pread,
void * pread_ctx,
const jof_info_t * info,
uint16_t tile_x,
uint16_t tile_y,
uint8_t * scratch,
uint32_t scratch_cap,
uint8_t * out_px,
uint32_t out_cap,
uint16_t * out_w,
uint16_t * out_h )
nodiscard

Read + decode one tile into caller pixels, in bounded RAM.

Fetches the tile's index entry (one 8-byte pread), validates its window against the tile-stream region, reads the stored stream, and decodes it: raw tiles are pread directly into out_px; deflate tiles are pread into scratch and inflated with ra8_decompress() (zero heap). The decoded byte count must equal the tile's exact payload size or the read fails closed. Resident cost is scratch_cap + out_cap, independent of the image size – the property #231 needs for decode-on-demand paging.

Parameters
[in]preadBacking read seam (non-NULL).
[in]pread_ctxContext for pread.
[in]infoParsed atlas geometry.
[in]tile_xTile column, [0, tile_cols).
[in]tile_yTile row, [0, tile_rows).
[out]scratchStored-stream staging (deflate codec only; may be NULL for raw atlases).
[in]scratch_capCapacity of scratch; must cover jof_stored_bound() of the tile payload for deflate atlases.
[out]out_pxDestination pixel buffer.
[in]out_capCapacity of out_px; must cover the payload.
[out]out_wReceives the tile's clamped width, pixels.
[out]out_hReceives the tile's clamped height, pixels.
Returns
ra8_err_t
Return values
k_ra8_okTile decoded into out_px.
k_ra8_err_null_ptrA required pointer is NULL.
k_ra8_err_out_of_rangetile_x / tile_y outside the grid.
k_ra8_err_invalid_sizeout_cap (or scratch_cap) too small for this tile.
k_ra8_err_validation_failedIndex/stream window corrupt, short read, or decoded size mismatch.
otherPropagated from pread.
Precondition
info came from a successful jof_parse() over the same backing.
out_px holds out_cap writable bytes.
Postcondition
On success exactly (*out_w) * (*out_h) * bpp bytes are valid.
On any error out_px content is unspecified.
Note
Thread-safe for distinct buffers (no shared state).
See also
jof_parse()
Since
0.1.0

Definition at line 637 of file jof.c.

References jof_info_t::bpp, internal_fetch_decode(), internal_read_args_ok(), jof_tile_dims(), k_ra8_err_invalid_size, k_ra8_ok, and jof_info_t::tile_cols.

Referenced by internal_audit_tile(), internal_compare(), internal_preflight(), longstrip_tile_decode(), and mg_tile_decode().

◆ jof_stored_bound()

uint32_t jof_stored_bound ( uint32_t raw_bytes)
nodiscard

Worst-case stored-tile byte bound for scratch/cell sizing.

For raw tiles the stored stream equals the payload; for deflate the stored stream is bounded by the incompressible-input expansion raw + raw/8 + 256 (a safe over-estimate of the miniz raw-DEFLATE worst case). Size jof_read_tile()'s scratch with this over raw = tile_w * tile_h * bpp.

Parameters
[in]raw_bytesDecoded tile payload size in bytes.
Returns
Upper bound on the stored tile stream length, bytes.
Return values
>=raw_bytesAlways at least the payload size plus margin.
Precondition
raw_bytes is a real tile payload size (fits uint32_t with margin).
The atlas codec is one of jof_codec_t.
Postcondition
No state mutated.
Return >= raw_bytes + 256.
Note
Thread-safe (pure).
Since
0.1.0

Worst-case stored-tile byte bound for scratch/cell sizing.

Definition at line 439 of file jof.c.

References k_jof_bound_add, and k_jof_bound_div.

Referenced by internal_carve_pixel_path(), internal_require_jof(), jof_audit_requirements(), jof_work_bytes(), priv_viewer_open_jof(), and ra8_fmt_jof_verify_requirements().

◆ jof_tile_dims()

ra8_err_t jof_tile_dims ( const jof_info_t * info,
uint16_t tile_x,
uint16_t tile_y,
uint16_t * out_w,
uint16_t * out_h )
nodiscard

Report the true (edge-clamped) pixel dimensions of one tile.

Parameters
[in]infoParsed atlas geometry.
[in]tile_xTile column, [0, tile_cols).
[in]tile_yTile row, [0, tile_rows).
[out]out_wReceives the tile's width, pixels.
[out]out_hReceives the tile's height, pixels.
Returns
ra8_err_t
Return values
k_ra8_okDimensions reported.
k_ra8_err_null_ptrinfo, out_w, or out_h is NULL.
k_ra8_err_out_of_rangetile_x / tile_y outside the grid.
Precondition
info came from a successful jof_parse().
out_w and out_h are writable.
Postcondition
On success both outputs are in [1, tile_w] / [1, tile_h].
On any error neither output is modified.
Note
Thread-safe (pure over its inputs).
Since
0.1.0

Definition at line 414 of file jof.c.

References jof_info_t::height, k_ra8_err_out_of_range, k_ra8_ok, RA8_CHECK_NULL_PTR, s_tag, jof_info_t::tile_cols, jof_info_t::tile_h, jof_info_t::tile_rows, jof_info_t::tile_w, and jof_info_t::width.

Referenced by internal_audit_tile(), and jof_read_tile().