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 /** Image Reader Management (Image Reader) */
18 /** */
19 /**************************************************************************/
20
21 #define GX_SOURCE_CODE
22
23
24 /* Include necessary system files. */
25
26 #include "gx_api.h"
27 #include "gx_system.h"
28 #include "gx_image_reader.h"
29
30 #define GX_FS_SCALE 10
31 #define GX_DITHER_SPECKLE_LIMIT 400
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _gx_image_reader_one_row_dither PORTABLE C */
38 /* 6.1 */
39 /* AUTHOR */
40 /* */
41 /* Kenneth Maxwell, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This helper function does dithering for one row of the pixelmap. */
46 /* */
47 /* INPUT */
48 /* */
49 /* image_reader Image reader control block */
50 /* error_ptr Memory for error information */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* None */
55 /* */
56 /* CALLS */
57 /* */
58 /* [gx_image_reader_pixel_read] Read a pixel from input buffer*/
59 /* [gx_image_reader_pixel_write] Write a pixel out with */
60 /* specified color format */
61 /* */
62 /* CALLED BY */
63 /* */
64 /* _gx_image_reader_colorspace_convert */
65 /* */
66 /* RELEASE HISTORY */
67 /* */
68 /* DATE NAME DESCRIPTION */
69 /* */
70 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
71 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
72 /* resulting in version 6.1 */
73 /* */
74 /**************************************************************************/
75 #if defined(GX_SOFTWARE_DECODER_SUPPORT)
_gx_image_reader_one_row_dither(GX_IMAGE_READER * image_reader,INT * error_ptr)76 static VOID _gx_image_reader_one_row_dither(GX_IMAGE_READER *image_reader, INT *error_ptr)
77 {
78 UINT width;
79 UINT err_width;
80 UINT col;
81 GX_PIXEL want_pixel;
82 GX_PIXEL written_pixel;
83 INT red_err;
84 INT green_err;
85 INT blue_err;
86 INT *next_err;
87 INT *cur_err;
88
89 width = image_reader -> gx_image_reader_image_width;
90 err_width = width + 2;
91
92 cur_err = error_ptr;
93 next_err = error_ptr + err_width * 3;
94 memset(next_err, 0, sizeof(INT) * err_width * 3);
95
96 for (col = 0; col < width; col++)
97 {
98 image_reader -> gx_image_reader_pixel_read(image_reader, (INT)col, &want_pixel);
99
100 red_err = (cur_err[col + 1] >> GX_FS_SCALE);
101 green_err = (cur_err[err_width + col + 1] >> GX_FS_SCALE);
102 blue_err = (cur_err[err_width * 2 + col + 1] >> GX_FS_SCALE);
103
104 if (want_pixel.gx_pixel_red + red_err > 255)
105 {
106 want_pixel.gx_pixel_red = 255;
107 }
108 else if (want_pixel.gx_pixel_red + red_err < 0)
109 {
110 want_pixel.gx_pixel_red = 0;
111 }
112 else
113 {
114 want_pixel.gx_pixel_red = (GX_UBYTE)(want_pixel.gx_pixel_red + red_err);
115 }
116
117 if (want_pixel.gx_pixel_green + green_err > 255)
118 {
119 want_pixel.gx_pixel_green = 255;
120 }
121 else if (want_pixel.gx_pixel_green + green_err < 0)
122 {
123 want_pixel.gx_pixel_green = 0;
124 }
125 else
126 {
127 want_pixel.gx_pixel_green = (GX_UBYTE)(want_pixel.gx_pixel_green + green_err);
128 }
129
130 if (want_pixel.gx_pixel_blue + blue_err > 255)
131 {
132 want_pixel.gx_pixel_blue = 255;
133 }
134 else if (want_pixel.gx_pixel_blue + blue_err < 0)
135 {
136 want_pixel.gx_pixel_blue = 0;
137 }
138 else
139 {
140 want_pixel.gx_pixel_blue = (GX_UBYTE)(want_pixel.gx_pixel_blue + blue_err);
141 }
142
143 written_pixel = want_pixel;
144
145 image_reader -> gx_image_reader_pixel_write(image_reader, &written_pixel);
146
147 /* Calculate color space convert error. */
148 red_err = ((want_pixel.gx_pixel_red - written_pixel.gx_pixel_red) << GX_FS_SCALE);
149 green_err = ((want_pixel.gx_pixel_green - written_pixel.gx_pixel_green) << GX_FS_SCALE);
150 blue_err = ((want_pixel.gx_pixel_blue - written_pixel.gx_pixel_blue) << GX_FS_SCALE);
151
152 /* Red error. */
153 if (GX_ABS(red_err) > GX_DITHER_SPECKLE_LIMIT)
154 {
155 cur_err[col + 2] += ((red_err * 7) >> 4);
156 next_err[col] += ((red_err * 3) >> 4);
157 next_err[col + 1] += ((red_err * 5) >> 4);
158 next_err[col + 2] += ((red_err) >> 4);
159 }
160 else
161 {
162 cur_err[col + 2] = 0;
163 next_err[col] = 0;
164 next_err[col + 1] = 0;
165 next_err[col + 2] = 0;
166 }
167
168 /* Green error. */
169 if (GX_ABS(green_err) > GX_DITHER_SPECKLE_LIMIT)
170 {
171 cur_err[err_width + col + 2] += ((green_err * 7) >> 4);
172 next_err[err_width + col] += ((green_err * 3) >> 4);
173 next_err[err_width + col + 1] += ((green_err * 5) >> 4);
174 next_err[err_width + col + 2] += ((green_err) >> 4);
175 }
176 else
177 {
178 cur_err[err_width + col + 2] = 0;
179 next_err[err_width + col] = 0;
180 next_err[err_width + col + 1] = 0;
181 next_err[err_width + col + 2] = 0;
182 }
183
184 /* Blue error. */
185 if (GX_ABS(blue_err) > GX_DITHER_SPECKLE_LIMIT)
186 {
187 cur_err[err_width * 2 + col + 2] += ((blue_err * 7) >> 4);
188 next_err[err_width * 2 + col] += ((blue_err * 3) >> 4);
189 next_err[err_width * 2 + col + 1] += ((blue_err * 5) >> 4);
190 next_err[err_width * 2 + col + 2] += ((blue_err) >> 4);
191 }
192 else
193 {
194 cur_err[err_width * 2 + col + 2] = 0;
195 next_err[err_width * 2 + col] = 0;
196 next_err[err_width * 2 + col + 1] = 0;
197 next_err[err_width * 2 + col + 2] = 0;
198 }
199 }
200
201 memcpy((void *)cur_err, (void *)next_err, err_width * 3 * sizeof(INT)); /* Use case of memcpy is verified. */
202 }
203 #endif
204
205 /**************************************************************************/
206 /* */
207 /* FUNCTION RELEASE */
208 /* */
209 /* _gx_image_reader_one_row_convert PORTABLE C */
210 /* 6.1 */
211 /* AUTHOR */
212 /* */
213 /* Kenneth Maxwell, Microsoft Corporation */
214 /* */
215 /* DESCRIPTION */
216 /* */
217 /* This helper function converts pixel data to specified color format */
218 /* for one row of the pixelmap. */
219 /* */
220 /* INPUT */
221 /* */
222 /* image_reader Image reader control block */
223 /* width Pointer to pixelmap width */
224 /* */
225 /* OUTPUT */
226 /* */
227 /* None */
228 /* */
229 /* CALLS */
230 /* */
231 /* [gx_image_reader_pixel_read] Read a pixel from input buffer*/
232 /* [gx_image_reader_pixel_write] Write a pixel out with */
233 /* specified color format */
234 /* */
235 /* CALLED BY */
236 /* */
237 /* _gx_image_reader_colorspace_convert */
238 /* */
239 /* RELEASE HISTORY */
240 /* */
241 /* DATE NAME DESCRIPTION */
242 /* */
243 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
244 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
245 /* resulting in version 6.1 */
246 /* */
247 /**************************************************************************/
248 #if defined(GX_SOFTWARE_DECODER_SUPPORT)
_gx_image_reader_one_row_convert(GX_IMAGE_READER * image_reader,INT * width)249 static VOID _gx_image_reader_one_row_convert(GX_IMAGE_READER *image_reader, INT *width)
250 {
251 INT xval;
252 GX_PIXEL pixel;
253
254 for (xval = 0; xval < (*width); xval++)
255 {
256 image_reader -> gx_image_reader_pixel_read(image_reader, xval, &pixel);
257 image_reader -> gx_image_reader_pixel_write(image_reader, &pixel);
258 }
259 }
260 #endif
261
262 /**************************************************************************/
263 /* */
264 /* FUNCTION RELEASE */
265 /* */
266 /* _gx_image_reader_one_row_rotated_convert PORTABLE C */
267 /* 6.1.3 */
268 /* AUTHOR */
269 /* */
270 /* Kenneth Maxwell, Microsoft Corporation */
271 /* */
272 /* DESCRIPTION */
273 /* */
274 /* This helper function converts pixel data to specified color format */
275 /* for one row of the pixelmap with rotation. */
276 /* */
277 /* INPUT */
278 /* */
279 /* image_reader Image reader control block */
280 /* width Pointer to pixelmap width */
281 /* */
282 /* OUTPUT */
283 /* */
284 /* None */
285 /* */
286 /* CALLS */
287 /* */
288 /* [gx_image_reader_pixel_read] Read a pixel from input buffer*/
289 /* [gx_image_reader_pixel_write] Write a pixel out with */
290 /* specified color format */
291 /* */
292 /* CALLED BY */
293 /* */
294 /* _gx_image_reader_colorspace_convert */
295 /* */
296 /* RELEASE HISTORY */
297 /* */
298 /* DATE NAME DESCRIPTION */
299 /* */
300 /* 12-31-2020 Kenneth Maxwell Initial Version 6.1.3 */
301 /* */
302 /**************************************************************************/
303 #if defined(GX_SOFTWARE_DECODER_SUPPORT)
_gx_image_reader_one_row_rotated_convert(GX_IMAGE_READER * image_reader,INT * width)304 static VOID _gx_image_reader_one_row_rotated_convert(GX_IMAGE_READER *image_reader, INT *width)
305 {
306 INT xval;
307 GX_PIXEL pixel;
308
309 image_reader -> gx_image_reader_putdata = image_reader -> gx_image_reader_putdatarow;
310 image_reader -> gx_image_reader_putauxdata = image_reader -> gx_image_reader_putauxdatarow;
311
312 for (xval = 0; xval < (*width); xval++)
313 {
314 image_reader -> gx_image_reader_pixel_read(image_reader, xval, &pixel);
315 image_reader -> gx_image_reader_pixel_write(image_reader, &pixel);
316 }
317
318 image_reader -> gx_image_reader_putdatarow += image_reader -> gx_image_reader_putdatarow_stride;
319 image_reader -> gx_image_reader_putauxdatarow += image_reader -> gx_image_reader_putauxdatarow_stride;
320 }
321 #endif
322
323 /**************************************************************************/
324 /* */
325 /* FUNCTION RELEASE */
326 /* */
327 /* _gx_image_reader_colorspace_convert PORTABLE C */
328 /* 6.1 */
329 /* AUTHOR */
330 /* */
331 /* Kenneth Maxwell, Microsoft Corporation */
332 /* */
333 /* DESCRIPTION */
334 /* */
335 /* This function converts a pixelmap to the specified color format */
336 /* with or without dithering process. */
337 /* */
338 /* INPUT */
339 /* */
340 /* image_reader Image reader control block */
341 /* outmap Output pixelmap */
342 /* */
343 /* OUTPUT */
344 /* */
345 /* None */
346 /* */
347 /* CALLS */
348 /* */
349 /* _gx_image_reader_one_row_dither Process dithering for one row */
350 /* _gx_image_reader_one_row_convert Process direct convert for one */
351 /* row */
352 /* */
353 /* CALLED BY */
354 /* */
355 /* GUIX Internal Code */
356 /* */
357 /* RELEASE HISTORY */
358 /* */
359 /* DATE NAME DESCRIPTION */
360 /* */
361 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
362 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
363 /* resulting in version 6.1 */
364 /* */
365 /**************************************************************************/
366 #if defined(GX_SOFTWARE_DECODER_SUPPORT)
_gx_image_reader_colorspace_convert(GX_IMAGE_READER * image_reader,GX_PIXELMAP * outmap)367 UINT _gx_image_reader_colorspace_convert(GX_IMAGE_READER *image_reader, GX_PIXELMAP *outmap)
368 {
369 INT yval;
370 INT *param = GX_NULL;
371 INT width;
372 INT height;
373 VOID (*row_convert)(GX_IMAGE_READER *, INT *);
374
375 width = outmap -> gx_pixelmap_width;
376 height = outmap -> gx_pixelmap_height;
377
378 if (image_reader -> gx_image_reader_mode & GX_IMAGE_READER_MODE_DITHER)
379 {
380 /* This function is called to convert decoded png/jpeg data to guix format pixelmap,
381 max png/jpeg width and heigt is limited to 14 bits, so overflow cannot occur. */
382 param = (INT *)_gx_system_memory_allocator(sizeof(INT) * (UINT)(width + 2) * 6);
383
384 if (!param)
385 {
386 return GX_SYSTEM_MEMORY_ERROR;
387 }
388
389 memset((VOID *)param, 0, (sizeof(INT) * (UINT)(width + 2) * 3));
390 row_convert = _gx_image_reader_one_row_dither;
391 }
392 else
393 {
394 param = &width;
395
396 if (image_reader -> gx_image_reader_mode & (GX_IMAGE_READER_MODE_ROTATE_CW | GX_IMAGE_READER_MODE_ROTATE_CCW))
397 {
398 row_convert = _gx_image_reader_one_row_rotated_convert;
399 }
400 else
401 {
402 row_convert = _gx_image_reader_one_row_convert;
403 }
404 }
405
406 image_reader -> gx_image_reader_size_testing = GX_FALSE;
407
408 /* Run color space convert. */
409 for (yval = 0; yval < height; yval++)
410 {
411 row_convert(image_reader, param);
412
413 image_reader -> gx_image_reader_getdata += image_reader -> gx_image_reader_input_stride;
414 image_reader -> gx_image_reader_getauxdata += width;
415
416 switch (image_reader -> gx_image_reader_color_format)
417 {
418 case GX_COLOR_FORMAT_4BIT_GRAY:
419 if (image_reader -> gx_image_reader_putdata_mask != 0xf0)
420 {
421 image_reader -> gx_image_reader_putdata++;
422 image_reader -> gx_image_reader_putdata_mask = 0xf0;
423 }
424
425 if (image_reader -> gx_image_reader_putauxdata)
426 {
427 if (image_reader -> gx_image_reader_putauxdata_mask != 0x80)
428 {
429 image_reader -> gx_image_reader_putauxdata++;
430 image_reader -> gx_image_reader_putauxdata_mask = 0x80;
431 }
432 }
433 break;
434
435 case GX_COLOR_FORMAT_MONOCHROME:
436 if (image_reader -> gx_image_reader_putdata_mask != 0x80)
437 {
438 image_reader -> gx_image_reader_putdata++;
439 image_reader -> gx_image_reader_putdata_mask = 0x80;
440 }
441 break;
442 }
443 }
444
445 if (image_reader -> gx_image_reader_mode & GX_IMAGE_READER_MODE_DITHER)
446 {
447 _gx_system_memory_free((VOID *)param);
448 }
449
450 return GX_SUCCESS;
451 }
452 #endif
453
454