ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
sh_image.c
Go to the documentation of this file.
1
25#include "ra8_check.h"
26#include "ra8_gfx.h"
27#include "sh_app.h"
28
30typedef enum : uint32_t {
32 k_sh_two = 2U,
35
47
62static uint8_t
64
65static_assert((k_sh_loupe_w % k_sh_loupe_zoom) == 0U, "loupe width must be a multiple of zoom");
66static_assert((k_sh_loupe_h % k_sh_loupe_zoom) == 0U, "loupe height must be a multiple of zoom");
67
70static bool sh_gray4_fetch_row(const book_src_t* src, const book_image_t* img, uint32_t sy)
71{
72 return book_src_image_rect(src,
73 img,
74 0U,
75 sy,
76 (uint32_t)img->width,
77 1U,
79 (uint32_t)img->width) == k_ra8_ok;
80}
81
83static void sh_fit_box(int32_t src_w,
84 int32_t src_h,
85 int32_t box_w,
86 int32_t box_h,
87 int32_t* fit_w,
88 int32_t* fit_h)
89{
90 int32_t fw = box_w;
91 int32_t fh = (src_w > 0) ? ((box_w * src_h) / src_w) : box_h;
92 if (fh > box_h) {
93 fh = box_h;
94 fw = (src_h > 0) ? ((box_h * src_w) / src_h) : box_w;
95 }
96 *fit_w = (fw < 1) ? 1 : fw;
97 *fit_h = (fh < 1) ? 1 : fh;
98}
99
102static bool sh_gray4_image(const book_src_t* src, uint32_t img_idx, book_image_t* out_img)
103{
104 if (book_src_image(src, img_idx, out_img) != k_ra8_ok) {
105 return false;
106 }
107 if (out_img->format != (uint8_t)k_book_image_gray4) {
108 return false;
109 }
110 if ((out_img->width == 0U) || (out_img->height == 0U)) {
111 return false;
112 }
113 return (uint32_t)out_img->width <= (uint32_t)k_sh_img_max_w;
114}
115
117static int32_t sh_clampi(int32_t v, int32_t lo, int32_t hi)
118{
119 const int32_t x = (v < lo) ? lo : v;
120 return (x > hi) ? hi : x;
121}
122
124static void sh_loupe_pack(int32_t j, int32_t i, int32_t w, uint8_t g8)
125{
126 const size_t flat = ((size_t)j * (size_t)w) + (size_t)i;
127 const uint8_t nib = (uint8_t)(g8 >> k_sh_nib_sh);
128 const size_t bi = flat >> 1U;
129 if ((flat & 1U) == 0U) {
130 s_sh_loupe[bi] = (uint8_t)(nib << k_sh_nib_sh); /* even flat: high nibble (clears low) */
131 } else {
132 s_sh_loupe[bi] = (uint8_t)(s_sh_loupe[bi] | nib); /* odd flat: OR in the low nibble */
133 }
134}
135
139static bool sh_loupe_stage(const book_src_t* src,
140 const book_image_t* img,
141 int32_t sx,
142 int32_t sy,
143 int32_t w,
144 int32_t h)
145{
146 for (int32_t j = 0; j < h; ++j) {
147 if (book_src_image_rect(src,
148 img,
149 (uint32_t)sx,
150 (uint32_t)(sy + j),
151 (uint32_t)w,
152 1U,
154 (uint32_t)w) != k_ra8_ok) {
155 return false;
156 }
157 for (int32_t i = 0; i < w; ++i) {
158 sh_loupe_pack(j, i, w, s_sh_gray8_row[i]);
159 }
160 }
161 return true;
162}
163
165static void sh_loupe_chrome(int32_t dst_x, int32_t dst_y)
166{
167 const ra8_ui_rect_t r = {.x = dst_x,
168 .y = dst_y,
169 .w = (int32_t)k_sh_loupe_w,
170 .h = (int32_t)k_sh_loupe_h};
171 sh_border(r, (uint32_t)k_sh_col_ink, (int32_t)k_sh_loupe_border);
172}
173
175 uint32_t img_idx,
176 uint8_t* out,
177 int32_t box_w,
178 int32_t box_h,
179 int32_t* out_w,
180 int32_t* out_h)
181{
182 RA8_CHECK_NULL_PTR(src, "sh_image", "decode: null src");
183 RA8_CHECK_NULL_PTR(out, "sh_image", "decode: null out");
184 book_image_t img = {};
185 if (!sh_gray4_image(src, img_idx, &img) || (box_w <= 0) || (box_h <= 0)) {
187 }
188 int32_t fw = 0;
189 int32_t fh = 0;
190 sh_fit_box((int32_t)img.width, (int32_t)img.height, box_w, box_h, &fw, &fh);
191 uint32_t last_sy = UINT32_MAX;
192 for (int32_t dy = 0; dy < fh; ++dy) {
193 const uint32_t sy = (uint32_t)((dy * (int32_t)img.height) / fh);
194 if ((sy != last_sy) && !sh_gray4_fetch_row(src, &img, sy)) {
196 }
197 last_sy = sy;
198 for (int32_t dx = 0; dx < fw; ++dx) {
199 const uint32_t sx = (uint32_t)((dx * (int32_t)img.width) / fw);
200 out[(dy * fw) + dx] = s_sh_gray8_row[sx];
201 }
202 }
203 *out_w = fw;
204 *out_h = fh;
205 return k_ra8_ok;
206}
207
208void sh_image_blit_gray8(const uint8_t* src, int32_t w, int32_t h, int32_t dst_x, int32_t dst_y)
209{
210 if ((src == nullptr) || (w <= 0) || (h <= 0)) {
211 return;
212 }
213 /* One clipped row-loop in ra8_gfx instead of a per-pixel ra8_gfx_pixel chain. */
214 (void)ra8_gfx_blit_gray8(src, w, h, dst_x, dst_y);
215}
216
226static uint8_t s_sh_cover_row[k_sh_fb_w];
227
229 uint32_t img_idx,
230 int32_t dst_x,
231 int32_t dst_y,
232 int32_t box_w,
233 int32_t box_h,
234 int32_t* out_w,
235 int32_t* out_h)
236{
237 RA8_CHECK_NULL_PTR(src, "sh_image", "cover: null src");
238 book_image_t img = {};
239 if (!sh_gray4_image(src, img_idx, &img) || (box_w <= 0) || (box_h <= 0)) {
241 }
242 int32_t fw = 0;
243 int32_t fh = 0;
244 sh_fit_box((int32_t)img.width, (int32_t)img.height, box_w, box_h, &fw, &fh);
245 const int32_t ox = dst_x + ((box_w - fw) / (int32_t)k_sh_two);
246 const int32_t oy = dst_y + ((box_h - fh) / (int32_t)k_sh_two);
247 /* Read one unpacked gray8 source row via the library, nearest-neighbour scale
248 * it into a gray8 row, then blit that row in a single clipped pass -- the same
249 * pixels the resident per-pixel loop wrote, far fewer calls. */
250 const int32_t rw = (fw < (int32_t)k_sh_fb_w) ? fw : (int32_t)k_sh_fb_w;
251 uint32_t last_sy = UINT32_MAX;
252 for (int32_t dy = 0; dy < fh; ++dy) {
253 const uint32_t sy = (uint32_t)((dy * (int32_t)img.height) / fh);
254 if ((sy != last_sy) && !sh_gray4_fetch_row(src, &img, sy)) {
256 }
257 last_sy = sy;
258 for (int32_t dx = 0; dx < rw; ++dx) {
259 const uint32_t sx = (uint32_t)((dx * (int32_t)img.width) / fw);
260 s_sh_cover_row[(size_t)dx] = s_sh_gray8_row[sx];
261 }
262 (void)ra8_gfx_blit_gray8(s_sh_cover_row, rw, 1, ox, oy + dy);
263 }
264 if (out_w != nullptr) {
265 *out_w = fw;
266 }
267 if (out_h != nullptr) {
268 *out_h = fh;
269 }
270 return k_ra8_ok;
271}
272
274 uint32_t img_idx,
275 int32_t src_cx,
276 int32_t src_cy,
277 int32_t dst_x,
278 int32_t dst_y)
279{
280 RA8_CHECK_NULL_PTR(src, "sh_image", "loupe: null src");
281 book_image_t img = {};
282 if (!sh_gray4_image(src, img_idx, &img)) {
284 }
285 /* Sample a FULL-RESOLUTION window (never scale-to-fit) and magnify it 1:1. The
286 * window shrinks to the image if a small source cannot fill the lens. */
287 const int32_t sub_w = (int32_t)k_sh_loupe_w / (int32_t)k_sh_loupe_zoom;
288 const int32_t sub_h = (int32_t)k_sh_loupe_h / (int32_t)k_sh_loupe_zoom;
289 const int32_t w = ((int32_t)img.width < sub_w) ? (int32_t)img.width : sub_w;
290 const int32_t h = ((int32_t)img.height < sub_h) ? (int32_t)img.height : sub_h;
291 const int32_t sx = sh_clampi(src_cx - (w / (int32_t)k_sh_two), 0, (int32_t)img.width - w);
292 const int32_t sy = sh_clampi(src_cy - (h / (int32_t)k_sh_two), 0, (int32_t)img.height - h);
293 if (!sh_loupe_stage(src, &img, sx, sy, w, h)) {
295 }
296 /* Confine the magnified blit to the lens window so nothing spills, then frame. */
297 (void)ra8_gfx_set_clip(dst_x, dst_y, (int32_t)k_sh_loupe_w, (int32_t)k_sh_loupe_h);
298 (void)
299 ra8_gfx_blit_gray4_zoom(s_sh_loupe, w, h, 0, 0, w, h, (int32_t)k_sh_loupe_zoom, dst_x, dst_y);
300 (void)ra8_gfx_reset_clip();
301 sh_loupe_chrome(dst_x, dst_y);
302 return k_ra8_ok;
303}
304
306 uint32_t img_idx,
307 int32_t box_x,
308 int32_t box_y,
309 int32_t box_w,
310 int32_t box_h,
311 int32_t px,
312 int32_t py,
313 int32_t* out_cx,
314 int32_t* out_cy)
315{
316 if ((src == nullptr) || (out_cx == nullptr) || (out_cy == nullptr)) {
317 return false;
318 }
319 book_image_t img = {};
320 if (!sh_gray4_image(src, img_idx, &img) || (box_w <= 0) || (box_h <= 0)) {
321 return false;
322 }
323 int32_t fw = 0;
324 int32_t fh = 0;
325 sh_fit_box((int32_t)img.width, (int32_t)img.height, box_w, box_h, &fw, &fh);
326 const int32_t ox = box_x + ((box_w - fw) / (int32_t)k_sh_two);
327 const int32_t oy = box_y + ((box_h - fh) / (int32_t)k_sh_two);
328 const bool inside = (px >= ox) && (px < (ox + fw)) && (py >= oy) && (py < (oy + fh));
329 if (!inside) {
330 return false;
331 }
332 *out_cx = ((px - ox) * (int32_t)img.width) / fw;
333 *out_cy = ((py - oy) * (int32_t)img.height) / fh;
334 return true;
335}
@ k_book_image_gray4
4bpp gray, 2px/byte; pixel (x,y) is at flat index y*width + x.
Definition book.h:175
ra8_err_t book_src_image_rect(const book_src_t *src, const book_image_t *img, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t *out, uint32_t out_stride)
Read a sub-rectangle of a raster image (4bpp or 8bpp) as gray8, row by row.
Definition book_paged.c:325
ra8_err_t book_src_image(const book_src_t *src, uint32_t idx, book_image_t *out_img)
Read one image descriptor out of a book source (resident or paged).
Definition book_paged.c:314
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
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...
ra8_err_t ra8_gfx_reset_clip(void)
Reset the clip rectangle to the whole framebuffer.
ra8_err_t ra8_gfx_blit_gray4_zoom(const uint8_t *src, int32_t src_w, int32_t src_h, int32_t sx, int32_t sy, int32_t sw, int32_t sh, int32_t zoom, int32_t dst_x, int32_t dst_y)
Nearest-neighbour integer-zoom blit of a sub-rectangle of a packed 4-bit grayscale image into the fra...
ra8_err_t ra8_gfx_set_clip(int32_t x, int32_t y, int32_t w, int32_t h)
Restrict all subsequent drawing to a rectangle (dirty-region updates).
ra8_err_t ra8_gfx_blit_gray8(const uint8_t *src, int32_t w, int32_t h, int32_t dst_x, int32_t dst_y)
Blit an 8-bit grayscale image to a framebuffer rectangle.
Shared contract for the ereader_shelf multi-screen e-reader.
void sh_border(ra8_ui_rect_t r, uint32_t colour, int32_t width)
Draw a width-thick rectangle outline in colour.
Definition sh_util.c:69
@ k_sh_loupe_w
Lens window width in framebuffer pixels.
Definition sh_app.h:85
@ k_sh_loupe_zoom
Integer magnification of the sampled window.
Definition sh_app.h:87
@ k_sh_loupe_h
Lens window height in framebuffer pixels.
Definition sh_app.h:86
@ k_sh_loupe_border
Lens chrome (frame) thickness in pixels.
Definition sh_app.h:88
@ k_sh_fb_w
Panel width in pixels.
Definition sh_app.h:46
@ k_sh_col_ink
Body ink.
Definition sh_app.h:102
static bool sh_loupe_stage(const book_src_t *src, const book_image_t *img, int32_t sx, int32_t sy, int32_t w, int32_t h)
Stage the w x h source window at (sx, sy) into s_sh_loupe.
Definition sh_image.c:139
ra8_err_t sh_image_blit_cover(const book_src_t *src, uint32_t img_idx, 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 + aspect-fit a 4bpp image straight into the framebuffer box.
Definition sh_image.c:228
ra8_err_t sh_image_decode_gray8(const book_src_t *src, uint32_t img_idx, uint8_t *out, int32_t box_w, int32_t box_h, int32_t *out_w, int32_t *out_h)
Decode a 4bpp grayscale image, aspect-fit-scale it into box, and write the result into a gray8 buffer...
Definition sh_image.c:174
static bool sh_gray4_image(const book_src_t *src, uint32_t img_idx, book_image_t *out_img)
Read image descriptor img_idx via the library and confirm it is a renderable gray4 raster that fits s...
Definition sh_image.c:102
static uint8_t s_sh_cover_row[k_sh_fb_w]
One decoded gray8 row of the scaled cover, reused across rows.
Definition sh_image.c:226
bool sh_image_loupe_map(const book_src_t *src, uint32_t img_idx, int32_t box_x, int32_t box_y, int32_t box_w, int32_t box_h, int32_t px, int32_t py, int32_t *out_cx, int32_t *out_cy)
Map a framebuffer touch point over an aspect-fit image box to full-resolution source coordinates (lou...
Definition sh_image.c:305
ra8_err_t sh_image_loupe(const book_src_t *src, uint32_t img_idx, int32_t src_cx, int32_t src_cy, int32_t dst_x, int32_t dst_y)
Draw the magnifier loupe: a k_sh_loupe_zoom-magnified 1:1 window of a full-resolution 4bpp source ima...
Definition sh_image.c:273
static void sh_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)
Aspect-fit src_w x src_h into box; sets fit_w / fit_h (>=1).
Definition sh_image.c:83
void sh_image_blit_gray8(const uint8_t *src, int32_t w, int32_t h, int32_t dst_x, int32_t dst_y)
Blit a gray8 bitmap to the bound framebuffer at dst_x, dst_y.
Definition sh_image.c:208
static int32_t sh_clampi(int32_t v, int32_t lo, int32_t hi)
Clamp v into [lo, hi] (assumes hi >= lo).
Definition sh_image.c:117
static uint8_t s_sh_loupe[((k_sh_loupe_w/k_sh_loupe_zoom) *(k_sh_loupe_h/k_sh_loupe_zoom))/k_sh_two]
One magnifier-loupe source window, repacked as a compact gray4 image.
Definition sh_image.c:63
sh_img_const_t
Nibble repack + scale-bound constants.
Definition sh_image.c:30
@ k_sh_img_max_w
Max accepted source width (row-buffer cap).
Definition sh_image.c:33
@ k_sh_nib_sh
Gray8->gray4 nibble shift for the loupe repack.
Definition sh_image.c:31
@ k_sh_two
Centring divisor / half-extent divisor.
Definition sh_image.c:32
static void sh_loupe_pack(int32_t j, int32_t i, int32_t w, uint8_t g8)
Pack gray8 pixel g8 into s_sh_loupe at flat index j * w + i.
Definition sh_image.c:124
static bool sh_gray4_fetch_row(const book_src_t *src, const book_image_t *img, uint32_t sy)
Read source row sy of img as unpacked gray8 into s_sh_gray8_row via the library's sub-rect reader.
Definition sh_image.c:70
static uint8_t s_sh_gray8_row[k_sh_img_max_w]
One unpacked gray8 source row read from the paged image pool.
Definition sh_image.c:46
static void sh_loupe_chrome(int32_t dst_x, int32_t dst_y)
Frame the lens window with a k_sh_loupe_border-thick ink border.
Definition sh_image.c:165
Descriptor for one transcoded image in the image pool.
Definition book.h:354
uint16_t height
Pixel height.
Definition book.h:357
uint8_t format
book_image_format_t.
Definition book.h:358
uint16_t width
Pixel width.
Definition book.h:356
A book data source: resident (zero-copy) or paged (demand-fetched).
Definition book_paged.h:69
Axis-aligned rectangle in framebuffer pixel coordinates.
Definition ra8_ui.h:72