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