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 ALPHAVAL(_c)   (GX_UBYTE)(((_c) >> 12) & 0xf)
22 #define REDVAL(_c)     (GX_UBYTE)(((_c) >> 8) & 0xf)
23 #define GREENVAL(_c)   (GX_UBYTE)(((_c) >> 4) & 0xf)
24 #define BLUEVAL(_c)    (GX_UBYTE)(((_c)) & 0xf)
25 
26 #define ASSEMBLECOLOR(_a, _r, _g, _b)              \
27       (USHORT)((((_a) & 0xf) << 12)              | \
28                (((_r) & 0xf) << 8)               | \
29                (((_g) & 0xf) << 4)               | \
30                ((_b) & 0xf))
31 
32 #define BYTE_RANGE(_c) _c > 15 ? 15 : _c
33 
34 #define GX_SOURCE_CODE
35 
36 
37 /* Include necessary system files.  */
38 
39 #include "gx_api.h"
40 #include "gx_utility.h"
41 #include "gx_system.h"
42 
43 /**************************************************************************/
44 /*                                                                        */
45 /*  FUNCTION                                               RELEASE        */
46 /*                                                                        */
47 /*    _gx_utility_4444argb_pixelmap_resize                PORTABLE C      */
48 /*                                                           6.1.7        */
49 /*  AUTHOR                                                                */
50 /*                                                                        */
51 /*    Kenneth Maxwell, Microsoft Corporation                              */
52 /*                                                                        */
53 /*  DESCRIPTION                                                           */
54 /*                                                                        */
55 /*    4444argb pixelmap resize function that handles uncompress,          */
56 /*    with alpha channel.                                                 */
57 /*                                                                        */
58 /*  INPUT                                                                 */
59 /*                                                                        */
60 /*    src                                   The source pixelmap           */
61 /*    destination                           The resized pixelmap to be    */
62 /*                                            returned                    */
63 /*    width                                 New width                     */
64 /*    height                                New height                    */
65 /*                                                                        */
66 /*  OUTPUT                                                                */
67 /*                                                                        */
68 /*    status                                Completion status             */
69 /*                                                                        */
70 /*  CALLS                                                                 */
71 /*                                                                        */
72 /*                                                                        */
73 /*  CALLED BY                                                             */
74 /*                                                                        */
75 /*    GUIX Internal Code                                                  */
76 /*                                                                        */
77 /*  RELEASE HISTORY                                                       */
78 /*                                                                        */
79 /*    DATE              NAME                      DESCRIPTION             */
80 /*                                                                        */
81 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
82 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
83 /*                                            resulting in version 6.1    */
84 /*  06-02-2021     Kenneth Maxwell          Modified comment(s),          */
85 /*                                            removed unused variable     */
86 /*                                            assignment,                 */
87 /*                                            resulting in version 6.1.7  */
88 /*                                                                        */
89 /**************************************************************************/
_gx_utility_4444argb_pixelmap_resize(GX_PIXELMAP * src,GX_PIXELMAP * destination,INT width,INT height)90 UINT _gx_utility_4444argb_pixelmap_resize(GX_PIXELMAP *src, GX_PIXELMAP *destination, INT width, INT height)
91 {
92 USHORT  *get;
93 USHORT  *put;
94 INT      xdiff;
95 INT      ydiff;
96 INT      xradio;
97 INT      yradio;
98 INT      x;
99 INT      y;
100 INT      xx;
101 INT      yy;
102 USHORT   neighbor_pixels[2][2];
103 GX_COLOR alpha[4];
104 GX_COLOR red;
105 GX_COLOR green;
106 GX_COLOR blue;
107 
108     /* Calculate scale ratio and enlarge it by 256 times to keep precision.  */
109     xradio = ((src -> gx_pixelmap_width) << 8) / width;
110     yradio = ((src -> gx_pixelmap_height) << 8) / height;
111 
112     /* Fill property values into destination pixelmap structure. */
113     destination -> gx_pixelmap_flags = src -> gx_pixelmap_flags;
114     destination -> gx_pixelmap_format = src -> gx_pixelmap_format;
115 
116     destination -> gx_pixelmap_height = (GX_VALUE)height;
117     destination -> gx_pixelmap_width = (GX_VALUE)width;
118 
119     /* Safe int math is not required here, calling function limits max width, height to 14 bits so
120        overflow cannot occur. */
121     destination -> gx_pixelmap_data_size = (UINT)(height * width) * sizeof(USHORT);
122 
123     /* Allocate memory to load pixelmap data. */
124     destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
125 
126     if (destination -> gx_pixelmap_data == GX_NULL)
127     {
128         return GX_SYSTEM_MEMORY_ERROR;
129     }
130 
131     put = (USHORT *)destination -> gx_pixelmap_data;
132 
133     for (y = 0; y < height; y++)
134     {
135         for (x = 0; x < width; x++)
136         {
137             xx = (xradio * x) >> 8;
138             yy = (yradio * y) >> 8;
139 
140             /* The coordinates of the original source pixel are truncate value,
141                calucate their distance between the mathematical coordinates. */
142             xdiff = (xradio * x) & 0xff;
143             ydiff = (yradio * y) & 0xff;
144 
145             get = (USHORT *)src -> gx_pixelmap_data;
146             get += yy * src -> gx_pixelmap_width;
147             get += xx;
148 
149             neighbor_pixels[0][0] = *get;
150 
151             if ((xx < src -> gx_pixelmap_width - 1) && (yy < src -> gx_pixelmap_height - 1))
152             {
153                 neighbor_pixels[0][1] = *(get + 1);
154                 neighbor_pixels[1][0] = *(get + src -> gx_pixelmap_width);
155                 neighbor_pixels[1][1] = *(get + src -> gx_pixelmap_width + 1);
156             }
157             else
158             {
159                 if ((xx == src -> gx_pixelmap_width - 1) &&
160                     (yy == src -> gx_pixelmap_height - 1))
161                 {
162                     /* Handle right bottom corder pixel.  */
163                     neighbor_pixels[0][1] = neighbor_pixels[0][0];
164                     neighbor_pixels[1][0] = neighbor_pixels[0][0];
165                     neighbor_pixels[1][1] = neighbor_pixels[0][0];
166                 }
167                 else if (xx == src -> gx_pixelmap_width - 1)
168                 {
169                     /* Handle pixels in right edge.  */
170                     neighbor_pixels[0][1] = neighbor_pixels[0][0];
171                     neighbor_pixels[1][0] = *(get + src -> gx_pixelmap_width);
172                     neighbor_pixels[1][1] = neighbor_pixels[1][0];
173                 }
174                 else
175                 {
176                     /* Handle pixels in bottom edge.  */
177                     neighbor_pixels[0][1] = *(get + 1);
178                     neighbor_pixels[1][0] = neighbor_pixels[0][0];
179                     neighbor_pixels[1][1] = neighbor_pixels[0][1];
180                 }
181             }
182             alpha[0] = ALPHAVAL(neighbor_pixels[0][0]);
183             alpha[1] = ALPHAVAL(neighbor_pixels[0][1]);
184             alpha[2] = ALPHAVAL(neighbor_pixels[1][0]);
185             alpha[3] = ALPHAVAL(neighbor_pixels[1][1]);
186 
187             /* Calulate pixel values by interpolating 4 neighboring pixels. */
188             red = (REDVAL(neighbor_pixels[0][0]) * (alpha[0]) * (256 - (GX_COLOR)xdiff) * (256 - (GX_COLOR)ydiff) + \
189                    REDVAL(neighbor_pixels[0][1]) * (alpha[1]) * (GX_COLOR)xdiff * (256 - (GX_COLOR)ydiff) +         \
190                    REDVAL(neighbor_pixels[1][0]) * (alpha[2]) * (GX_COLOR)ydiff * (256 - (GX_COLOR)xdiff) +         \
191                    REDVAL(neighbor_pixels[1][1]) * (alpha[3]) * (GX_COLOR)xdiff * (GX_COLOR)ydiff) >> 16;
192 
193             green = (GREENVAL(neighbor_pixels[0][0]) * (alpha[0]) * (256 - (GX_COLOR)xdiff) * (256 - (GX_COLOR)ydiff) + \
194                      GREENVAL(neighbor_pixels[0][1]) * (alpha[1]) * (GX_COLOR)xdiff * (256 - (GX_COLOR)ydiff) +         \
195                      GREENVAL(neighbor_pixels[1][0]) * (alpha[2]) * (GX_COLOR)ydiff * (256 - (GX_COLOR)xdiff) +         \
196                      GREENVAL(neighbor_pixels[1][1]) * (alpha[3]) * (GX_COLOR)xdiff * (GX_COLOR)ydiff) >> 16;
197 
198             blue = (BLUEVAL(neighbor_pixels[0][0]) * (alpha[0]) * (256 - (GX_COLOR)xdiff) * (256 - (GX_COLOR)ydiff) + \
199                     BLUEVAL(neighbor_pixels[0][1]) * (alpha[1]) * (GX_COLOR)xdiff * (256 - (GX_COLOR)ydiff) +         \
200                     BLUEVAL(neighbor_pixels[1][0]) * (alpha[2]) * (GX_COLOR)ydiff * (256 - (GX_COLOR)xdiff) +         \
201                     BLUEVAL(neighbor_pixels[1][1]) * (alpha[3]) * (GX_COLOR)xdiff * (GX_COLOR)ydiff) >> 16;
202 
203             alpha[0] = ((alpha[0]) * (256 - (GX_COLOR)xdiff) * (256 - (GX_COLOR)ydiff) + \
204                         (alpha[1]) * (GX_COLOR)xdiff * (256 - (GX_COLOR)ydiff) +         \
205                         (alpha[2]) * (GX_COLOR)ydiff * (256 - (GX_COLOR)xdiff) +         \
206                         (alpha[3]) * (GX_COLOR)xdiff * (GX_COLOR)ydiff) >> 16;
207 
208             if (alpha[0])
209             {
210                 red /= alpha[0];
211                 green /= alpha[0];
212                 blue /= alpha[0];
213             }
214 
215             alpha[0] = BYTE_RANGE(alpha[0]);
216             red = BYTE_RANGE(red);
217             green = BYTE_RANGE(green);
218             blue = BYTE_RANGE(blue);
219 
220             *put++ = ASSEMBLECOLOR(alpha[0], red, green, blue);
221         }
222     }
223 
224     return GX_SUCCESS;
225 }
226 
227