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) >> 16)
22 #define GREENVAL(_c) (GX_UBYTE)((_c) >> 8)
23 #define BLUEVAL(_c) (GX_UBYTE)(_c)
24
25 #define ASSEMBLECOLOR(_r, _g, _b) \
26 ((GX_COLOR)(((_r) << 16) | \
27 ((_g) << 8)) | \
28 (_b))
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_32argb_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_32argb_pixelmap_raw_resize(GX_PIXELMAP * src,GX_PIXELMAP * destination,INT width,INT height)89 static UINT _gx_utility_32argb_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 GX_COLOR *get;
95 GX_COLOR *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 GX_COLOR neighbor_pixels[2][2];
105 INT red;
106 INT green;
107 INT blue;
108
109
110 /* Calculate scale ratio and enlarge it by 256 times to keep precision. */
111 xradio = ((src -> gx_pixelmap_width) << 8) / width;
112 yradio = ((src -> gx_pixelmap_height) << 8) / height;
113
114 /* Fill property values into destination pixelmap structure. */
115 destination -> gx_pixelmap_flags = src -> gx_pixelmap_flags;
116 destination -> gx_pixelmap_format = src -> gx_pixelmap_format;
117
118 destination -> gx_pixelmap_height = (GX_VALUE)height;
119 destination -> gx_pixelmap_width = (GX_VALUE)width;
120
121 /* Safe int math is not required here, calling function limits max width, height to 14 bits so
122 overflow cannot occur. */
123 destination -> gx_pixelmap_data_size = (UINT)(height * width) * sizeof(GX_COLOR);
124
125 /* Allocate memory for destination pixelmap. */
126 destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
127
128 if (destination -> gx_pixelmap_data == GX_NULL)
129 {
130 return GX_SYSTEM_MEMORY_ERROR;
131 }
132
133 put = (GX_COLOR *)destination -> gx_pixelmap_data;
134
135 /* Loop throught destination's pixels and fill each pixel with the interpolation of
136 4 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 = (GX_COLOR *)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 if ((xx == src -> gx_pixelmap_width - 1) &&
166 (yy == src -> gx_pixelmap_height - 1))
167 {
168 /* Handle the bottom right pixel. */
169 neighbor_pixels[0][1] = neighbor_pixels[0][0];
170 neighbor_pixels[1][0] = neighbor_pixels[0][0];
171 neighbor_pixels[1][1] = neighbor_pixels[0][0];
172 }
173 else if (xx == src -> gx_pixelmap_width - 1)
174 {
175 /* Handle the pixel in right-most edge. */
176 neighbor_pixels[0][1] = neighbor_pixels[0][0];
177 neighbor_pixels[1][0] = *(get + src -> gx_pixelmap_width);
178 neighbor_pixels[1][1] = neighbor_pixels[1][0];
179 }
180 else
181 {
182 /* Handle the pixel in bottom edge. */
183 neighbor_pixels[0][1] = *(get + 1);
184 neighbor_pixels[1][0] = neighbor_pixels[0][0];
185 neighbor_pixels[1][1] = neighbor_pixels[0][1];
186 }
187 }
188
189 /* Calulate pixel values by interpolating 4 neighboring pixels. */
190 red = (REDVAL(neighbor_pixels[0][0]) * (256 - xdiff) * (256 - ydiff) + \
191 REDVAL(neighbor_pixels[0][1]) * xdiff * (256 - ydiff) + \
192 REDVAL(neighbor_pixels[1][0]) * ydiff * (256 - xdiff) + \
193 REDVAL(neighbor_pixels[1][1]) * xdiff * ydiff) >> 16;
194
195 green = (GREENVAL(neighbor_pixels[0][0]) * (256 - xdiff) * (256 - ydiff) + \
196 GREENVAL(neighbor_pixels[0][1]) * xdiff * (256 - ydiff) + \
197 GREENVAL(neighbor_pixels[1][0]) * ydiff * (256 - xdiff) + \
198 GREENVAL(neighbor_pixels[1][1]) * xdiff * ydiff) >> 16;
199
200 blue = (BLUEVAL(neighbor_pixels[0][0]) * (256 - xdiff) * (256 - ydiff) + \
201 BLUEVAL(neighbor_pixels[0][1]) * xdiff * (256 - ydiff) + \
202 BLUEVAL(neighbor_pixels[1][0]) * ydiff * (256 - xdiff) + \
203 BLUEVAL(neighbor_pixels[1][1]) * xdiff * ydiff) >> 16;
204
205 red = BYTE_RANGE(red);
206 green = BYTE_RANGE(green);
207 blue = BYTE_RANGE(blue);
208
209 *put++ = ASSEMBLECOLOR((GX_COLOR)red, (GX_COLOR)green, (GX_COLOR)blue);
210 }
211 }
212
213 return GX_SUCCESS;
214 }
215
216 /**************************************************************************/
217 /* */
218 /* FUNCTION RELEASE */
219 /* */
220 /* _gx_utility_32argb_pixelmap_alpha_resize PORTABLE C */
221 /* 6.1.7 */
222 /* AUTHOR */
223 /* */
224 /* Kenneth Maxwell, Microsoft Corporation */
225 /* */
226 /* DESCRIPTION */
227 /* */
228 /* Internal helper function that resize an uncompressed pixelmap */
229 /* with alpha. */
230 /* */
231 /* INPUT */
232 /* */
233 /* src The source pixelmap */
234 /* destination The resized pixelmap to be */
235 /* returned */
236 /* width New width */
237 /* height New height */
238 /* */
239 /* OUTPUT */
240 /* */
241 /* status Completion status */
242 /* */
243 /* CALLS */
244 /* */
245 /* None */
246 /* */
247 /* CALLED BY */
248 /* */
249 /* GUIX Internal Code */
250 /* */
251 /* RELEASE HISTORY */
252 /* */
253 /* DATE NAME DESCRIPTION */
254 /* */
255 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
256 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
257 /* resulting in version 6.1 */
258 /* 06-02-2021 Kenneth Maxwell Modified comment(s), */
259 /* removed unused variable */
260 /* assignment, */
261 /* resulting in version 6.1.7 */
262 /* */
263 /**************************************************************************/
_gx_utility_32argb_pixelmap_alpha_resize(GX_PIXELMAP * src,GX_PIXELMAP * destination,INT width,INT height)264 static UINT _gx_utility_32argb_pixelmap_alpha_resize(GX_PIXELMAP *src, GX_PIXELMAP *destination, INT width, INT height)
265 {
266 /* The pixelmap resize function is implemented from bilinear interpolation
267 image scaling algorithm. */
268
269 GX_COLOR *get;
270 GX_COLOR *put;
271 INT xdiff;
272 INT ydiff;
273 INT xradio;
274 INT yradio;
275 INT x;
276 INT y;
277 INT xx;
278 INT yy;
279 GX_COLOR neighbor_pixels[2][2] = {{0, 0}, {0, 0}};
280 INT red;
281 INT green;
282 INT blue;
283 INT alpha;
284
285 /* Calculate scale ratio and enlarge it by 256 times to keep precision. */
286 xradio = ((src -> gx_pixelmap_width) << 8) / width;
287 yradio = ((src -> gx_pixelmap_height) << 8) / height;
288
289 /* Fill property values into destination pixelmap structure. */
290 destination -> gx_pixelmap_flags = src -> gx_pixelmap_flags;
291 destination -> gx_pixelmap_format = src -> gx_pixelmap_format;
292
293 destination -> gx_pixelmap_height = (GX_VALUE)height;
294 destination -> gx_pixelmap_width = (GX_VALUE)width;
295
296 /* Safe int math is not required here, calling function limits max width, height to 14 bits so
297 overflow cannot occur. */
298 destination -> gx_pixelmap_data_size = (UINT)(height * width) * sizeof(GX_COLOR);
299
300 /* Allocate memory to load pixelmap data. */
301 destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
302
303 if (destination -> gx_pixelmap_data == GX_NULL)
304 {
305 return GX_SYSTEM_MEMORY_ERROR;
306 }
307
308 put = (GX_COLOR *)destination -> gx_pixelmap_data;
309
310 /* Loop through destination's pixel and fill each pixel with
311 the interpolation of 4 nearest neighboring pixels.*/
312 for (y = 0; y < height; y++)
313 {
314 for (x = 0; x < width; x++)
315 {
316 /* Find the original source pixel that the destination pixel conrespond to. */
317 xx = (xradio * x) >> 8;
318 yy = (yradio * y) >> 8;
319
320 /* The coordinates of the original source pixel are truncate value,
321 calucate their distance between the mathematical coordinates. */
322 xdiff = xradio * x - (xx << 8);
323 ydiff = yradio * y - (yy << 8);
324
325 get = (GX_COLOR *)src -> gx_pixelmap_data;
326 get += yy * src -> gx_pixelmap_width;
327 get += xx;
328
329 /* Calculate 4 nearest neighboring pixels around the mathematical point of original pixel. */
330 neighbor_pixels[0][0] = *get;
331
332 if ((xx < src -> gx_pixelmap_width - 1) && (yy < src -> gx_pixelmap_height - 1))
333 {
334 neighbor_pixels[0][1] = *(get + 1);
335 neighbor_pixels[1][0] = *(get + src -> gx_pixelmap_width);
336 neighbor_pixels[1][1] = *(get + src -> gx_pixelmap_width + 1);
337 }
338 else
339 {
340
341 if ((xx == src -> gx_pixelmap_width - 1) &&
342 (yy == src -> gx_pixelmap_height - 1))
343 {
344 /* Hanle pixels in right bottom corner. */
345 neighbor_pixels[0][1] = neighbor_pixels[0][0];
346 neighbor_pixels[1][0] = neighbor_pixels[0][0];
347 neighbor_pixels[1][1] = neighbor_pixels[0][0];
348 }
349 else if (xx == src -> gx_pixelmap_width - 1)
350 {
351 /* Handle pixels in right edge. */
352 neighbor_pixels[0][1] = neighbor_pixels[0][0];
353 neighbor_pixels[1][0] = *(get + src -> gx_pixelmap_width);
354 neighbor_pixels[1][1] = neighbor_pixels[1][0];
355 }
356 else
357 {
358 /* Handle pixels in bottom edge. */
359 neighbor_pixels[0][1] = *(get + 1);
360 neighbor_pixels[1][0] = neighbor_pixels[0][0];
361 neighbor_pixels[1][1] = neighbor_pixels[0][1];
362 }
363 }
364
365 /* Calulate pixel values by interpolating 4 neighboring pixels. */
366 red = (INT)((REDVAL(neighbor_pixels[0][0]) * (neighbor_pixels[0][0] >> 24) * (256 - (ULONG)xdiff) * (256 - (ULONG)ydiff) + \
367 REDVAL(neighbor_pixels[0][1]) * (neighbor_pixels[0][1] >> 24) * (ULONG)xdiff * (256 - (ULONG)ydiff) + \
368 REDVAL(neighbor_pixels[1][0]) * (neighbor_pixels[1][0] >> 24) * (ULONG)ydiff * (256 - (ULONG)xdiff) + \
369 REDVAL(neighbor_pixels[1][1]) * (neighbor_pixels[1][1] >> 24) * (ULONG)xdiff * (ULONG)ydiff) >> 16);
370
371 green = (INT)((GREENVAL(neighbor_pixels[0][0]) * (neighbor_pixels[0][0] >> 24) * (256 - (ULONG)xdiff) * (256 - (ULONG)ydiff) + \
372 GREENVAL(neighbor_pixels[0][1]) * (neighbor_pixels[0][1] >> 24) * (ULONG)xdiff * (256 - (ULONG)ydiff) + \
373 GREENVAL(neighbor_pixels[1][0]) * (neighbor_pixels[1][0] >> 24) * (ULONG)ydiff * (256 - (ULONG)xdiff) + \
374 GREENVAL(neighbor_pixels[1][1]) * (neighbor_pixels[1][1] >> 24) * (ULONG)xdiff * (ULONG)ydiff) >> 16);
375
376 blue = (INT)((BLUEVAL(neighbor_pixels[0][0]) * (neighbor_pixels[0][0] >> 24) * (256 - (ULONG)xdiff) * (256 - (ULONG)ydiff) + \
377 BLUEVAL(neighbor_pixels[0][1]) * (neighbor_pixels[0][1] >> 24) * (ULONG)xdiff * (256 - (ULONG)ydiff) + \
378 BLUEVAL(neighbor_pixels[1][0]) * (neighbor_pixels[1][0] >> 24) * (ULONG)ydiff * (256 - (ULONG)xdiff) + \
379 BLUEVAL(neighbor_pixels[1][1]) * (neighbor_pixels[1][1] >> 24) * (ULONG)xdiff * (ULONG)ydiff) >> 16);
380
381 alpha = (INT)(((neighbor_pixels[0][0] >> 24) * (256 - (ULONG)xdiff) * (256 - (ULONG)ydiff) + \
382 (neighbor_pixels[0][1] >> 24) * (ULONG)xdiff * (256 - (ULONG)ydiff) + \
383 (neighbor_pixels[1][0] >> 24) * (ULONG)ydiff * (256 - (ULONG)xdiff) + \
384 (neighbor_pixels[1][1] >> 24) * (ULONG)xdiff * (ULONG)ydiff) >> 16);
385
386 if (alpha)
387 {
388 red /= alpha;
389 green /= alpha;
390 blue /= alpha;
391 }
392
393 alpha = BYTE_RANGE(alpha);
394 red = BYTE_RANGE(red);
395 green = BYTE_RANGE(green);
396 blue = BYTE_RANGE(blue);
397
398 *put++ = ASSEMBLECOLOR((ULONG)red, (ULONG)green, (ULONG)blue) + ((ULONG)alpha << 24);
399 }
400 }
401
402 return GX_SUCCESS;
403 }
404
405 /**************************************************************************/
406 /* */
407 /* FUNCTION RELEASE */
408 /* */
409 /* _gx_utility_32argb_pixelmap_resize PORTABLE C */
410 /* 6.1 */
411 /* AUTHOR */
412 /* */
413 /* Kenneth Maxwell, Microsoft Corporation */
414 /* */
415 /* DESCRIPTION */
416 /* */
417 /* 32argb pixelmap resize function that handles uncompress, with or */
418 /* alpha channel. */
419 /* */
420 /* INPUT */
421 /* */
422 /* src The source pixelmap */
423 /* destination The resized pixelmap to be */
424 /* returned */
425 /* width New width */
426 /* height New height */
427 /* */
428 /* OUTPUT */
429 /* */
430 /* status Completion status */
431 /* */
432 /* CALLS */
433 /* */
434 /* _gx_utility_32argb_pixelmap_alpha_resize */
435 /* _gx_utility_32argb_pixelmap_raw_resize */
436 /* */
437 /* CALLED BY */
438 /* */
439 /* GUIX Internal Code */
440 /* */
441 /* RELEASE HISTORY */
442 /* */
443 /* DATE NAME DESCRIPTION */
444 /* */
445 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
446 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
447 /* resulting in version 6.1 */
448 /* */
449 /**************************************************************************/
_gx_utility_32argb_pixelmap_resize(GX_PIXELMAP * src,GX_PIXELMAP * destination,INT width,INT height)450 UINT _gx_utility_32argb_pixelmap_resize(GX_PIXELMAP *src, GX_PIXELMAP *destination, INT width, INT height)
451 {
452 UINT status;
453
454 if (src -> gx_pixelmap_flags & GX_PIXELMAP_ALPHA)
455 {
456 /* alpha, no compression */
457
458 status = _gx_utility_32argb_pixelmap_alpha_resize(src, destination, width, height);
459 }
460 else
461 {
462 /* no compression or alpha */
463
464 status = _gx_utility_32argb_pixelmap_raw_resize(src, destination, width, height);
465 }
466
467 return status;
468 }
469
470