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_utility.h"
29 #include "gx_image_reader.h"
30
31 #if defined(GX_SOFTWARE_DECODER_SUPPORT)
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _gx_image_reader_rgb2gray PORTABLE C */
38 /* 6.1 */
39 /* AUTHOR */
40 /* */
41 /* Kenneth Maxwell, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function converts RGB value to grayscale. */
46 /* */
47 /* INPUT */
48 /* */
49 /* pixel RGB value */
50 /* gray Grayscale value to return */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* None */
55 /* */
56 /* CALLS */
57 /* */
58 /* None */
59 /* */
60 /* CALLED BY */
61 /* */
62 /* GUIX Internal Code */
63 /* */
64 /* RELEASE HISTORY */
65 /* */
66 /* DATE NAME DESCRIPTION */
67 /* */
68 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
69 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
70 /* resulting in version 6.1 */
71 /* */
72 /**************************************************************************/
_gx_image_reader_rgb2gray(GX_PIXEL * pixel,GX_UBYTE * gray)73 VOID _gx_image_reader_rgb2gray(GX_PIXEL *pixel, GX_UBYTE *gray)
74 {
75 (*gray) = (GX_UBYTE)((pixel -> gx_pixel_red * 299 +
76 pixel -> gx_pixel_green * 587 +
77 pixel -> gx_pixel_blue * 114) / 1000);
78 }
79
80 /**************************************************************************/
81 /* */
82 /* FUNCTION RELEASE */
83 /* */
84 /* _gx_image_reader_gray_threshold_calculate PORTABLE C */
85 /* 6.1 */
86 /* AUTHOR */
87 /* */
88 /* Kenneth Maxwell, Microsoft Corporation */
89 /* */
90 /* DESCRIPTION */
91 /* */
92 /* This function calcualtes thredshold value used to create monochrome */
93 /* pixlemap. */
94 /* */
95 /* INPUT */
96 /* */
97 /* image_reader Image reader control block */
98 /* */
99 /* OUTPUT */
100 /* */
101 /* None */
102 /* */
103 /* CALLS */
104 /* */
105 /* [gx_image_reader_pixel_read] Pixel read callback */
106 /* _gx_image_reader_rgb2gray Conver RGB value to grayscale */
107 /* */
108 /* CALLED BY */
109 /* */
110 /* _gx_image_reader_start */
111 /* */
112 /* RELEASE HISTORY */
113 /* */
114 /* DATE NAME DESCRIPTION */
115 /* */
116 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
117 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
118 /* resulting in version 6.1 */
119 /* */
120 /**************************************************************************/
_gx_image_reader_gray_threshold_calculate(GX_IMAGE_READER * image_reader)121 static VOID _gx_image_reader_gray_threshold_calculate(GX_IMAGE_READER *image_reader)
122 {
123 INT threshold = 0;
124 INT xval;
125 INT yval;
126 INT count = 0;
127 GX_PIXEL pixel;
128 GX_UBYTE gray;
129
130 for (yval = 0; yval < (INT)image_reader -> gx_image_reader_image_height; yval++)
131 {
132 for (xval = 0; xval < (INT)image_reader -> gx_image_reader_image_width; xval++)
133 {
134 image_reader -> gx_image_reader_pixel_read(image_reader, xval, &pixel);
135
136 if (pixel.gx_pixel_alpha > 128)
137 {
138 /* Convert RGB value to grayscale. */
139 _gx_image_reader_rgb2gray(&pixel, &gray);
140 threshold += gray;
141 count++;
142 }
143 }
144
145 image_reader -> gx_image_reader_getdata += image_reader -> gx_image_reader_input_stride;
146 }
147
148 if (count)
149 {
150 image_reader -> gx_image_reader_mono_shreshold = (GX_UBYTE)(threshold / count);
151 }
152
153 if (image_reader -> gx_image_reader_mono_shreshold == 0)
154 {
155 /* All opaque pixels are black. */
156 image_reader -> gx_image_reader_mono_shreshold = 255;
157 }
158 else if (image_reader -> gx_image_reader_mono_shreshold == 255)
159 {
160 /* All opqaute pixels are white. */
161 image_reader -> gx_image_reader_mono_shreshold = 0;
162 }
163 }
164
165
166 /**************************************************************************/
167 /* */
168 /* FUNCTION RELEASE */
169 /* */
170 /* _gx_image_reader_pixelmap_info_set PORTABLE C */
171 /* 6.1 */
172 /* AUTHOR */
173 /* */
174 /* Kenneth Maxwell, Microsoft Corporation */
175 /* */
176 /* DESCRIPTION */
177 /* */
178 /* This function prepares for image converting. */
179 /* */
180 /* INPUT */
181 /* */
182 /* image_reader Image reader control block */
183 /* outmap Pointer to a pixelmap that is */
184 /* used to loading converted */
185 /* image */
186 /* */
187 /* OUTPUT */
188 /* */
189 /* Completion status */
190 /* */
191 /* CALLS */
192 /* */
193 /* None */
194 /* */
195 /* CALLED BY */
196 /* */
197 /* _gx_image_reader_start */
198 /* */
199 /* RELEASE HISTORY */
200 /* */
201 /* DATE NAME DESCRIPTION */
202 /* */
203 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
204 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
205 /* resulting in version 6.1 */
206 /* */
207 /**************************************************************************/
_gx_image_reader_pixelmap_info_set(GX_IMAGE_READER * image_reader,GX_PIXELMAP * outmap)208 static UINT _gx_image_reader_pixelmap_info_set(GX_IMAGE_READER *image_reader, GX_PIXELMAP *outmap)
209 {
210 outmap -> gx_pixelmap_width = (GX_VALUE)image_reader -> gx_image_reader_image_width;
211 outmap -> gx_pixelmap_height = (GX_VALUE)image_reader -> gx_image_reader_image_height;
212 outmap -> gx_pixelmap_data_size = 0;
213 outmap -> gx_pixelmap_aux_data_size = 0;
214 outmap -> gx_pixelmap_format = image_reader -> gx_image_reader_color_format;
215
216 /* Set alpha flag. */
217 if (image_reader -> gx_image_reader_mode & GX_IMAGE_READER_MODE_ALPHA)
218 {
219 switch (outmap -> gx_pixelmap_format)
220 {
221 case GX_COLOR_FORMAT_8BIT_PALETTE:
222 case GX_COLOR_FORMAT_4BIT_GRAY:
223 case GX_COLOR_FORMAT_MONOCHROME:
224 outmap -> gx_pixelmap_flags = GX_PIXELMAP_TRANSPARENT;
225 outmap -> gx_pixelmap_transparent_color = GX_TRANSPARENT_COLOR;
226 break;
227
228 default:
229 outmap -> gx_pixelmap_flags = GX_PIXELMAP_ALPHA;
230 break;
231 }
232 }
233
234 /* Calculate pixelmap data size, which will be used for memory allocation lator. Max width and height is limited to 14 bits,
235 so overflow cannot occur. */
236 switch (outmap -> gx_pixelmap_format)
237 {
238 case GX_COLOR_FORMAT_565RGB:
239 case GX_COLOR_FORMAT_1555XRGB:
240 outmap -> gx_pixelmap_data_size = (ULONG)(outmap -> gx_pixelmap_width * outmap -> gx_pixelmap_height * (INT)sizeof(USHORT));
241
242 if (outmap -> gx_pixelmap_flags & GX_PIXELMAP_ALPHA)
243 {
244 outmap -> gx_pixelmap_aux_data_size = (ULONG)(outmap -> gx_pixelmap_width * outmap -> gx_pixelmap_height);
245 }
246 break;
247
248 case GX_COLOR_FORMAT_4444ARGB:
249 outmap -> gx_pixelmap_data_size = (ULONG)(outmap -> gx_pixelmap_width * outmap -> gx_pixelmap_height * (INT)sizeof(USHORT));
250 break;
251
252 case GX_COLOR_FORMAT_32ARGB:
253 case GX_COLOR_FORMAT_24XRGB:
254 outmap -> gx_pixelmap_data_size = (ULONG)(outmap -> gx_pixelmap_width * outmap -> gx_pixelmap_height * (INT)sizeof(GX_COLOR));
255 image_reader -> gx_image_reader_mode = (GX_UBYTE)(image_reader -> gx_image_reader_mode & (~GX_IMAGE_READER_MODE_DITHER));
256 break;
257
258 case GX_COLOR_FORMAT_8BIT_ALPHAMAP:
259 case GX_COLOR_FORMAT_8BIT_PALETTE:
260 outmap -> gx_pixelmap_data_size = (ULONG)(outmap -> gx_pixelmap_width * outmap -> gx_pixelmap_height);
261 break;
262
263 case GX_COLOR_FORMAT_4BIT_GRAY:
264 outmap -> gx_pixelmap_data_size = (ULONG)(((outmap -> gx_pixelmap_width + 1) >> 1) * outmap -> gx_pixelmap_height);
265 if (image_reader -> gx_image_reader_mode & GX_IMAGE_READER_MODE_ALPHA)
266 {
267 outmap -> gx_pixelmap_aux_data_size = (ULONG)(((outmap -> gx_pixelmap_width + 7) >> 3) * outmap -> gx_pixelmap_height);
268 }
269 break;
270
271 case GX_COLOR_FORMAT_MONOCHROME:
272 if (image_reader -> gx_image_reader_mode & GX_IMAGE_READER_MODE_ALPHA)
273 {
274 outmap -> gx_pixelmap_data_size = (ULONG)(((outmap -> gx_pixelmap_width + 3) >> 2) * outmap -> gx_pixelmap_height);
275 }
276 else
277 {
278 outmap -> gx_pixelmap_data_size = (ULONG)(((outmap -> gx_pixelmap_width + 7) >> 3) * outmap -> gx_pixelmap_height);
279 }
280 break;
281
282 default:
283 return GX_NOT_SUPPORTED;
284 }
285
286 return GX_SUCCESS;
287 }
288
289 /**************************************************************************/
290 /* */
291 /* FUNCTION RELEASE */
292 /* */
293 /* _gx_image_reader_start PORTABLE C */
294 /* 6.3.0 */
295 /* AUTHOR */
296 /* */
297 /* Kenneth Maxwell, Microsoft Corporation */
298 /* */
299 /* DESCRIPTION */
300 /* */
301 /* This function converts pixelmap to a specified color format. */
302 /* */
303 /* INPUT */
304 /* */
305 /* image_reader Image reader control block */
306 /* outmap Output pixelmap */
307 /* */
308 /* OUTPUT */
309 /* */
310 /* None */
311 /* */
312 /* CALLS */
313 /* */
314 /* memcpy */
315 /* memset */
316 /* _gx_system_memory_allocator Application defined memory */
317 /* allocation function */
318 /* _gx_system_memory_free Application defined memory */
319 /* free function */
320 /* _gx_image_reader_image_decode Decode specified image */
321 /* _gx_image_reader_pixel_read_callback_set */
322 /* Set pixel read callback */
323 /* _gx_image_reader_pixel_write_callback_set */
324 /* Set pixel write callback */
325 /* _gx_image_reader_dither Process dither algorithm */
326 /* _gx_image_reader_rle_encode Compress image with RLE */
327 /* algorithm */
328 /* _gx_image_reader_raw_convert Convert raw format map to */
329 /* specified format */
330 /* */
331 /* CALLED BY */
332 /* */
333 /* Application Code */
334 /* */
335 /* RELEASE HISTORY */
336 /* */
337 /* DATE NAME DESCRIPTION */
338 /* */
339 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
340 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
341 /* resulting in version 6.1 */
342 /* 10-31-2023 Ting Zhu Modified comment(s), */
343 /* improved logic, */
344 /* resulting in version 6.3.0 */
345 /* */
346 /**************************************************************************/
_gx_image_reader_start(GX_IMAGE_READER * image_reader,GX_PIXELMAP * outmap)347 UINT _gx_image_reader_start(GX_IMAGE_READER *image_reader, GX_PIXELMAP *outmap)
348 {
349 UINT status;
350 GX_PIXELMAP srcmap;
351 GX_PIXELMAP tempmap;
352 UINT compressed_data_size;
353 UINT compressed_aux_size;
354 UINT raw_size;
355 GX_BOOL do_compress;
356
357 memset(outmap, 0, sizeof(GX_PIXELMAP));
358 memset(&srcmap, 0, sizeof(GX_PIXELMAP));
359
360 if (!_gx_system_memory_allocator)
361 {
362 return GX_SYSTEM_MEMORY_ERROR;
363 }
364
365 /* Decode input image to raw format. */
366 status = _gx_image_reader_image_decode(image_reader, &srcmap);
367
368 if (status == GX_SUCCESS)
369 {
370 /* Set output pixelmap information. */
371 image_reader -> gx_image_reader_image_width = (UINT)srcmap.gx_pixelmap_width;
372 image_reader -> gx_image_reader_image_height = (UINT)srcmap.gx_pixelmap_height;
373
374 status = _gx_image_reader_pixelmap_info_set(image_reader, outmap);
375 }
376
377 if (image_reader -> gx_image_reader_mode & GX_IMAGE_READER_MODE_COMPRESS)
378 {
379 do_compress = GX_TRUE;
380 }
381 else
382 {
383 do_compress = GX_FALSE;
384 }
385
386 if((image_reader -> gx_image_reader_image_type == GX_IMAGE_TYPE_JPG && srcmap.gx_pixelmap_format == GX_IMAGE_FORMAT_24BPP) ||
387 (image_reader -> gx_image_reader_image_type == GX_IMAGE_TYPE_PNG))
388 {
389
390 if (status == GX_SUCCESS)
391 {
392 if (image_reader -> gx_image_reader_color_format == GX_COLOR_FORMAT_MONOCHROME)
393 {
394 status = _gx_image_reader_pixel_read_callback_set(image_reader, &srcmap);
395 _gx_image_reader_gray_threshold_calculate(image_reader);
396 }
397 }
398
399 image_reader -> gx_image_reader_mode = (GX_UBYTE)(image_reader -> gx_image_reader_mode & (~GX_IMAGE_READER_MODE_COMPRESS));
400
401 /* Color Space Convert. */
402 if (status == GX_SUCCESS)
403 {
404 tempmap = *outmap;
405
406 status = _gx_image_reader_pixel_read_callback_set(image_reader, &srcmap);
407 }
408
409 if (status == GX_SUCCESS)
410 {
411 status = _gx_image_reader_pixel_write_callback_set(image_reader, &tempmap);
412 }
413
414 if (status == GX_SUCCESS)
415 {
416 status = _gx_image_reader_colorspace_convert(image_reader, &tempmap);
417
418 _gx_system_memory_free((VOID *)srcmap.gx_pixelmap_data);
419
420 if (srcmap.gx_pixelmap_aux_data)
421 {
422 _gx_system_memory_free((VOID *)srcmap.gx_pixelmap_aux_data);
423 }
424
425 srcmap = tempmap;
426 }
427 }
428
429 /* Compare compressed size and raw size. */
430 if (do_compress)
431 {
432 image_reader -> gx_image_reader_mode |= GX_IMAGE_READER_MODE_COMPRESS;
433
434 /* Seet pixel read and write callback. */
435 if (status == GX_SUCCESS)
436 {
437 status = _gx_image_reader_pixel_read_callback_set(image_reader, &srcmap);
438 }
439
440 if (status == GX_SUCCESS)
441 {
442 tempmap = *outmap;
443 tempmap.gx_pixelmap_data_size = 0;
444 tempmap.gx_pixelmap_aux_data_size = 0;
445 tempmap.gx_pixelmap_flags |= GX_PIXELMAP_COMPRESSED;
446
447 status = _gx_image_reader_pixel_write_callback_set(image_reader, &tempmap);
448 }
449
450 /* Calculate the storage size that needed for rle encode. */
451 if (status == GX_SUCCESS)
452 {
453 _gx_image_reader_rle_encode_size_get(image_reader, &compressed_data_size, &compressed_aux_size);
454
455 raw_size = outmap -> gx_pixelmap_aux_data_size + outmap -> gx_pixelmap_data_size;
456
457 /* Test wheather the encoded data size is smaller that raw size. */
458 if (compressed_aux_size + compressed_data_size < raw_size)
459 {
460 outmap -> gx_pixelmap_data_size = compressed_data_size;
461 outmap -> gx_pixelmap_aux_data_size = compressed_aux_size;
462 outmap -> gx_pixelmap_flags |= GX_PIXELMAP_COMPRESSED;
463
464 _gx_image_reader_pixel_read_callback_set(image_reader, &srcmap);
465
466 status = _gx_image_reader_pixel_write_callback_set(image_reader, outmap);
467
468 if (status == GX_SUCCESS)
469 {
470 status = _gx_image_reader_rle_encode(image_reader, outmap);
471 }
472 }
473 else
474 {
475 *outmap = srcmap;
476 memset(&srcmap, 0, sizeof(GX_PIXELMAP));
477 }
478 }
479 }
480 else
481 {
482 *outmap = srcmap;
483 memset(&srcmap, 0, sizeof(GX_PIXELMAP));
484 }
485
486 /* Release memory that used to load decoded pixelmap data. */
487 if (srcmap.gx_pixelmap_data)
488 {
489 _gx_system_memory_free((VOID *)srcmap.gx_pixelmap_data);
490 }
491
492 if (srcmap.gx_pixelmap_aux_data)
493 {
494 _gx_system_memory_free((VOID *)srcmap.gx_pixelmap_aux_data);
495 }
496
497 if (image_reader -> gx_image_reader_png_trans)
498 {
499 _gx_system_memory_free((VOID *)image_reader -> gx_image_reader_png_trans);
500 }
501
502 if (status != GX_SUCCESS)
503 {
504 if (outmap -> gx_pixelmap_data)
505 {
506 _gx_system_memory_free((VOID *)outmap -> gx_pixelmap_data);
507 outmap -> gx_pixelmap_data = GX_NULL;
508 }
509
510 if (outmap -> gx_pixelmap_aux_data)
511 {
512 _gx_system_memory_free((VOID *)outmap -> gx_pixelmap_aux_data);
513 outmap -> gx_pixelmap_aux_data = GX_NULL;
514 }
515 }
516
517 return status;
518 }
519 #endif
520
521