mb/hardkernel/odroid-h4: Correct number of jacks in hda_verb.c
[coreboot.git] / src / lib / jpeg.c
blobd084c1a7a5fd1cc78b250eae01b553861020063d
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 /*
4 * Provide a simple API around the Wuffs JPEG decoder.
5 */
7 #include <stdint.h>
9 #include "jpeg.h"
11 #define WUFFS_CONFIG__AVOID_CPU_ARCH
12 #define WUFFS_CONFIG__MODULES
13 #define WUFFS_CONFIG__MODULE__BASE
14 #define WUFFS_CONFIG__MODULE__JPEG
15 #define WUFFS_CONFIG__STATIC_FUNCTIONS
16 #define WUFFS_IMPLEMENTATION
17 #include "../vendorcode/wuffs/wuffs-v0.4.c"
19 /* ~16K is big enough to move this off the stack */
20 static wuffs_jpeg__decoder dec;
22 const char *jpeg_fetch_size(unsigned char *filedata, size_t filesize, unsigned int *width,
23 unsigned int *height)
25 if (!width || !height) {
26 return "invalid arg";
29 wuffs_base__status status = wuffs_jpeg__decoder__initialize(
30 &dec, sizeof(dec), WUFFS_VERSION, WUFFS_INITIALIZE__DEFAULT_OPTIONS);
31 if (status.repr) {
32 return status.repr;
35 wuffs_base__image_config imgcfg;
36 wuffs_base__io_buffer src = wuffs_base__ptr_u8__reader(filedata, filesize, true);
37 status = wuffs_jpeg__decoder__decode_image_config(&dec, &imgcfg, &src);
38 if (status.repr) {
39 return status.repr;
42 *width = wuffs_base__pixel_config__width(&imgcfg.pixcfg);
43 *height = wuffs_base__pixel_config__height(&imgcfg.pixcfg);
45 return NULL;
48 const char *jpeg_decode(unsigned char *filedata, size_t filesize, unsigned char *pic,
49 unsigned int width, unsigned int height, unsigned int bytes_per_line,
50 unsigned int depth)
52 if (!filedata || !pic) {
53 return "invalid arg";
55 /* Relatively arbitrary limit that shouldn't hurt anybody.
56 * 300M (10k*10k*3bytes/pixel) is already larger than our heap, so
57 * it's on the safe side.
58 * This avoids overflows when width or height are used for
59 * calculations in this function.
61 if ((width > 10000) || (height > 10000)) {
62 return "invalid arg";
65 uint32_t pixfmt;
66 switch (depth) {
67 case 16:
68 pixfmt = WUFFS_BASE__PIXEL_FORMAT__BGR_565;
69 break;
70 case 24:
71 pixfmt = WUFFS_BASE__PIXEL_FORMAT__BGR;
72 break;
73 case 32:
74 pixfmt = WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL;
75 break;
76 default:
77 return "invalid arg";
80 wuffs_base__status status = wuffs_jpeg__decoder__initialize(
81 &dec, sizeof(dec), WUFFS_VERSION, WUFFS_INITIALIZE__DEFAULT_OPTIONS);
82 if (status.repr) {
83 return status.repr;
86 /* Opting in to lower quality means that we can pass an empty slice as the
87 * "work buffer" argument to wuffs_jpeg__decoder__decode_frame below.
89 * Decoding progressive (not sequential) JPEGs would still require dynamic
90 * memory allocation (and the amount of work buffer required depends on the
91 * image dimensions), but we choose to just reject progressive JPEGs. It is
92 * simpler than sometimes calling malloc (which can fail, especially for
93 * large allocations) and free.
95 * More commentary about these quirks is at
96 * https://github.com/google/wuffs/blob/beaf45650085a16780b5f708b72daaeb1aa865c8/std/jpeg/decode_quirks.wuffs
98 wuffs_jpeg__decoder__set_quirk(
99 &dec, WUFFS_BASE__QUIRK_QUALITY,
100 WUFFS_BASE__QUIRK_QUALITY__VALUE__LOWER_QUALITY);
101 wuffs_jpeg__decoder__set_quirk(
102 &dec, WUFFS_JPEG__QUIRK_REJECT_PROGRESSIVE_JPEGS, 1);
104 wuffs_base__image_config imgcfg;
105 wuffs_base__io_buffer src = wuffs_base__ptr_u8__reader(filedata, filesize, true);
106 status = wuffs_jpeg__decoder__decode_image_config(&dec, &imgcfg, &src);
107 if (status.repr) {
108 return status.repr;
111 wuffs_base__pixel_config pixcfg;
112 wuffs_base__pixel_config__set(&pixcfg, pixfmt, 0, width, height);
114 wuffs_base__pixel_buffer pixbuf;
115 status = wuffs_base__pixel_buffer__set_interleaved(
116 &pixbuf, &pixcfg,
117 wuffs_base__make_table_u8(pic, width * (depth / 8), height, bytes_per_line),
118 wuffs_base__empty_slice_u8());
119 if (status.repr) {
120 return status.repr;
123 status = wuffs_jpeg__decoder__decode_frame(&dec, &pixbuf, &src,
124 WUFFS_BASE__PIXEL_BLEND__SRC,
125 wuffs_base__empty_slice_u8(), NULL);
126 return status.repr;