ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_viewer_comic.c
Go to the documentation of this file.
1
12
13#include <stddef.h>
14#include <stdint.h>
15
16#include "comic.h"
17#include "ra8_attributes.h"
18#include "ra8_decomp_limits.h"
19#include "ra8_err.h"
20#include "ra8_gfx.h"
21#include "ra8_img_arena.h"
23#include "reflow_image.h"
24
26typedef struct {
27 int32_t x;
28 int32_t y;
29 int32_t width;
30 int32_t height;
32
49RA8_INTERNAL static void internal_fit_centered(int32_t source_width,
50 int32_t source_height,
51 int32_t target_width,
52 int32_t target_height,
54{
55 const int64_t tw = (int64_t)target_width;
56 const int64_t th = (int64_t)target_height;
57 int64_t width = tw;
58 int64_t height = ((int64_t)source_height * tw) / (int64_t)source_width;
59 if (height > th) {
60 height = th;
61 width = ((int64_t)source_width * th) / (int64_t)source_height;
62 }
63 if (width < 1) {
64 width = 1;
65 }
66 if (height < 1) {
67 height = 1;
68 }
69 *box = (viewer_fit_box_t){.x = (int32_t)((tw - width) / 2),
70 .y = (int32_t)((th - height) / 2),
71 .width = (int32_t)width,
72 .height = (int32_t)height};
73}
74
89RA8_INTERNAL static void internal_cap_render(uint32_t native_width,
90 uint32_t native_height,
91 uint32_t* render_width,
92 uint32_t* render_height)
93{
94 const uint32_t edge = (uint32_t)k_ra8_gfx_max_dim;
95 uint32_t width = native_width;
96 uint32_t height = native_height;
97 if (width > edge) {
98 height = (uint32_t)(((uint64_t)height * (uint64_t)edge) / (uint64_t)width);
99 width = edge;
100 }
101 if (height > edge) {
102 width = (uint32_t)(((uint64_t)width * (uint64_t)edge) / (uint64_t)height);
103 height = edge;
104 }
105 *render_width = (width == 0U) ? 1U : width;
106 *render_height = (height == 0U) ? 1U : height;
107}
108
127internal_read_page(ra8_viewer_reader_t* reader, uint32_t page, size_t* out_bytes)
128{
129 uint64_t declared = 0U;
130 ra8_err_t error =
131 comic_page_info(&reader->comic.archive, page, nullptr, 0U, nullptr, &declared, nullptr);
132 if (error == k_ra8_ok) {
133 error = ra8_decomp_check_declared(&reader->limits, reader->file.size, declared);
134 }
135 if ((error == k_ra8_ok) && (declared > (uint64_t)reader->comic.page_cap)) {
137 }
138 if (error != k_ra8_ok) {
139 return error;
140 }
141 *out_bytes = 0U;
142 error = comic_page_read(&reader->comic.archive,
143 page,
144 reader->comic.page,
145 reader->comic.page_cap,
146 out_bytes);
147 if ((error == k_ra8_ok) && ((uint64_t)*out_bytes != declared)) {
149 }
150 return error;
151}
152
170{
171 size_t encoded = 0U;
172 ra8_err_t error = internal_read_page(reader, page, &encoded);
173 int32_t width = 0;
174 int32_t height = 0;
175 if (error == k_ra8_ok) {
176 ra8_img_arena_t arena = {.base = reader->comic.arena, .cap = reader->comic.arena_cap};
177 ra8_img_arena_bind(&arena);
178 error = ra8_img_probe_size(reader->comic.page, encoded, &width, &height);
180 }
181 if ((error == k_ra8_ok) && ((width <= 0) || (height <= 0))) {
183 }
184 if (error == k_ra8_ok) {
185 internal_cap_render((uint32_t)width,
186 (uint32_t)height,
187 &reader->tile_wpx[page],
188 &reader->tile_hpx[page]);
189 }
190 return error;
191}
192
211internal_decode(ra8_viewer_reader_t* reader, uint32_t page, const viewer_fit_box_t* fit)
212{
213 size_t encoded = 0U;
214 ra8_err_t error = internal_read_page(reader, page, &encoded);
215 if (error == k_ra8_ok) {
216 error = ra8_gfx_clear((uint32_t)k_viewer_background);
217 }
218 if (error == k_ra8_ok) {
219 ra8_img_arena_t arena = {.base = reader->comic.arena, .cap = reader->comic.arena_cap};
220 error = ra8_img_decode_blit(&arena,
221 reader->comic.page,
222 encoded,
223 fit->x,
224 fit->y,
225 fit->width,
226 fit->height,
227 nullptr,
228 nullptr);
229 }
230 return error;
231}
232
233size_t priv_viewer_comic_read(void* ctx, uint64_t offset, void* buffer, size_t length)
234{
235 size_t got = 0U;
236 return (priv_viewer_pread(ctx, offset, (uint8_t*)buffer, length, &got) == k_ra8_ok) ? got : 0U;
237}
238
240{
241 return comic_open(&reader->comic.archive,
243 &reader->file,
244 reader->file.size,
245 reader->comic.pages,
246 (uint32_t)k_viewer_comic_page_cap,
247 reader->comic.names,
248 (uint32_t)k_viewer_comic_name_bytes);
249}
250
252{
253 for (uint32_t page = 0U; page < reader->tile_n; ++page) {
254 const ra8_err_t error = internal_probe_page(reader, page);
255 if (error != k_ra8_ok) {
256 return error;
257 }
258 }
259 return k_ra8_ok;
260}
261
263{
264 const uint32_t source_width = reader->tile_wpx[page];
265 const uint32_t source_height = reader->tile_hpx[page];
266 viewer_fit_box_t fit = {};
267 internal_fit_centered((int32_t)source_width,
268 (int32_t)source_height,
269 (int32_t)k_ra8_viewer_fb_width,
270 (int32_t)k_ra8_viewer_fb_height,
271 &fit);
272 const ra8_err_t error = ra8_gfx_init(reader->fb,
276 return (error == k_ra8_ok) ? internal_decode(reader, page, &fit) : error;
277}
278
280 uint32_t index,
281 uint16_t* pixels,
282 size_t pixel_bytes,
283 uint32_t* width,
284 uint32_t* height)
285{
286 const uint32_t render_width = reader->tile_wpx[index];
287 const uint32_t render_height = reader->tile_hpx[index];
288 const uint64_t required =
289 (uint64_t)render_width * (uint64_t)render_height * (uint64_t)sizeof(uint16_t);
290 if ((required > (uint64_t)pixel_bytes) || (render_width > UINT16_MAX) ||
291 (render_height > UINT16_MAX)) {
293 }
294 ra8_err_t error =
295 ra8_gfx_init(pixels, (uint16_t)render_width, (uint16_t)render_height, k_ra8_gfx_format_rgb565);
296 if (error == k_ra8_ok) {
297 const viewer_fit_box_t fit = {.x = 0,
298 .y = 0,
299 .width = (int32_t)render_width,
300 .height = (int32_t)render_height};
301 error = internal_decode(reader, index, &fit);
302 }
303 const ra8_err_t restored = ra8_gfx_init(reader->fb,
307 if ((error == k_ra8_ok) && (restored != k_ra8_ok)) {
308 error = restored;
309 }
310 if (error == k_ra8_ok) {
311 *width = render_width;
312 *height = render_height;
313 }
314 return error;
315}
Unified demand-paged reader for comic-book archives – CBZ (ZIP) and CBR (RAR).
ra8_err_t comic_page_read(comic_t *c, uint32_t page, uint8_t *buf, size_t cap, size_t *got)
Extract one page's encoded image bytes for the decoder.
Definition comic.c:472
ra8_err_t comic_open(comic_t *c, comic_read_fn read, void *ctx, uint64_t size, comic_page_t *pages, uint32_t page_cap, char *names, uint32_t names_cap)
Open a comic archive (CBZ or CBR) and build its sorted page index.
Definition comic.c:390
ra8_err_t comic_page_info(const comic_t *c, uint32_t page, char *name_buf, uint16_t name_cap, uint16_t *out_name_len, uint64_t *out_raw_size, uint8_t *out_extractable)
Read one page's manifest entry: name, encoded length, decodability.
Definition comic.c:434
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Unified decompression-limits policy: one bound set for every decoder.
ra8_err_t ra8_decomp_check_declared(const ra8_decomp_limits_t *limits, uint64_t comp_size, uint64_t out_size)
Header-level check of a member's declared sizes against a policy.
Error Code Definitions for ra8-firmware.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Software 2D graphics primitives layered on top of a caller-ownedframebuffer (DRW / D/AVE 2D / GLCDC r...
@ k_ra8_gfx_format_rgb565
16-bit RGB565, little-endian in memory.
Definition ra8_gfx.h:40
@ k_ra8_gfx_max_dim
Maximum supported edge length.
Definition ra8_gfx.h:51
ra8_err_t ra8_gfx_clear(uint32_t color)
Fill the bound framebuffer's clip region with a single colour.
ra8_err_t ra8_gfx_init(void *fb, uint16_t width, uint16_t height, ra8_gfx_format_t format)
Bind ra8_gfx to a caller-owned framebuffer.
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.
static void internal_fit_centered(int32_t source_width, int32_t source_height, int32_t target_width, int32_t target_height, viewer_fit_box_t *box)
Fit an image into a target while preserving aspect ratio.
static ra8_err_t internal_decode(ra8_viewer_reader_t *reader, uint32_t page, const viewer_fit_box_t *fit)
Decode one page into the currently selected graphics target.
size_t priv_viewer_comic_read(void *ctx, uint64_t offset, void *buffer, size_t length)
Adapt exact descriptor reads to the comic size-returning seam.
ra8_err_t priv_viewer_render_comic(ra8_viewer_reader_t *reader, uint32_t page)
Render one comic page into the fixed framebuffer.
static void internal_cap_render(uint32_t native_width, uint32_t native_height, uint32_t *render_width, uint32_t *render_height)
Cap a page to the graphics engine edge limit.
ra8_err_t priv_viewer_size_comic_tiles(ra8_viewer_reader_t *reader)
Probe every comic page into the bound dimension arrays.
static ra8_err_t internal_read_page(ra8_viewer_reader_t *reader, uint32_t page, size_t *out_bytes)
Extract one bounded encoded page into its resident slice.
ra8_err_t priv_viewer_tile_comic(ra8_viewer_reader_t *reader, uint32_t index, uint16_t *pixels, size_t pixel_bytes, uint32_t *width, uint32_t *height)
Render one comic page into caller-owned RGB565 storage.
static ra8_err_t internal_probe_page(ra8_viewer_reader_t *reader, uint32_t page)
Probe one page and publish its bounded render dimensions.
ra8_err_t priv_viewer_open_comic(ra8_viewer_reader_t *reader)
Open a bare CBZ/CBR/CBT engine over a bound reader.
@ k_ra8_viewer_fb_height
Framebuffer height in pixels.
@ k_ra8_viewer_fb_width
Framebuffer width in pixels.
struct ra8_viewer_reader ra8_viewer_reader_t
Opaque state bound inside caller-owned workspace.
Cross-translation-unit state for the bounded JOF/comic viewer.
ra8_err_t priv_viewer_pread(void *ctx, uint64_t offset, uint8_t *buffer, size_t length, size_t *out_read)
JOF positional-reader seam over viewer_file_ctx_t.
size_t priv_viewer_comic_read(void *ctx, uint64_t offset, void *buffer, size_t length)
Adapt exact descriptor reads to the comic size-returning seam.
@ k_viewer_background
White graphics clear colour.
@ k_viewer_comic_page_cap
Maximum indexed pages.
@ k_viewer_comic_name_bytes
Member-name arena bytes.
Zero-heap raster image decode + scale + blit for reflow (#106).
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)
Decode bytes and blit it, scaled to fit, into the bound framebuffer.
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.
Caller-owned bump arena backing a single image decode.
uint32_t * tile_hpx
Native height per viewport tile.
uint32_t * tile_wpx
Native width per viewport tile.
viewer_comic_t comic
Comic engine and caller slices.
uint16_t * fb
Fixed headless framebuffer.
viewer_file_ctx_t file
Raw source descriptor.
ra8_decomp_limits_t limits
Shared untrusted-input policy.
uint32_t tile_n
Populated dimension entries.
uint8_t * page
Resident encoded-image bytes.
comic_t archive
Open CBZ/CBR/CBT facade.
char * names
Resident member-name arena.
size_t page_cap
Encoded-image capacity in bytes.
uint8_t * arena
stb caller-owned decode arena.
comic_page_t * pages
Resident sorted page index.
size_t arena_cap
Decode-arena capacity in bytes.
uint64_t size
Document length in bytes.
Destination rectangle for aspect-preserving page placement.
int32_t x
Left edge in target pixels.
int32_t height
Render height in pixels.
int32_t y
Top edge in target pixels.
int32_t width
Render width in pixels.