ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_rabook_raster.c
Go to the documentation of this file.
1
15
16#include "ra8_rabook_raster.h"
17
18#include <limits.h>
19#include <stddef.h>
20#include <stdint.h>
21#include <string.h>
22
23#include "ra8_attributes.h"
24#include "ra8_img_arena.h"
25#include "ra8_rabook_gray4.h"
26#include "ra8_webp.h"
27#include "stb_image.h"
28
39
57RA8_INTERNAL static bool internal_is_webp(const uint8_t* source, size_t source_size)
58{
59 static const uint8_t k_riff[] = {'R', 'I', 'F', 'F'};
60 static const uint8_t k_webp[] = {'W', 'E', 'B', 'P'};
61 if (source_size < (size_t)k_raster_webp_signature_size) {
62 return false;
63 }
64 if (memcmp(source, k_riff, sizeof k_riff) != 0) {
65 return false;
66 }
67 return memcmp(&source[k_raster_webp_form_offset], k_webp, sizeof k_webp) == 0;
68}
69
84RA8_INTERNAL static void internal_rgba_to_gray(uint8_t* rgba, uint32_t pixels)
85{
86 for (uint32_t i = 0U; i < pixels; ++i) {
87 const size_t p = (size_t)i * (size_t)k_raster_webp_bytes_per_px;
88 const uint32_t y = ((uint32_t)rgba[p] * (uint32_t)k_raster_luma_r) +
89 ((uint32_t)rgba[p + 1U] * (uint32_t)k_raster_luma_g) +
90 ((uint32_t)rgba[p + 2U] * (uint32_t)k_raster_luma_b);
91 rgba[i] = (uint8_t)(y >> k_raster_luma_shift);
92 }
93}
94
111RA8_INTERNAL static void internal_output_dims(uint16_t source_width,
112 uint16_t source_height,
113 uint16_t max_edge,
114 uint16_t* out_width,
115 uint16_t* out_height)
116{
117 if (max_edge == 0U) {
118 *out_width = source_width;
119 *out_height = source_height;
120 return;
121 }
122 ra8_rabook_gray4_output_dims(source_width, source_height, max_edge, out_width, out_height);
123}
124
148RA8_INTERNAL static ra8_err_t internal_scale(const uint8_t* source_gray,
149 uint16_t source_width,
150 uint16_t source_height,
151 uint16_t out_width,
152 uint16_t out_height,
154 const uint8_t** out_gray)
155{
156 if (source_width == out_width) {
157 if (source_height == out_height) {
158 *out_gray = source_gray;
159 return k_ra8_ok;
160 }
161 }
162 const uint32_t pixels = (uint32_t)out_width * (uint32_t)out_height;
163 if (workspace->gray == nullptr) {
164 return k_ra8_err_no_mem;
165 }
166 if ((size_t)pixels > workspace->gray_cap) {
167 return k_ra8_err_no_mem;
168 }
169 const ra8_err_t rc = ra8_rabook_gray4_downscale(source_gray,
170 source_width,
171 source_height,
172 workspace->gray,
173 out_width,
174 out_height);
175 if (rc == k_ra8_ok) {
176 *out_gray = workspace->gray;
177 }
178 return rc;
179}
180
203RA8_INTERNAL static ra8_err_t internal_encode(const uint8_t* gray,
204 uint16_t width,
205 uint16_t height,
206 uint8_t pixel_format,
207 uint8_t* encoded,
208 size_t encoded_cap,
209 uint32_t* out_size)
210{
211 const uint32_t bounded_cap = (encoded_cap > UINT32_MAX) ? UINT32_MAX : (uint32_t)encoded_cap;
212 if (pixel_format == (uint8_t)k_book_pixfmt_gray8) {
213 return ra8_rabook_gray8_encode(gray, width, height, encoded, bounded_cap, out_size);
214 }
215 return ra8_rabook_gray4_encode(gray, width, height, encoded, bounded_cap, out_size);
216}
217
241RA8_INTERNAL static ra8_err_t internal_decode_webp(const uint8_t* source,
242 size_t source_size,
244 const uint8_t** out_gray,
245 uint16_t* out_width,
246 uint16_t* out_height)
247{
248 uint32_t width = 0U;
249 uint32_t height = 0U;
250 ra8_err_t rc = ra8_webp_get_info(source, source_size, &width, &height);
251 if (rc != k_ra8_ok) {
252 return rc;
253 }
254 if (width > UINT16_MAX) {
256 }
257 if (height > UINT16_MAX) {
259 }
260 const uint64_t frame_size =
261 (uint64_t)width * (uint64_t)height * (uint64_t)k_raster_webp_bytes_per_px;
262 if (workspace->webp_arena == nullptr) {
263 return k_ra8_err_no_mem;
264 }
265 if (workspace->rgba == nullptr) {
266 return k_ra8_err_no_mem;
267 }
268 if (frame_size > (uint64_t)workspace->rgba_cap) {
269 return k_ra8_err_no_mem;
270 }
271 rc = ra8_webp_decode_rgba(source,
272 source_size,
273 workspace->webp_arena,
274 workspace->rgba,
275 (size_t)width * (size_t)k_raster_webp_bytes_per_px,
276 (size_t)frame_size,
277 nullptr,
278 nullptr);
279 if (rc != k_ra8_ok) {
280 return rc;
281 }
282 const uint32_t pixels = width * height;
283 internal_rgba_to_gray(workspace->rgba, pixels);
284 *out_gray = workspace->rgba;
285 *out_width = (uint16_t)width;
286 *out_height = (uint16_t)height;
287 return k_ra8_ok;
288}
289
314RA8_INTERNAL static ra8_err_t internal_decode_stb(const uint8_t* source,
315 size_t source_size,
317 uint8_t** out_gray,
318 uint16_t* out_width,
319 uint16_t* out_height)
320{
321 if (source_size > (size_t)INT_MAX) {
323 }
324 if (workspace->stb_arena == nullptr) {
325 return k_ra8_err_no_mem;
326 }
327 int width = 0;
328 int height = 0;
329 int components = 0;
330 ra8_img_arena_bind(workspace->stb_arena);
331 uint8_t* pixels = stbi_load_from_memory(source, /* alloc-allow: caller-bound ra8_img_arena */
332 (int)source_size,
333 &width,
334 &height,
335 &components,
336 1);
337 if (pixels == nullptr) {
340 }
341 bool dimensions_valid = width > 0;
342 if (height <= 0) {
343 dimensions_valid = false;
344 }
345 if (width > (int)UINT16_MAX) {
346 dimensions_valid = false;
347 }
348 if (height > (int)UINT16_MAX) {
349 dimensions_valid = false;
350 }
351 if (!dimensions_valid) {
352 stbi_image_free(pixels); /* alloc-allow: caller-bound ra8_img_arena */
355 }
356 *out_gray = pixels;
357 *out_width = (uint16_t)width;
358 *out_height = (uint16_t)height;
359 return k_ra8_ok;
360}
361
364 const uint8_t* gray;
365 uint8_t* stb_pixels;
366 uint16_t width;
367 uint16_t height;
368 bool webp;
370
392static ra8_err_t internal_decode_source(const uint8_t* source,
393 size_t source_size,
396{
397 decoded->webp = internal_is_webp(source, source_size);
398 const ra8_err_t result = decoded->webp ? internal_decode_webp(source,
399 source_size,
400 workspace,
401 &decoded->gray,
402 &decoded->width,
403 &decoded->height)
404 : internal_decode_stb(source,
405 source_size,
406 workspace,
407 &decoded->stb_pixels,
408 &decoded->width,
409 &decoded->height);
410 if (!decoded->webp) {
411 decoded->gray = decoded->stb_pixels;
412 }
413 return result;
414}
415
442static ra8_err_t internal_encode_source(const uint8_t* source,
443 size_t source_size,
444 uint16_t max_edge,
445 uint8_t pixel_format,
447 uint8_t* encoded,
448 size_t encoded_cap,
450{
451 internal_decoded_raster_t decoded = {};
452 ra8_err_t rc = internal_decode_source(source, source_size, workspace, &decoded);
453 if (rc != k_ra8_ok) {
454 return rc;
455 }
456 uint16_t out_width = 0U;
457 uint16_t out_height = 0U;
458 internal_output_dims(decoded.width, decoded.height, max_edge, &out_width, &out_height);
459 const uint8_t* scaled = nullptr;
460 rc = internal_scale(decoded.gray,
461 decoded.width,
462 decoded.height,
463 out_width,
464 out_height,
465 workspace,
466 &scaled);
467 if (rc == k_ra8_ok) {
468 rc = internal_encode(scaled,
469 out_width,
470 out_height,
471 pixel_format,
472 encoded,
473 encoded_cap,
474 &result->encoded_size);
475 }
476 if (!decoded.webp) {
477 stbi_image_free(decoded.stb_pixels); /* alloc-allow: caller-bound ra8_img_arena */
479 }
480 if (rc != k_ra8_ok) {
481 *result = (ra8_rabook_raster_result_t){0};
482 return rc;
483 }
484 result->width = out_width;
485 result->height = out_height;
486 result->pixel_format = pixel_format;
487 return k_ra8_ok;
488}
489
491 size_t source_size,
492 uint16_t max_edge,
493 uint8_t pixel_format,
495 uint8_t* encoded,
496 size_t encoded_cap,
498{
499 if (source == nullptr) {
500 return k_ra8_err_null_ptr;
501 }
502 if (workspace == nullptr) {
503 return k_ra8_err_null_ptr;
504 }
505 if (encoded == nullptr) {
506 return k_ra8_err_null_ptr;
507 }
508 if (result == nullptr) {
509 return k_ra8_err_null_ptr;
510 }
511 *result = (ra8_rabook_raster_result_t){0};
512 if (source_size == 0U) {
514 }
515 if (pixel_format != (uint8_t)k_book_pixfmt_gray4) {
516 if (pixel_format != (uint8_t)k_book_pixfmt_gray8) {
518 }
519 }
520
521 return internal_encode_source(source,
522 source_size,
523 max_edge,
524 pixel_format,
525 workspace,
526 encoded,
527 encoded_cap,
528 result);
529}
@ 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
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
Definition ra8_err.h:142
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_validation_failed
Validation rule failed (caller-supplied invariant not satisfied).
Definition ra8_err.h:459
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
@ 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
int memcmp(const void *a, const void *b, size_t n)
Compare bytes in two memory areas.
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.
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_decode_source(const uint8_t *source, size_t source_size, ra8_rabook_raster_workspace_t *workspace, internal_decoded_raster_t *decoded)
Decode one supported source into a normalized grayscale view.
ra8_err_t ra8_rabook_raster_encode(const uint8_t *source, size_t source_size, uint16_t max_edge, uint8_t pixel_format, ra8_rabook_raster_workspace_t *workspace, uint8_t *encoded, size_t encoded_cap, ra8_rabook_raster_result_t *result)
Decode and normalize one encoded raster into a RABOOK image payload.
static bool internal_is_webp(const uint8_t *source, size_t source_size)
Return true only for a complete RIFF/WEBP signature.
static ra8_err_t internal_encode(const uint8_t *gray, uint16_t width, uint16_t height, uint8_t pixel_format, uint8_t *encoded, size_t encoded_cap, uint32_t *out_size)
Encode scaled grayscale pixels at the requested device depth.
static ra8_err_t internal_decode_webp(const uint8_t *source, size_t source_size, ra8_rabook_raster_workspace_t *workspace, const uint8_t **out_gray, uint16_t *out_width, uint16_t *out_height)
Decode WebP into caller RGBA storage and expose its gray prefix.
static ra8_err_t internal_encode_source(const uint8_t *source, size_t source_size, uint16_t max_edge, uint8_t pixel_format, ra8_rabook_raster_workspace_t *workspace, uint8_t *encoded, size_t encoded_cap, ra8_rabook_raster_result_t *result)
Scale, encode, and release one successfully validated source.
static ra8_err_t internal_scale(const uint8_t *source_gray, uint16_t source_width, uint16_t source_height, uint16_t out_width, uint16_t out_height, ra8_rabook_raster_workspace_t *workspace, const uint8_t **out_gray)
Select the source or caller downscale buffer for final encoding.
ra8_rabook_raster_consts_t
Raster signature and color-conversion constants.
@ k_raster_luma_shift
Luminance normalization shift.
@ k_raster_webp_signature_size
RIFF size plus WEBP form tag.
@ k_raster_luma_r
stb-compatible red weight.
@ k_raster_luma_g
stb-compatible green weight.
@ k_raster_webp_form_offset
WEBP form tag byte offset.
@ k_raster_luma_b
stb-compatible blue weight.
@ k_raster_webp_bytes_per_px
Decoded RGBA bytes per pixel.
static void internal_rgba_to_gray(uint8_t *rgba, uint32_t pixels)
Convert an in-place RGBA frame to a packed grayscale prefix.
static ra8_err_t internal_decode_stb(const uint8_t *source, size_t source_size, ra8_rabook_raster_workspace_t *workspace, uint8_t **out_gray, uint16_t *out_width, uint16_t *out_height)
Decode an stb-supported raster and expose arena-owned gray pixels.
static void internal_output_dims(uint16_t source_width, uint16_t source_height, uint16_t max_edge, uint16_t *out_width, uint16_t *out_height)
Compute output geometry, preserving dimensions when unclamped.
Caller-arena raster normalizer for RABOOK image records.
Zero-heap WebP (VP8 / VP8L) decode facade over the vendored libwebp.
ra8_err_t ra8_webp_decode_rgba(const uint8_t *data, size_t size, ra8_webp_arena_t *arena, uint8_t *out_rgba, size_t out_stride, size_t out_capacity, uint32_t *out_w, uint32_t *out_h)
Decode a WebP into a caller-owned RGBA8888 buffer, heap-free.
Definition ra8_webp.c:187
ra8_err_t ra8_webp_get_info(const uint8_t *data, size_t size, uint32_t *out_w, uint32_t *out_h)
Read a WebP header's pixel dimensions without decoding the body.
Definition ra8_webp.c:33
One decoded source view and the ownership needed to release it.
uint16_t height
Source height in pixels.
uint16_t width
Source width in pixels.
uint8_t * stb_pixels
stb-owned arena span, or null for WebP.
bool webp
Whether the WebP caller arena owns it.
const uint8_t * gray
Decoded grayscale samples.
Geometry and byte count of a normalized RABOOK raster payload.
uint16_t height
Output height in pixels.
uint32_t encoded_size
Bytes written to the encoded destination.
uint8_t pixel_format
book_image_pixfmt_t emitted.
uint16_t width
Output width in pixels.
Exclusive caller-owned scratch used by one raster conversion.
size_t gray_cap
Capacity of gray in bytes.
uint8_t * rgba
WebP RGBA frame storage.
uint8_t * gray
Downscaled grayscale storage.
ra8_webp_arena_t * webp_arena
WebP decoder scratch arena.
ra8_img_arena_t * stb_arena
JPEG/PNG/GIF/BMP decoder arena.
size_t rgba_cap
Capacity of rgba in bytes.