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

Grayscale image transcode stage (4-bpp / 8-bpp) for the on-device EPUB compiler (#149). More...

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

Go to the source code of this file.

Enumerations

enum  ra8_rabook_gray4_consts_t : uint16_t {
  k_ra8_rabook_gray4_gray_levels = 16U ,
  k_ra8_rabook_gray4_quant_div = 17U ,
  k_ra8_rabook_gray4_round_half = 8U ,
  k_ra8_rabook_gray4_nib_max = 15U ,
  k_ra8_rabook_gray4_nib_per_byte = 2U
}
 Compile-time constants for the gray4 transcode stage. More...

Functions

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.
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_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_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).

Detailed Description

Grayscale image transcode stage (4-bpp / 8-bpp) for the on-device EPUB compiler (#149).

Converts a decoded grayscale pixel buffer (one byte per pixel, 0-255) into the panel-native 4-bpp nibble format used by book_image_t. The pipeline is three independently-testable steps:

  1. ra8_rabook_gray4_output_dims – compute the output size that keeps the longer edge within the caller's opt-in clamp (none by default).
  2. ra8_rabook_gray4_downscale – bilinear-interpolate from the (possibly large) source buffer into a caller-owned intermediate buffer.
  3. ra8_rabook_gray4_encode – quantise every pixel to 4 bits and pack two pixels per byte (high nibble = even pixel, low nibble = odd pixel), matching the byte layout of tools/epub_compile/src/epub_compile.py.
Quantisation rule
Grayscale value v (0-255) maps to nibble n = (v + 8) / 17, clamped to [0, 15]. This is the round-to-nearest equivalent of the desktop palette quantisation (16 evenly-spaced entries at i * 17, i = 0..15). Downscaled images are byte-identical between host and device (issue #213): the desktop tool resamples and quantises with this exact integer kernel, mirrored in tools/epub_compile/src/gray4_kernel.py, so both sides emit the same pixels – no LANCZOS-vs-bilinear exception. test_ra8_rabook_downscale_parity.c gates that parity against a generated golden (rabook_downscale_parity_fixture.h).
Zero allocation
No malloc. All working storage (source pixels, intermediate scaled buffer) is caller-owned.
Note
Not thread-safe.
See also
rabook_compile.h Builder back-end this feeds into.
book_image_t On-disk descriptor stored in the RABOOK1 blob.
Since
Version 0.1.0

[Ring 4 / EPUB Compiler] {World: NS}

Definition in file ra8_rabook_gray4.h.

Enumeration Type Documentation

◆ ra8_rabook_gray4_consts_t

enum ra8_rabook_gray4_consts_t : uint16_t

Compile-time constants for the gray4 transcode stage.

k_ra8_rabook_gray4_gray_levels and k_ra8_rabook_gray4_quant_div define the 16-level even palette (entry i is at grayscale value i * k_ra8_rabook_gray4_quant_div). There is deliberately NO baked-in max-edge constant: the compile preserves source resolution by default (the planned zoom loupe needs full-resolution manga pages), and any downscale clamp is the caller's opt-in via the pipeline scratch's max_image_edge field, mirroring the desktop tool's opt-in --max-edge knob.

Invariant
k_ra8_rabook_gray4_quant_div * (k_ra8_rabook_gray4_gray_levels - 1) == 255.
// Compute output buffer size for an opt-in clamp chosen by the caller:
uint16_t ow, oh;
ra8_rabook_gray4_output_dims(src_w, src_h, caller_max_edge, &ow, &oh);
uint32_t nibble_bytes = ((uint32_t)ow * oh + 1U) / k_ra8_rabook_gray4_nib_per_byte;
@ k_ra8_rabook_gray4_nib_per_byte
Pixels packed per output byte.
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.
See also
ra8_rabook_gray4_output_dims
ra8_rabook_gray4_encode
Since
Version 0.1.0
Enumerator
k_ra8_rabook_gray4_gray_levels 

Palette depth: 16 evenly-spaced levels.

k_ra8_rabook_gray4_quant_div 

Palette step: 255 / 15 rounds to 17.

k_ra8_rabook_gray4_round_half 

Added before quant divide to round-to-nearest.

k_ra8_rabook_gray4_nib_max 

Maximum nibble value (4 bits unsigned).

k_ra8_rabook_gray4_nib_per_byte 

Pixels packed per output byte.

Definition at line 79 of file ra8_rabook_gray4.h.

Function Documentation

◆ ra8_rabook_gray4_downscale()

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).

Each output pixel is the bilinear interpolation of the four nearest source pixels at the corresponding sample point, computed in Q16.16 fixed-point arithmetic (no floating-point, no malloc). The mapping places the sample for output pixel dx at source x = dx * src_w / dst_w (and similarly for y); this is a left-aligned sample grid that is deterministic for any src/dst size pair.

When dst_w == src_w and dst_h == src_h the output is an exact copy. When src_w or src_h is 0 the output is zeroed and k_ra8_ok returned.

Parameters
[in]srcSource buffer: src_w * src_h bytes, one byte per pixel.
[in]src_wSource width in pixels.
[in]src_hSource height in pixels.
[out]dstDestination buffer: must hold dst_w * dst_h writable bytes.
[in]dst_wDestination width (> 0).
[in]dst_hDestination height (> 0).
Returns
Error code.
Return values
k_ra8_okResampled successfully.
k_ra8_err_null_ptrsrc or dst is NULL.
k_ra8_err_invalid_argdst_w or dst_h is 0.
Precondition
src holds at least src_w * src_h readable bytes.
dst holds at least dst_w * dst_h writable bytes.
Postcondition
Every byte in dst[0..dst_w*dst_h) holds the interpolated value.
The source buffer is unchanged.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 194 of file ra8_rabook_gray4.c.

References internal_bilinear_sample(), k_fp_shift, k_ra8_err_invalid_arg, k_ra8_ok, memset(), RA8_CHECK_NULL_PTR, ra8_log_error, and s_tag.

Referenced by internal_downscale_if_needed(), and internal_scale().

◆ ra8_rabook_gray4_encode()

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.

For each source pixel v the nibble is n = (v + 8) / 17, clamped to [0, 15] (round-to-nearest quantisation to the 16-level palette at {0, 17, 34, ..., 255}). Pairs of nibbles are packed one per byte: byte[i] = (nib[2i] << 4) | nib[2i+1]. For an odd pixel count the last byte holds the final nibble in its high half and its low half is zero.

Output size is ceil(w * h / 2) == (w * h + 1) / 2 bytes.

The packing order is byte-identical to epub_compile.py for the same input pixel values.

Parameters
[in]gray_pixelsGrayscale source: w * h bytes, 0-255 each.
[in]wImage width in pixels.
[in]hImage height in pixels.
[out]outOutput nibble buffer; must hold at least (w*h+1)/2 bytes.
[in]out_capCapacity of out in bytes.
[out]out_sizeOn success: bytes written (== (w*h+1)/2).
Returns
Error code.
Return values
k_ra8_okEncoded successfully.
k_ra8_err_null_ptrgray_pixels, out, or out_size is NULL.
k_ra8_err_no_memout_cap < (w*h+1)/2.
Precondition
gray_pixels holds at least w * h readable bytes.
out_cap >= (w * h + 1) / 2.
Postcondition
*out_size == (w * h + 1) / 2.
Every output nibble n satisfies 0 <= n <= 15.
Note
When w or h is 0, *out_size is set to 0 and k_ra8_ok is returned.
Not thread-safe.
Since
Version 0.1.0

Definition at line 229 of file ra8_rabook_gray4.c.

References internal_pack_nibbles(), k_ra8_err_no_mem, k_ra8_ok, k_ra8_rabook_gray4_nib_per_byte, memset(), RA8_CHECK_NULL_PTR, ra8_log_error, and s_tag.

Referenced by internal_encode(), and internal_encode_gray().

◆ ra8_rabook_gray4_output_dims()

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.

If max(src_w, src_h) <= max_edge the source dimensions are returned unchanged. Otherwise both dimensions are scaled by max_edge / longer_edge (rounded to nearest, minimum 1 each) so the image fits the panel class without distorting the aspect ratio. The result is the exact size the caller must allocate for the intermediate downscale buffer.

Parameters
[in]src_wSource width in pixels.
[in]src_hSource height in pixels.
[in]max_edgeMaximum allowed length of the longer edge.
[out]out_wScaled output width (>= 1 when src_w, src_h and max_edge are all > 0; 0 otherwise, per the
Note
below).
Parameters
[out]out_hScaled output height (>= 1 when src_w, src_h and max_edge are all > 0; 0 otherwise, per the
Note
below).
Precondition
out_w is non-NULL.
out_h is non-NULL.
Postcondition
If max(src_w, src_h) <= max_edge then *out_w == src_w and *out_h == src_h.
If scaling is required then max(*out_w, *out_h) <= max_edge.
Note
Not thread-safe.
When src_w, src_h, or max_edge is 0 both outputs are set to 0.
Since
Version 0.1.0

Definition at line 159 of file ra8_rabook_gray4.c.

Referenced by internal_output_dims(), and internal_transcode_image().

◆ ra8_rabook_gray8_encode()

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).

The 8-bpp counterpart of ra8_rabook_gray4_encode, selected when a device profile wants the lossless grayscale source instead of the half-size 4-bpp packing. There is no quantise and no packing: the k_book_pixfmt_gray8 pool bytes ARE the decoded (and possibly downscaled) gray pixels, so out[i] == gray_pixels[i] for every pixel. Keeping it a distinct, validated call – rather than a bare memcpy at the call site – means the transcode stage always states the depth it produced and the capacity is checked once, here.

Output size is w * h bytes (0 when either dimension is 0).

Parameters
[in]gray_pixelsGrayscale source: w * h bytes, 0-255 each.
[in]wImage width in pixels.
[in]hImage height in pixels.
[out]outOutput buffer; must hold at least w * h bytes.
[in]out_capCapacity of out in bytes.
[out]out_sizeOn success: bytes written (== w * h).
Returns
Error code.
Return values
k_ra8_okCopied successfully.
k_ra8_err_null_ptrgray_pixels, out, or out_size is NULL.
k_ra8_err_no_memout_cap < w * h.
Precondition
gray_pixels holds at least w * h readable bytes.
out_cap >= w * h, and out does not overlap gray_pixels.
Postcondition
*out_size == w * h (0 when w or h is 0).
out[0..w*h) equals gray_pixels[0..w*h) byte for byte.
Note
When w or h is 0, *out_size is set to 0 and k_ra8_ok is returned.
Not thread-safe.
See also
ra8_rabook_gray4_encode The 4-bpp (quantise + nibble-pack) counterpart.
Since
Version 0.1.0

Definition at line 260 of file ra8_rabook_gray4.c.

References k_ra8_err_no_mem, k_ra8_ok, memcpy(), RA8_CHECK_NULL_PTR, ra8_log_error, and s_tag.

Referenced by internal_encode(), and internal_encode_gray().