1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** GUIX Component */
16 /** */
17 /** Utility (Utility) */
18 /** */
19 /**************************************************************************/
20 #define GX_SOURCE_CODE
21
22
23 /* Include necessary system files. */
24
25 #include "gx_api.h"
26 #include "gx_utility.h"
27 #include "gx_system.h"
28
29 #define REDVAL_332(_c) (((_c) >> 5) & 0x07)
30 #define GREENVAL_332(_c) (((_c) >> 2) & 0x07)
31 #define BLUEVAL_332(_c) ((_c) & 0x03)
32
33 #define ASSEMBLECOLOR_332(_r, _g, _b) \
34 ((((_r) & 0x07) << 5) | \
35 (((_g) & 0x07) << 2) | \
36 ((_b) & 0x03))
37
38
39 /**************************************************************************/
40 /* */
41 /* FUNCTION RELEASE */
42 /* */
43 /* _gx_utility_8bpp_pixelmap_raw_resize PORTABLE C */
44 /* 6.1.7 */
45 /* AUTHOR */
46 /* */
47 /* Kenneth Maxwell, Microsoft Corporation */
48 /* */
49 /* DESCRIPTION */
50 /* */
51 /* Internal helper function that resize 8bpp format uncompressed */
52 /* pixelmap with or without transparent channel. */
53 /* */
54 /* INPUT */
55 /* */
56 /* src The source pixelmap */
57 /* destination The resized pixelmap to be */
58 /* returned */
59 /* width New width */
60 /* height New height */
61 /* */
62 /* OUTPUT */
63 /* */
64 /* status Completion status */
65 /* */
66 /* CALLS */
67 /* */
68 /* _gx_system_memory_allocator Application defined memory */
69 /* allocation function */
70 /* */
71 /* CALLED BY */
72 /* */
73 /* GUIX Internal Code */
74 /* */
75 /* RELEASE HISTORY */
76 /* */
77 /* DATE NAME DESCRIPTION */
78 /* */
79 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
80 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
81 /* resulting in version 6.1 */
82 /* 06-02-2021 Kenneth Maxwell Modified comment(s), */
83 /* removed unused variable */
84 /* assignment, */
85 /* resulting in version 6.1.7 */
86 /* */
87 /**************************************************************************/
_gx_utility_8bpp_pixelmap_raw_resize(GX_PIXELMAP * src,GX_PIXELMAP * destination,INT width,INT height)88 static UINT _gx_utility_8bpp_pixelmap_raw_resize(GX_PIXELMAP *src, GX_PIXELMAP *destination, INT width, INT height)
89 {
90 /* The pixelmap resize function is implemented from nearest neighbor
91 image scaling algorithm. */
92
93 GX_UBYTE *get;
94 GX_UBYTE *put;
95 INT xradio;
96 INT yradio;
97 INT x;
98 INT y;
99 INT xx;
100 INT yy;
101
102 /* Calculate scale ratio and enlarge it by 256 times to keep precision. */
103 xradio = ((src -> gx_pixelmap_width) << 8) / width;
104 yradio = ((src -> gx_pixelmap_height) << 8) / height;
105
106 /* Fill property values into destination pixelmap structure. */
107 destination -> gx_pixelmap_flags = src -> gx_pixelmap_flags;
108 destination -> gx_pixelmap_format = src -> gx_pixelmap_format;
109 destination -> gx_pixelmap_transparent_color = src -> gx_pixelmap_transparent_color;
110 destination -> gx_pixelmap_version_major = src -> gx_pixelmap_version_major;
111 destination -> gx_pixelmap_version_minor = src -> gx_pixelmap_version_minor;
112
113 destination -> gx_pixelmap_height = (GX_VALUE)height;
114 destination -> gx_pixelmap_width = (GX_VALUE)width;
115
116 /* Safe int math is not required here, calling function limits max width, height to 14 bits so
117 overflow cannot occur. */
118 destination -> gx_pixelmap_data_size = (UINT)(height * width) * sizeof(GX_UBYTE);
119
120 /* Allocate memory to load pixelmap data. */
121 destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
122
123 if (destination -> gx_pixelmap_data == GX_NULL)
124 {
125 return GX_SYSTEM_MEMORY_ERROR;
126 }
127
128 put = (GX_UBYTE *)destination -> gx_pixelmap_data;
129
130 /* Loop through destination's pixel and fill each pixel with the nearest neighbor. */
131 for (y = 0; y < height; y++)
132 {
133 for (x = 0; x < width; x++)
134 {
135 xx = (xradio * x) >> 8;
136 yy = (yradio * y) >> 8;
137
138 get = (GX_UBYTE *)src -> gx_pixelmap_data;
139 get += yy * src -> gx_pixelmap_width;
140 get += xx;
141
142 *put++ = *get;
143 }
144 }
145
146 return GX_SUCCESS;
147 }
148
149 /**************************************************************************/
150 /* */
151 /* FUNCTION RELEASE */
152 /* */
153 /* _gx_utility_8bpp_pixelmap_alpha_resize PORTABLE C */
154 /* 6.1.7 */
155 /* AUTHOR */
156 /* */
157 /* Kenneth Maxwell, Microsoft Corporation */
158 /* */
159 /* DESCRIPTION */
160 /* */
161 /* Internal helper function that resize an 8bpp format uncompressed */
162 /* pixelmap with transparent channel. */
163 /* */
164 /* INPUT */
165 /* */
166 /* src The source pixelmap */
167 /* destination The resized pixelmap to be */
168 /* returned */
169 /* width New width */
170 /* height New height */
171 /* */
172 /* OUTPUT */
173 /* */
174 /* status Completion status */
175 /* */
176 /* CALLS */
177 /* */
178 /* _gx_system_memory_allocator Application defined memory */
179 /* allocation function */
180 /* */
181 /* CALLED BY */
182 /* */
183 /* GUIX Internal Code */
184 /* */
185 /* RELEASE HISTORY */
186 /* */
187 /* DATE NAME DESCRIPTION */
188 /* */
189 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
190 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
191 /* resulting in version 6.1 */
192 /* 06-02-2021 Kenneth Maxwell Modified comment(s), */
193 /* removed unused variable */
194 /* assignment, */
195 /* resulting in version 6.1.7 */
196 /* */
197 /**************************************************************************/
_gx_utility_8bpp_pixelmap_alpha_resize(GX_PIXELMAP * src,GX_PIXELMAP * destination,INT width,INT height)198 static UINT _gx_utility_8bpp_pixelmap_alpha_resize(GX_PIXELMAP *src, GX_PIXELMAP *destination, INT width, INT height)
199 {
200 /* The pixelmap resize function is implemented from bilinear interpolation
201 image scaling algorithm. */
202 GX_UBYTE *get;
203 GX_UBYTE *put;
204 GX_UBYTE *getalpha;
205 GX_UBYTE *putalpha;
206 INT xdiff;
207 INT ydiff;
208 INT xradio;
209 INT yradio;
210 INT x;
211 INT y;
212 INT xx;
213 INT yy;
214 GX_UBYTE neighbor_pixels[2][2];
215 GX_COLOR alpha[4];
216 GX_COLOR red;
217 GX_COLOR green;
218 GX_COLOR blue;
219
220 /* Calculate scale ratio and enlarge it by 256 times to keep precision. */
221 xradio = ((src -> gx_pixelmap_width) << 8) / width;
222 yradio = ((src -> gx_pixelmap_height) << 8) / height;
223
224 /* Fill property values into destination pixelmap structure. */
225 destination -> gx_pixelmap_flags = src -> gx_pixelmap_flags;
226 destination -> gx_pixelmap_format = src -> gx_pixelmap_format;
227
228 destination -> gx_pixelmap_height = (GX_VALUE)height;
229 destination -> gx_pixelmap_width = (GX_VALUE)width;
230
231 /* Safe int math is not required here, calling function limits max width, height to 14 bits so
232 overflow cannot occur. */
233 destination -> gx_pixelmap_data_size = (UINT)(height * width) * sizeof(GX_UBYTE);
234
235 /* Safe int math is not required here, calling function limits max width, height to 14 bits so
236 overflow cannot occur. */
237 destination -> gx_pixelmap_aux_data_size = (UINT)(height * width) * sizeof(GX_UBYTE);
238
239 /* Allocate memory to load pixelmap data. */
240 destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
241
242 if (destination -> gx_pixelmap_data == GX_NULL)
243 {
244 return GX_SYSTEM_MEMORY_ERROR;
245 }
246
247 destination -> gx_pixelmap_aux_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_aux_data_size);
248
249 if (destination -> gx_pixelmap_aux_data == GX_NULL)
250 {
251 _gx_system_memory_free((void *)destination -> gx_pixelmap_data);
252 return GX_SYSTEM_MEMORY_ERROR;
253 }
254
255 put = (GX_UBYTE *)destination -> gx_pixelmap_data;
256 putalpha = (GX_UBYTE *)destination -> gx_pixelmap_aux_data;
257
258 /* Loop through destination's pixel and fill each pixel with
259 the interpolation of 4 nearest neighboring pixels.*/
260 for (y = 0; y < height; y++)
261 {
262 for (x = 0; x < width; x++)
263 {
264 /* Find the original source pixel that the destination pixel conrespond to. */
265 xx = (xradio * x) >> 8;
266 yy = (yradio * y) >> 8;
267
268 /* The coordinates of the original source pixel are truncate value,
269 calucate their distance between the mathematical coordinates. */
270 xdiff = (xradio * x) & 0xff;
271 ydiff = (yradio * y) & 0xff;
272
273 get = (GX_UBYTE *)src -> gx_pixelmap_data;
274 get += yy * src -> gx_pixelmap_width;
275 get += xx;
276
277 getalpha = (GX_UBYTE *)src -> gx_pixelmap_aux_data;
278 getalpha += yy * src -> gx_pixelmap_width;
279 getalpha += xx;
280
281
282 /* Calculate 4 nearest neighboring pixels around the mathematical point of original pixel. */
283 neighbor_pixels[0][0] = *get;
284 alpha[0] = *getalpha;
285
286 if ((xx < src -> gx_pixelmap_width - 1) && (yy < src -> gx_pixelmap_height - 1))
287 {
288 neighbor_pixels[0][1] = *(get + 1);
289 neighbor_pixels[1][0] = *(get + src -> gx_pixelmap_width);
290 neighbor_pixels[1][1] = *(get + src -> gx_pixelmap_width + 1);
291
292 alpha[1] = *(getalpha + 1);
293 alpha[2] = *(getalpha + src -> gx_pixelmap_width);
294 alpha[3] = *(getalpha + src -> gx_pixelmap_width + 1);
295 }
296 else
297 {
298
299 if ((xx == src -> gx_pixelmap_width - 1) &&
300 (yy == src -> gx_pixelmap_height - 1))
301 {
302 /* Handle right bottom corder pixel. */
303 neighbor_pixels[0][1] = neighbor_pixels[0][0];
304 neighbor_pixels[1][0] = neighbor_pixels[0][0];
305 neighbor_pixels[1][1] = neighbor_pixels[0][0];
306
307 alpha[1] = alpha[0];
308 alpha[2] = alpha[0];
309 alpha[3] = alpha[0];
310 }
311 else if (xx == src -> gx_pixelmap_width - 1)
312 {
313 /* Handle pixels in right edge. */
314 neighbor_pixels[0][1] = neighbor_pixels[0][0];
315 neighbor_pixels[1][0] = *(get + src -> gx_pixelmap_width);
316 neighbor_pixels[1][1] = neighbor_pixels[1][0];
317
318 alpha[1] = alpha[0];
319 alpha[2] = *(getalpha + src -> gx_pixelmap_width);
320 alpha[3] = alpha[2];
321 }
322 else
323 {
324 /* Handle pixels in bottom edge. */
325 neighbor_pixels[0][1] = *(get + 1);
326 neighbor_pixels[1][0] = neighbor_pixels[0][0];
327 neighbor_pixels[1][1] = neighbor_pixels[0][1];
328
329 alpha[1] = *(getalpha + 1);
330 alpha[2] = alpha[0];
331 alpha[3] = alpha[1];
332 }
333 }
334
335 /* Calulate pixel values by interpolating 4 neighboring pixels. */
336 red = (REDVAL_332(neighbor_pixels[0][0]) * (alpha[0]) * (256 - (GX_COLOR)xdiff) * (256 - (GX_COLOR)ydiff) + \
337 REDVAL_332(neighbor_pixels[0][1]) * (alpha[1]) * (GX_COLOR)xdiff * (256 - (GX_COLOR)ydiff) + \
338 REDVAL_332(neighbor_pixels[1][0]) * (alpha[2]) * (GX_COLOR)ydiff * (256 - (GX_COLOR)xdiff) + \
339 REDVAL_332(neighbor_pixels[1][1]) * (alpha[3]) * (GX_COLOR)xdiff * (GX_COLOR)ydiff) >> 16;
340
341 green = (GREENVAL_332(neighbor_pixels[0][0]) * (alpha[0]) * (256 - (GX_COLOR)xdiff) * (256 - (GX_COLOR)ydiff) + \
342 GREENVAL_332(neighbor_pixels[0][1]) * (alpha[1]) * (GX_COLOR)xdiff * (256 - (GX_COLOR)ydiff) + \
343 GREENVAL_332(neighbor_pixels[1][0]) * (alpha[2]) * (GX_COLOR)ydiff * (256 - (GX_COLOR)xdiff) + \
344 GREENVAL_332(neighbor_pixels[1][1]) * (alpha[3]) * (GX_COLOR)xdiff * (GX_COLOR)ydiff) >> 16;
345
346 blue = (BLUEVAL_332(neighbor_pixels[0][0]) * (alpha[0]) * (256 - (GX_COLOR)xdiff) * (256 - (GX_COLOR)ydiff) + \
347 BLUEVAL_332(neighbor_pixels[0][1]) * (alpha[1]) * (GX_COLOR)xdiff * (256 - (GX_COLOR)ydiff) + \
348 BLUEVAL_332(neighbor_pixels[1][0]) * (alpha[2]) * (GX_COLOR)ydiff * (256 - (GX_COLOR)xdiff) + \
349 BLUEVAL_332(neighbor_pixels[1][1]) * (alpha[3]) * (GX_COLOR)xdiff * (GX_COLOR)ydiff) >> 16;
350
351 alpha[0] = ((alpha[0]) * (256 - (GX_COLOR)xdiff) * (256 - (GX_COLOR)ydiff) + \
352 (alpha[1]) * (GX_COLOR)xdiff * (256 - (GX_COLOR)ydiff) + \
353 (alpha[2]) * (GX_COLOR)ydiff * (256 - (GX_COLOR)xdiff) + \
354 (alpha[3]) * (GX_COLOR)xdiff * (GX_COLOR)ydiff) >> 16;
355
356 if (alpha[0])
357 {
358 red /= alpha[0];
359 green /= alpha[0];
360 blue /= alpha[0];
361 }
362
363 alpha[0] = alpha[0] > 255 ? 255 : alpha[0];
364 red = red > 7 ? 7 : red;
365 green = green > 7 ? 7 : green;
366 blue = blue > 3 ? 3 : blue;
367
368 *put++ = (GX_UBYTE)ASSEMBLECOLOR_332(red, green, blue);
369 *putalpha++ = (GX_UBYTE)alpha[0];
370 }
371 }
372
373 return GX_SUCCESS;
374 }
375 /**************************************************************************/
376 /* */
377 /* FUNCTION RELEASE */
378 /* */
379 /* _gx_utility_8bpp_pixelmap_resize PORTABLE C */
380 /* 6.1 */
381 /* AUTHOR */
382 /* */
383 /* Kenneth Maxwell, Microsoft Corporation */
384 /* */
385 /* DESCRIPTION */
386 /* */
387 /* This function resize an 8bpp format uncompressed pixelmap with or */
388 /* without transparent channel. */
389 /* */
390 /* INPUT */
391 /* */
392 /* src The source pixelmap */
393 /* destination The resized pixelmap to be */
394 /* returned */
395 /* width New width */
396 /* height New height */
397 /* */
398 /* OUTPUT */
399 /* */
400 /* status Completion status */
401 /* */
402 /* CALLS */
403 /* */
404 /* _gx_system_memory_allocator Application defined memory */
405 /* allocation function */
406 /* */
407 /* CALLED BY */
408 /* */
409 /* GUIX Internal Code */
410 /* */
411 /* RELEASE HISTORY */
412 /* */
413 /* DATE NAME DESCRIPTION */
414 /* */
415 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
416 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
417 /* resulting in version 6.1 */
418 /* */
419 /**************************************************************************/
_gx_utility_8bpp_pixelmap_resize(GX_PIXELMAP * src,GX_PIXELMAP * destination,INT width,INT height)420 UINT _gx_utility_8bpp_pixelmap_resize(GX_PIXELMAP *src, GX_PIXELMAP *destination, INT width, INT height)
421 {
422 UINT status;
423
424 if (src -> gx_pixelmap_flags & GX_PIXELMAP_ALPHA)
425 {
426 /* alpha, no compression */
427 status = _gx_utility_8bpp_pixelmap_alpha_resize(src, destination, width, height);
428 }
429 else
430 {
431 /* no compression or transparent channel */
432 status = _gx_utility_8bpp_pixelmap_raw_resize(src, destination, width, height);
433 }
434
435 return status;
436 }
437
438 /**************************************************************************/
439 /* */
440 /* FUNCTION RELEASE */
441 /* */
442 /* _gx_utility_8bit_alphamap_resize PORTABLE C */
443 /* 6.1.7 */
444 /* AUTHOR */
445 /* */
446 /* Kenneth Maxwell, Microsoft Corporation */
447 /* */
448 /* DESCRIPTION */
449 /* */
450 /* This function resize an 8bit uncompressed alphamap. */
451 /* */
452 /* INPUT */
453 /* */
454 /* src The source pixelmap */
455 /* destination The resized pixelmap to be */
456 /* returned */
457 /* width New width */
458 /* height New height */
459 /* */
460 /* OUTPUT */
461 /* */
462 /* status Completion status */
463 /* */
464 /* CALLS */
465 /* */
466 /* _gx_system_memory_allocator Application defined memory */
467 /* allocation function */
468 /* */
469 /* CALLED BY */
470 /* */
471 /* GUIX Internal Code */
472 /* */
473 /* RELEASE HISTORY */
474 /* */
475 /* DATE NAME DESCRIPTION */
476 /* */
477 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
478 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
479 /* resulting in version 6.1 */
480 /* 06-02-2021 Kenneth Maxwell Modified comment(s), */
481 /* removed unused variable */
482 /* assignment, */
483 /* resulting in version 6.1.7 */
484 /* */
485 /**************************************************************************/
_gx_utility_8bit_alphamap_resize(GX_PIXELMAP * src,GX_PIXELMAP * destination,INT width,INT height)486 UINT _gx_utility_8bit_alphamap_resize(GX_PIXELMAP *src, GX_PIXELMAP *destination, INT width, INT height)
487 {
488 /* The pixelmap resize function is implemented from bilinear interpolation
489 image scaling algorithm. */
490
491 GX_UBYTE *get;
492 GX_UBYTE *put;
493 INT xdiff;
494 INT ydiff;
495 INT xradio;
496 INT yradio;
497 INT x;
498 INT y;
499 INT xx;
500 INT yy;
501 GX_UBYTE neighbor_pixels[2][2] = {{0, 0}, {0, 0}};
502 INT alpha;
503
504 /* Calculate scale ratio and enlarge it by 256 times to keep precision. */
505 xradio = ((src -> gx_pixelmap_width) << 8) / width;
506 yradio = ((src -> gx_pixelmap_height) << 8) / height;
507
508 /* Fill property values into destination pixelmap structure. */
509 destination -> gx_pixelmap_flags = src -> gx_pixelmap_flags;
510 destination -> gx_pixelmap_format = src -> gx_pixelmap_format;
511
512 destination -> gx_pixelmap_height = (GX_VALUE)height;
513 destination -> gx_pixelmap_width = (GX_VALUE)width;
514
515 /* Safe int math is not required here, calling function limits max width, height to 14 bits so
516 overflow cannot occur. */
517 destination -> gx_pixelmap_data_size = (UINT)(height * width) * sizeof(GX_COLOR);
518
519 /* Allocate memory to load pixelmap data. */
520 destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
521
522 if (destination -> gx_pixelmap_data == GX_NULL)
523 {
524 return GX_SYSTEM_MEMORY_ERROR;
525 }
526
527 put = (GX_UBYTE *)destination -> gx_pixelmap_data;
528
529 /* Loop through destination's pixel and fill each pixel with
530 the interpolation of 4 nearest neighboring pixels.*/
531 for (y = 0; y < height; y++)
532 {
533 for (x = 0; x < width; x++)
534 {
535 /* Find the original source pixel that the destination pixel conrespond to. */
536 xx = (xradio * x) >> 8;
537 yy = (yradio * y) >> 8;
538
539 /* The coordinates of the original source pixel are truncate value,
540 calucate their distance between the mathematical coordinates. */
541 xdiff = xradio * x - (xx << 8);
542 ydiff = yradio * y - (yy << 8);
543
544 get = (GX_UBYTE *)src -> gx_pixelmap_data;
545 get += yy * src -> gx_pixelmap_width;
546 get += xx;
547
548 /* Calculate 4 nearest neighboring pixels around the mathematical point of original pixel. */
549 neighbor_pixels[0][0] = *get;
550
551 if ((xx < src -> gx_pixelmap_width - 1) && (yy < src -> gx_pixelmap_height - 1))
552 {
553 neighbor_pixels[0][1] = *(get + 1);
554 neighbor_pixels[1][0] = *(get + src -> gx_pixelmap_width);
555 neighbor_pixels[1][1] = *(get + src -> gx_pixelmap_width + 1);
556 }
557 else
558 {
559
560 if ((xx == src -> gx_pixelmap_width - 1) &&
561 (yy == src -> gx_pixelmap_height - 1))
562 {
563 /* Hanle pixels in right bottom corner. */
564 neighbor_pixels[0][1] = neighbor_pixels[0][0];
565 neighbor_pixels[1][0] = neighbor_pixels[0][0];
566 neighbor_pixels[1][1] = neighbor_pixels[0][0];
567 }
568 else if (xx == src -> gx_pixelmap_width - 1)
569 {
570 /* Handle pixels in right edge. */
571 neighbor_pixels[0][1] = neighbor_pixels[0][0];
572 neighbor_pixels[1][0] = *(get + src -> gx_pixelmap_width);
573 neighbor_pixels[1][1] = neighbor_pixels[1][0];
574 }
575 else
576 {
577 /* Handle pixels in bottom edge. */
578 neighbor_pixels[0][1] = *(get + 1);
579 neighbor_pixels[1][0] = neighbor_pixels[0][0];
580 neighbor_pixels[1][1] = neighbor_pixels[0][1];
581 }
582 }
583
584 /* Calulate alpha values by interpolating 4 neighboring pixels. */
585 alpha = (INT)(((neighbor_pixels[0][0]) * (256 - (ULONG)xdiff) * (256 - (ULONG)ydiff) + \
586 (neighbor_pixels[0][1]) * (ULONG)xdiff * (256 - (ULONG)ydiff) + \
587 (neighbor_pixels[1][0]) * (ULONG)ydiff * (256 - (ULONG)xdiff) + \
588 (neighbor_pixels[1][1]) * (ULONG)xdiff * (ULONG)ydiff) >> 16);
589
590 *put++ = (GX_UBYTE)alpha;
591 }
592 }
593
594 return GX_SUCCESS;
595 }
596
597