xref: /aosp_15_r20/external/coreboot/src/lib/jpeg.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 /*
4  * Provide a simple API around the Wuffs JPEG decoder
5  * Uses the heap (and lots of it) for the image-size specific
6  * work buffer, so ramstage-only.
7  */
8 
9 #include <stdint.h>
10 
11 #include "jpeg.h"
12 
13 #define WUFFS_CONFIG__AVOID_CPU_ARCH
14 #define WUFFS_CONFIG__MODULES
15 #define WUFFS_CONFIG__MODULE__BASE
16 #define WUFFS_CONFIG__MODULE__JPEG
17 #define WUFFS_CONFIG__STATIC_FUNCTIONS
18 #define WUFFS_IMPLEMENTATION
19 #include "../vendorcode/wuffs/wuffs-v0.4.c"
20 
21 /* ~16K is big enough to move this off the stack */
22 static wuffs_jpeg__decoder dec;
23 
jpeg_fetch_size(unsigned char * filedata,size_t filesize,unsigned int * width,unsigned int * height)24 int jpeg_fetch_size(unsigned char *filedata, size_t filesize, unsigned int *width,
25 		    unsigned int *height)
26 {
27 	if (!width || !height) {
28 		return JPEG_DECODE_FAILED;
29 	}
30 
31 	wuffs_base__status status = wuffs_jpeg__decoder__initialize(
32 		&dec, sizeof(dec), WUFFS_VERSION, WUFFS_INITIALIZE__DEFAULT_OPTIONS);
33 	if (status.repr) {
34 		return JPEG_DECODE_FAILED;
35 	}
36 
37 	wuffs_base__image_config imgcfg;
38 	wuffs_base__io_buffer src = wuffs_base__ptr_u8__reader(filedata, filesize, true);
39 	status = wuffs_jpeg__decoder__decode_image_config(&dec, &imgcfg, &src);
40 	if (status.repr) {
41 		return JPEG_DECODE_FAILED;
42 	}
43 
44 	*width = wuffs_base__pixel_config__width(&imgcfg.pixcfg);
45 	*height = wuffs_base__pixel_config__height(&imgcfg.pixcfg);
46 
47 	return 0;
48 }
49 
jpeg_decode(unsigned char * filedata,size_t filesize,unsigned char * pic,unsigned int width,unsigned int height,unsigned int bytes_per_line,unsigned int depth)50 int jpeg_decode(unsigned char *filedata, size_t filesize, unsigned char *pic,
51 		unsigned int width, unsigned int height, unsigned int bytes_per_line,
52 		unsigned int depth)
53 {
54 	if (!filedata || !pic) {
55 		return JPEG_DECODE_FAILED;
56 	}
57 	/* Relatively arbitrary limit that shouldn't hurt anybody.
58 	 * 300M (10k*10k*3bytes/pixel) is already larger than our heap, so
59 	 * it's on the safe side.
60 	 * This avoids overflows when width or height are used for
61 	 * calculations in this function.
62 	 */
63 	if ((width > 10000) || (height > 10000)) {
64 		return JPEG_DECODE_FAILED;
65 	}
66 
67 	uint32_t pixfmt;
68 	switch (depth) {
69 	case 16:
70 		pixfmt = WUFFS_BASE__PIXEL_FORMAT__BGR_565;
71 		break;
72 	case 24:
73 		pixfmt = WUFFS_BASE__PIXEL_FORMAT__BGR;
74 		break;
75 	case 32:
76 		pixfmt = WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL;
77 		break;
78 	default:
79 		return JPEG_DECODE_FAILED;
80 	}
81 
82 	wuffs_base__status status = wuffs_jpeg__decoder__initialize(
83 		&dec, sizeof(dec), WUFFS_VERSION, WUFFS_INITIALIZE__DEFAULT_OPTIONS);
84 	if (status.repr) {
85 		return JPEG_DECODE_FAILED;
86 	}
87 
88 	wuffs_base__image_config imgcfg;
89 	wuffs_base__io_buffer src = wuffs_base__ptr_u8__reader(filedata, filesize, true);
90 	status = wuffs_jpeg__decoder__decode_image_config(&dec, &imgcfg, &src);
91 	if (status.repr) {
92 		return JPEG_DECODE_FAILED;
93 	}
94 
95 	wuffs_base__pixel_config pixcfg;
96 	wuffs_base__pixel_config__set(&pixcfg, pixfmt, 0, width, height);
97 
98 	wuffs_base__pixel_buffer pixbuf;
99 	status = wuffs_base__pixel_buffer__set_interleaved(
100 		&pixbuf, &pixcfg,
101 		wuffs_base__make_table_u8(pic, width * (depth / 8), height, bytes_per_line),
102 		wuffs_base__empty_slice_u8());
103 	if (status.repr) {
104 		return JPEG_DECODE_FAILED;
105 	}
106 
107 	uint64_t workbuf_len_min_incl = wuffs_jpeg__decoder__workbuf_len(&dec).min_incl;
108 	uint8_t *workbuf_array = malloc(workbuf_len_min_incl);
109 	if ((workbuf_array == NULL) && workbuf_len_min_incl) {
110 		return JPEG_DECODE_FAILED;
111 	}
112 
113 	wuffs_base__slice_u8 workbuf =
114 		wuffs_base__make_slice_u8(workbuf_array, workbuf_len_min_incl);
115 	status = wuffs_jpeg__decoder__decode_frame(&dec, &pixbuf, &src,
116 						   WUFFS_BASE__PIXEL_BLEND__SRC, workbuf, NULL);
117 
118 	free(workbuf_array);
119 
120 	if (status.repr) {
121 		return JPEG_DECODE_FAILED;
122 	}
123 
124 	return 0;
125 }
126