source: mainline/uspace/lib/gfxfont/src/glyph_bmp.c

Last change on this file was 1fa6292, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 6 months ago

Remove a ton of duplicated code in libui/libgfxfont tests

  • Property mode set to 100644
File size: 8.5 KB
Line 
1/*
2 * Copyright (c) 2020 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libgfxfont
30 * @{
31 */
32/**
33 * @file Glyph bitmap
34 */
35
36#include <errno.h>
37#include <gfx/bitmap.h>
38#include <gfx/coord.h>
39#include <gfx/glyph_bmp.h>
40#include <io/pixelmap.h>
41#include <stdlib.h>
42#include "../private/font.h"
43#include "../private/glyph.h"
44#include "../private/glyph_bmp.h"
45
46static errno_t gfx_glyph_bmp_extend(gfx_glyph_bmp_t *, gfx_coord2_t *);
47
48/** Open glyph bitmap for editing.
49 *
50 * @param glyph Glyph
51 * @param rbmp Place to store glyph bitmap
52 * @return EOK on success, ENOMEM if out of memory
53 */
54errno_t gfx_glyph_bmp_open(gfx_glyph_t *glyph, gfx_glyph_bmp_t **rbmp)
55{
56 gfx_font_t *font = glyph->font;
57 gfx_glyph_bmp_t *bmp;
58 pixelmap_t pmap;
59 gfx_bitmap_alloc_t alloc;
60 gfx_coord_t x, y;
61 pixel_t pixel;
62 errno_t rc;
63
64 bmp = calloc(1, sizeof(gfx_glyph_bmp_t));
65 if (bmp == NULL)
66 return ENOMEM;
67
68 /* Bitmap coordinates are relative to glyph origin point */
69 gfx_rect_rtranslate(&glyph->origin, &glyph->rect, &bmp->rect);
70
71 bmp->pixels = calloc((bmp->rect.p1.x - bmp->rect.p0.x) *
72 (bmp->rect.p1.y - bmp->rect.p0.y), sizeof(int));
73 if (bmp->pixels == NULL) {
74 free(bmp);
75 return ENOMEM;
76 }
77
78 rc = gfx_bitmap_get_alloc(font->bitmap, &alloc);
79 if (rc != EOK) {
80 free(bmp->pixels);
81 free(bmp);
82 return rc;
83 }
84
85 assert(font->rect.p0.x == 0);
86 assert(font->rect.p0.y == 0);
87 pmap.width = font->rect.p1.x;
88 pmap.height = font->rect.p1.y;
89 pmap.data = alloc.pixels;
90
91 /* Copy pixels from font bitmap */
92
93 for (y = bmp->rect.p0.y; y < bmp->rect.p1.y; y++) {
94 for (x = bmp->rect.p0.x; x < bmp->rect.p1.x; x++) {
95 pixel = pixelmap_get_pixel(&pmap, glyph->origin.x + x,
96 glyph->origin.y + y);
97 bmp->pixels[(y - bmp->rect.p0.y) *
98 (bmp->rect.p1.x - bmp->rect.p0.x) +
99 (x - bmp->rect.p0.x)] = (pixel != 0) ? 1 : 0;
100 }
101 }
102
103 bmp->glyph = glyph;
104 *rbmp = bmp;
105 return EOK;
106}
107
108/** Save glyph bitmap.
109 *
110 * @param bmp Glyph bitmap
111 * @return EOK on success, ENOMEM if out of memory
112 */
113errno_t gfx_glyph_bmp_save(gfx_glyph_bmp_t *bmp)
114{
115 gfx_glyph_t *glyph = bmp->glyph;
116 gfx_font_t *font = glyph->font;
117 gfx_coord_t x, y;
118 gfx_rect_t used_rect;
119 pixel_t pixel;
120 pixelmap_t pmap;
121 gfx_bitmap_alloc_t alloc;
122 errno_t rc;
123
124 /* Find actual rectangle being used */
125 gfx_glyph_bmp_find_used_rect(bmp, &used_rect);
126
127 /*
128 * Replace glyph with empty space in the font bitmap, the width
129 * of the empty equal to new glyph bitmap width. The glyph width
130 * is adjusted.
131 */
132 rc = gfx_font_splice_at_glyph(font, glyph, &used_rect);
133 if (rc != EOK)
134 return rc;
135
136 rc = gfx_bitmap_get_alloc(font->bitmap, &alloc);
137 if (rc != EOK)
138 return rc;
139
140 assert(font->rect.p0.x == 0);
141 assert(font->rect.p0.y == 0);
142 pmap.width = font->rect.p1.x;
143 pmap.height = font->rect.p1.y;
144 pmap.data = alloc.pixels;
145
146 /* Copy pixels to font bitmap */
147
148 for (y = used_rect.p0.y; y < used_rect.p1.y; y++) {
149 for (x = used_rect.p0.x; x < used_rect.p1.x; x++) {
150 pixel = bmp->pixels[(y - bmp->rect.p0.y) *
151 (bmp->rect.p1.x - bmp->rect.p0.x) +
152 (x - bmp->rect.p0.x)] ?
153 PIXEL(255, 255, 255, 255) : PIXEL(0, 0, 0, 0);
154 pixelmap_put_pixel(&pmap, glyph->origin.x + x,
155 glyph->origin.y + y, pixel);
156 }
157 }
158
159 return EOK;
160}
161
162/** Close glyph bitmap.
163 *
164 * @param bmp Glyph bitmap
165 */
166void gfx_glyph_bmp_close(gfx_glyph_bmp_t *bmp)
167{
168 free(bmp->pixels);
169 free(bmp);
170}
171
172/** Get rectangle covered by glyph bitmap.
173 *
174 * @param bmp Glyph bitmap
175 * @param rect Place to store rectangle
176 */
177void gfx_glyph_bmp_get_rect(gfx_glyph_bmp_t *bmp, gfx_rect_t *rect)
178{
179 *rect = bmp->rect;
180}
181
182/** Find minimum rectangle covering all non-background pixels.
183 *
184 * @param bmp Glyph bitmap
185 * @param rect Place to store rectangle
186 */
187void gfx_glyph_bmp_find_used_rect(gfx_glyph_bmp_t *bmp, gfx_rect_t *rect)
188{
189 gfx_coord_t x, y;
190 gfx_coord2_t min;
191 gfx_coord2_t max;
192 bool anypix;
193 int pix;
194
195 min.x = bmp->rect.p1.x;
196 min.y = bmp->rect.p1.y;
197 max.x = bmp->rect.p0.x;
198 max.y = bmp->rect.p0.y;
199
200 anypix = false;
201 for (y = bmp->rect.p0.y; y < bmp->rect.p1.y; y++) {
202 for (x = bmp->rect.p0.x; x < bmp->rect.p1.x; x++) {
203 pix = gfx_glyph_bmp_getpix(bmp, x, y);
204 if (pix != 0) {
205 anypix = true;
206 if (x < min.x)
207 min.x = x;
208 if (y < min.y)
209 min.y = y;
210 if (x > max.x)
211 max.x = x;
212 if (y > max.y)
213 max.y = y;
214 }
215 }
216 }
217
218 if (anypix) {
219 rect->p0.x = min.x;
220 rect->p0.y = min.y;
221 rect->p1.x = max.x + 1;
222 rect->p1.y = max.y + 1;
223 } else {
224 rect->p0.x = 0;
225 rect->p0.y = 0;
226 rect->p1.x = 0;
227 rect->p1.y = 0;
228 }
229}
230
231/** Get pixel from glyph bitmap.
232 *
233 * @param bmp Glyph bitmap
234 * @param x X-coordinate
235 * @param y Y-coordinate
236 * @return Pixel value
237 */
238int gfx_glyph_bmp_getpix(gfx_glyph_bmp_t *bmp, gfx_coord_t x, gfx_coord_t y)
239{
240 gfx_coord2_t pos;
241 size_t pitch;
242
243 pos.x = x;
244 pos.y = y;
245 if (!gfx_pix_inside_rect(&pos, &bmp->rect))
246 return 0;
247
248 pitch = bmp->rect.p1.x - bmp->rect.p0.x;
249
250 return bmp->pixels[(y - bmp->rect.p0.y) * pitch +
251 (x - bmp->rect.p0.x)];
252}
253
254/** Set pixel in glyph bitmap.
255 *
256 * @param bmp Glyph bitmap
257 * @param x X-coordinate
258 * @param y Y-coordinate
259 *
260 * @reutrn EOK on success, ENOMEM if out of memory
261 */
262errno_t gfx_glyph_bmp_setpix(gfx_glyph_bmp_t *bmp, gfx_coord_t x,
263 gfx_coord_t y, int value)
264{
265 gfx_coord2_t pos;
266 size_t pitch;
267 errno_t rc;
268
269 pos.x = x;
270 pos.y = y;
271
272 if (!gfx_pix_inside_rect(&pos, &bmp->rect)) {
273 rc = gfx_glyph_bmp_extend(bmp, &pos);
274 if (rc != EOK)
275 return rc;
276 }
277
278 pitch = bmp->rect.p1.x - bmp->rect.p0.x;
279 bmp->pixels[(y - bmp->rect.p0.y) * pitch +
280 (x - bmp->rect.p0.x)] = value;
281 return EOK;
282}
283
284/** Clear glyph bitmap
285 *
286 * @param bmp Glyph bitmap
287 *
288 * @return EOK on sucesss, ENOMEM if out of memory
289 */
290errno_t gfx_glyph_bmp_clear(gfx_glyph_bmp_t *bmp)
291{
292 int *npixels;
293
294 /* Allocate new pixel array */
295 npixels = calloc(1, sizeof(int));
296 if (npixels == NULL)
297 return ENOMEM;
298
299 /* Switch new and old data */
300 free(bmp->pixels);
301 bmp->pixels = npixels;
302 bmp->rect.p0.x = 0;
303 bmp->rect.p0.y = 0;
304 bmp->rect.p1.x = 0;
305 bmp->rect.p1.y = 0;
306
307 return EOK;
308}
309
310/** Extend glyph bitmap to cover a patricular pixel.
311 *
312 * @param bmp Glyph bitmap
313 * @param pos Pixel position
314 *
315 * @return EOK on sucesss, ENOMEM if out of memory
316 */
317static errno_t gfx_glyph_bmp_extend(gfx_glyph_bmp_t *bmp, gfx_coord2_t *pos)
318{
319 gfx_rect_t prect;
320 gfx_rect_t nrect;
321 int *npixels;
322 size_t npitch;
323 size_t opitch;
324 gfx_coord_t x, y;
325
326 /* Compute new rectangle enveloping current rectangle and new pixel */
327 prect.p0 = *pos;
328 prect.p1.x = prect.p0.x + 1;
329 prect.p1.y = prect.p0.y + 1;
330
331 gfx_rect_envelope(&bmp->rect, &prect, &nrect);
332
333 /* Allocate new pixel array */
334 npixels = calloc((nrect.p1.x - nrect.p0.x) *
335 (nrect.p1.y - nrect.p0.y), sizeof(int));
336 if (npixels == NULL)
337 return ENOMEM;
338
339 /* Transfer pixel data */
340 opitch = bmp->rect.p1.x - bmp->rect.p0.x;
341 npitch = nrect.p1.x - nrect.p0.x;
342
343 for (y = bmp->rect.p0.y; y < bmp->rect.p1.y; y++) {
344 for (x = bmp->rect.p0.x; x < bmp->rect.p1.x; x++) {
345 npixels[(y - nrect.p0.y) * npitch + x - nrect.p0.x] =
346 bmp->pixels[(y - bmp->rect.p0.y) * opitch +
347 x - bmp->rect.p0.x];
348 }
349 }
350
351 /* Switch new and old data */
352 free(bmp->pixels);
353 bmp->pixels = npixels;
354 bmp->rect = nrect;
355
356 return EOK;
357}
358
359/** @}
360 */
Note: See TracBrowser for help on using the repository browser.