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