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