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