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