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