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

Zero-heap raster image decode + nearest-neighbour scale + blit (#106). More...

#include "reflow_image.h"
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_gfx.h"
#include "ra8_img_arena.h"
#include "ra8_log.h"
#include "reflow_svg.h"
#include "stb_image.h"
Include dependency graph for reflow_image.c:

Go to the source code of this file.

Enumerations

enum  ra8_img_pack_t : uint8_t {
  k_ra8_img_req_rgb = 3 ,
  k_ra8_img_ch_r = 0 ,
  k_ra8_img_ch_g = 1 ,
  k_ra8_img_ch_b = 2 ,
  k_ra8_img_min_edge = 1
}
 Pixel-packing and channel constants (no magic numbers). More...
enum  ra8_img_shift_t : uint8_t {
  k_ra8_img_shift_r = 16 ,
  k_ra8_img_shift_g = 8
}
 Channel shifts to assemble a 0x00RRGGBB colour for ra8_gfx (no magics). More...

Functions

ra8_err_t ra8_img_probe_size (const uint8_t *bytes, size_t len, int32_t *out_w, int32_t *out_h)
 Probe an image's intrinsic dimensions without a full decode.
static void internal_fit_box (int32_t src_w, int32_t src_h, int32_t box_w, int32_t box_h, int32_t *fit_w, int32_t *fit_h)
 Compute the aspect-preserving fit rectangle for an image in a box.
static ra8_err_t internal_decode_fail (void)
 Map a decode failure to the closest ra8_err_t via stbi_failure_reason.
static void internal_blit_scaled (const uint8_t *pixels, int32_t src_w, int32_t src_h, int32_t fit_w, int32_t fit_h, int32_t dst_x, int32_t dst_y)
 Nearest-neighbour blit a decoded RGB image into the bound framebuffer.
static void internal_arena_release (ra8_img_arena_t *arena)
 Unbind the decode arena and force it back to the fully-drained state.
ra8_err_t ra8_img_decode_blit (ra8_img_arena_t *arena, const uint8_t *bytes, size_t len, int32_t dst_x, int32_t dst_y, int32_t box_w, int32_t box_h, int32_t *out_w, int32_t *out_h)
 Implementation of ra8_img_decode_blit() – nearest-neighbour scale.

Variables

static const char *const s_tag_img = "ra8_img"
 Log tag for the image decode/blit module.

Detailed Description

Zero-heap raster image decode + nearest-neighbour scale + blit (#106).

Implements reflow_image.h. The decode runs through the vendored stb_image (built once in apps/shared_libs/third_party/stb/stb_image_impl.c) with its allocator redirected to a caller-bound bump arena, so no malloc is reached. The blit is an integer nearest-neighbour scale-to-fit into a layout box, emitting one ra8_gfx_pixel() per destination pixel (which clips to the framebuffer).

[Ring 4 / Reflow] {World: NS}

Since
0.1.0

Definition in file reflow_image.c.

Enumeration Type Documentation

◆ ra8_img_pack_t

enum ra8_img_pack_t : uint8_t

Pixel-packing and channel constants (no magic numbers).

Enumerator
k_ra8_img_req_rgb 

Desired channel count requested from stb_image.

k_ra8_img_ch_r 

Red byte offset within an RGB triple.

k_ra8_img_ch_g 

Green byte offset within an RGB triple.

k_ra8_img_ch_b 

Blue byte offset within an RGB triple.

k_ra8_img_min_edge 

Minimum scaled / box edge length, pixels.

Definition at line 42 of file reflow_image.c.

◆ ra8_img_shift_t

enum ra8_img_shift_t : uint8_t

Channel shifts to assemble a 0x00RRGGBB colour for ra8_gfx (no magics).

Enumerator
k_ra8_img_shift_r 

Red channel shift into 0x00RRGGBB.

k_ra8_img_shift_g 

Green channel shift into 0x00RRGGBB.

Definition at line 54 of file reflow_image.c.

Function Documentation

◆ internal_arena_release()

void internal_arena_release ( ra8_img_arena_t * arena)
static

Unbind the decode arena and force it back to the fully-drained state.

Calls ra8_img_arena_unbind() to clear the module-static pointer that redirects stb_image allocations, then resets both bookkeeping fields of the arena struct to zero: offset (the bump pointer) and live (the outstanding allocation count). This guarantees the arena is ready for reuse and that no stale stb_image allocation callbacks can reach it after the call. The base and cap fields, which are owned by the caller, are left untouched. Called on every return path of ra8_img_decode_blit() – both on success after stbi_image_free() and on failure before returning an error code. Internal helper for ra8_img_decode_blit().

Parameters
[in,out]arenaBump arena to unbind and reset; must not be NULL.
Returns
Nothing.
Precondition
arena is a valid non-NULL pointer to a bound or partially-used ra8_img_arena_t that was previously passed to ra8_img_arena_bind().
The stb_image allocator is currently redirected to arena (i.e., ra8_img_arena_bind() has been called and not yet paired with unbind).
Postcondition
arena->offset == 0 and arena->live == 0.
The module-static current-arena pointer is NULL; no further stb allocation callbacks can reach arena.
Note
Not thread-safe; uses the same module-static arena pointer as the stb_image hook. Caller must ensure single-threaded access.
Since
0.1.0

Definition at line 269 of file reflow_image.c.

References ra8_img_arena_t::live, ra8_img_arena_t::offset, and ra8_img_arena_unbind().

Referenced by ra8_img_decode_blit().

◆ internal_blit_scaled()

void internal_blit_scaled ( const uint8_t * pixels,
int32_t src_w,
int32_t src_h,
int32_t fit_w,
int32_t fit_h,
int32_t dst_x,
int32_t dst_y )
static

Nearest-neighbour blit a decoded RGB image into the bound framebuffer.

Iterates over every pixel in the fit_w x fit_h destination rectangle. For each destination pixel (dx, dy) the corresponding source row and column are computed with integer division scaled by int64 products to avoid overflow: map_y = (dy * src_h) / fit_h and map_x = (dx * src_w) / fit_w. The RGB triple at that position in the row-major pixels buffer is then packed into a 0x00RRGGBB word and emitted via ra8_gfx_pixel(dst_x + dx, dst_y + dy, color), which clips coordinates that fall outside the bound framebuffer. The function reads every pixel in the destination rectangle once; no sub-pixel filtering is applied. Internal helper for ra8_img_decode_blit().

Parameters
[in]pixelsDecoded source buffer, row-major RGB triples, size src_w * src_h * 3 bytes; must not be NULL.
[in]src_wSource width, pixels (>= 1).
[in]src_hSource height, pixels (>= 1).
[in]fit_wDestination width, pixels (>= 1).
[in]fit_hDestination height, pixels (>= 1).
[in]dst_xDestination left edge in framebuffer coordinates.
[in]dst_yDestination top edge in framebuffer coordinates.
Returns
Nothing.
Precondition
pixels is a valid pointer to src_w * src_h * 3 readable bytes.
All dimension arguments (src_w, src_h, fit_w, fit_h) are >= 1 so neither loop bound is zero and no division by zero occurs.
Postcondition
Exactly fit_w * fit_h calls to ra8_gfx_pixel() have been made.
The pixels buffer is not modified (read-only traversal).
Note
Not thread-safe; both ra8_gfx_pixel() and the stb arena backing pixels use module-static state. Caller must ensure exclusive access.
Since
0.1.0

Definition at line 217 of file reflow_image.c.

References k_ra8_img_ch_b, k_ra8_img_ch_g, k_ra8_img_ch_r, k_ra8_img_req_rgb, k_ra8_img_shift_g, k_ra8_img_shift_r, and ra8_gfx_pixel().

Referenced by ra8_img_decode_blit().

◆ internal_decode_fail()

ra8_err_t internal_decode_fail ( void )
static

Map a decode failure to the closest ra8_err_t via stbi_failure_reason.

Queries stbi_failure_reason() immediately after a failed stbi_load_from_memory() call and inspects the returned string for the substring "outofmem". When that tag is present the arena exhausted its capacity before the decode completed; the function returns k_ra8_err_no_mem so the caller can report a memory shortage rather than a format error. Any other reason string (corrupt header, unsupported colour depth, unsupported format, etc.) maps to k_ra8_err_not_supported. A NULL reason string is treated the same way as an unrecognised string. Internal helper for ra8_img_decode_blit().

Returns
ra8_err_t Classification of the most-recent stb_image failure.
Return values
k_ra8_err_no_memThe "outofmem" tag was found in the reason.
k_ra8_err_not_supportedAny other failure (corrupt or unsupported).
Precondition
stbi_load_from_memory() has just returned NULL (sets the reason).
The stb_image thread-local reason pointer is valid for this thread.
Postcondition
No stb_image state is modified; the reason string is only read.
The returned code is one of the two documented retval constants.
Note
Not thread-safe; stb_image stores the reason in a module-static variable. Caller must ensure single-threaded access.
Since
0.1.0

Definition at line 163 of file reflow_image.c.

References k_ra8_err_no_mem, k_ra8_err_not_supported, and strstr().

Referenced by ra8_img_decode_blit().

◆ internal_fit_box()

void internal_fit_box ( int32_t src_w,
int32_t src_h,
int32_t box_w,
int32_t box_h,
int32_t * fit_w,
int32_t * fit_h )
static

Compute the aspect-preserving fit rectangle for an image in a box.

Picks the largest integer scale that maps the source into the box while preserving aspect ratio. The tighter axis is determined by comparing box_w * src_h with box_h * src_w using int64 products to prevent overflow on large dimensions. The width-constrained branch scales height proportionally to width; the height-constrained branch scales width proportionally to height. Both output dimensions are clamped to at least k_ra8_img_min_edge (1 pixel) so downstream callers never receive a zero-size rectangle. Internal helper for ra8_img_decode_blit().

Parameters
[in]src_wSource width, pixels (>= 1).
[in]src_hSource height, pixels (>= 1).
[in]box_wBox width, pixels (>= 1).
[in]box_hBox height, pixels (>= 1).
[out]fit_wReceives the scaled width, pixels (>= 1).
[out]fit_hReceives the scaled height, pixels (>= 1).
Returns
Nothing.
Precondition
All four dimension arguments are greater than or equal to 1.
fit_w and fit_h are valid, writable, non-NULL pointers.
Postcondition
*fit_w and *fit_h are each >= 1 (clamped to k_ra8_img_min_edge).
The aspect ratio of the output is as close as integer division allows to the aspect ratio of the source.
Note
Not thread-safe; intended to be called only from ra8_img_decode_blit().
Since
0.1.0

Definition at line 113 of file reflow_image.c.

References k_ra8_img_min_edge.

Referenced by ra8_img_decode_blit().

◆ ra8_img_decode_blit()

ra8_err_t ra8_img_decode_blit ( ra8_img_arena_t * arena,
const uint8_t * bytes,
size_t len,
int32_t dst_x,
int32_t dst_y,
int32_t box_w,
int32_t box_h,
int32_t * out_w,
int32_t * out_h )
nodiscard

◆ ra8_img_probe_size()

ra8_err_t ra8_img_probe_size ( const uint8_t * bytes,
size_t len,
int32_t * out_w,
int32_t * out_h )
nodiscard

Probe an image's intrinsic dimensions without a full decode.

Wraps stbi_info_from_memory – lets the layout pass size an <img> box from the source dimensions before deciding to decode + blit. Allocates nothing.

Parameters
[in]bytesEncoded image bytes.
[in]lenLength of bytes.
[out]out_wReceives intrinsic width.
[out]out_hReceives intrinsic height.
Returns
ra8_err_t
Return values
k_ra8_okDimensions read.
k_ra8_err_null_ptrAny pointer argument is NULL.
k_ra8_err_not_supportedstb_image could not parse the header.
Precondition
bytes holds len bytes; out_w / out_h are writable.
Postcondition
On success *out_w / *out_h are the source pixel dimensions.
Note
Pure read of bytes; thread-safe.
Since
0.1.0

Definition at line 59 of file reflow_image.c.

References k_ra8_err_not_supported, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_log_error, ra8_svg_is_svg(), ra8_svg_size(), and s_tag_img.

Referenced by internal_image_resolve_size(), and internal_probe_page().

Variable Documentation

◆ s_tag_img

const char* const s_tag_img = "ra8_img"
static

Log tag for the image decode/blit module.

Definition at line 36 of file reflow_image.c.

Referenced by ra8_img_decode_blit(), and ra8_img_probe_size().