blob: 242cf0ca8eeee93259b4d955f6eb13e6cf881906 [file] [log] [blame]
Angel Pons118a9c72020-04-02 23:48:34 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauerd650e992010-02-22 04:33:13 +00002
3/*
Patrick Georgi1d029b42023-10-06 20:19:15 +02004 * 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.
Stefan Reinauerd650e992010-02-22 04:33:13 +00007 */
8
Patrick Georgi1d029b42023-10-06 20:19:15 +02009#include <stdint.h>
10
Stefan Reinauerd650e992010-02-22 04:33:13 +000011#include "jpeg.h"
Stefan Reinauerd650e992010-02-22 04:33:13 +000012
Patrick Georgi1d029b42023-10-06 20:19:15 +020013#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"
Stefan Reinauerd650e992010-02-22 04:33:13 +000020
Patrick Georgi1d029b42023-10-06 20:19:15 +020021/* ~16K is big enough to move this off the stack */
22static wuffs_jpeg__decoder dec;
Stefan Reinauerd650e992010-02-22 04:33:13 +000023
Patrick Georgi1d029b42023-10-06 20:19:15 +020024int jpeg_fetch_size(unsigned char *filedata, size_t filesize, unsigned int *width,
25 unsigned int *height)
Stefan Reinauerd650e992010-02-22 04:33:13 +000026{
Patrick Georgi1d029b42023-10-06 20:19:15 +020027 if (!width || !height) {
28 return JPEG_DECODE_FAILED;
Stefan Reinauerd650e992010-02-22 04:33:13 +000029 }
30
Patrick Georgi1d029b42023-10-06 20:19:15 +020031 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;
Stefan Reinauerd650e992010-02-22 04:33:13 +000035 }
36
Patrick Georgi1d029b42023-10-06 20:19:15 +020037 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);
Stefan Reinauerd650e992010-02-22 04:33:13 +000046
47 return 0;
48}
49
Patrick Georgi1d029b42023-10-06 20:19:15 +020050int 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)
Stefan Reinauerd650e992010-02-22 04:33:13 +000053{
Patrick Georgi1d029b42023-10-06 20:19:15 +020054 if (!filedata || !pic) {
55 return JPEG_DECODE_FAILED;
Stefan Reinauerd650e992010-02-22 04:33:13 +000056 }
Patrick Georgi1d029b42023-10-06 20:19:15 +020057 /* 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;
Stefan Reinauerd650e992010-02-22 04:33:13 +000065 }
Stefan Reinauerd650e992010-02-22 04:33:13 +000066
Patrick Georgi1d029b42023-10-06 20:19:15 +020067 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;
Stefan Reinauerd650e992010-02-22 04:33:13 +000080 }
Patrick Georgi1d029b42023-10-06 20:19:15 +020081
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;
Stefan Reinauerd650e992010-02-22 04:33:13 +000086 }
Stefan Reinauerd650e992010-02-22 04:33:13 +000087
Patrick Georgi1d029b42023-10-06 20:19:15 +020088 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;
Stefan Reinauerd650e992010-02-22 04:33:13 +000093 }
Stefan Reinauerd650e992010-02-22 04:33:13 +000094
Patrick Georgi1d029b42023-10-06 20:19:15 +020095 wuffs_base__pixel_config pixcfg;
96 wuffs_base__pixel_config__set(&pixcfg, pixfmt, 0, width, height);
Stefan Reinauerd650e992010-02-22 04:33:13 +000097
Patrick Georgi1d029b42023-10-06 20:19:15 +020098 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;
Stefan Reinauerd650e992010-02-22 04:33:13 +0000105 }
Stefan Reinauerd650e992010-02-22 04:33:13 +0000106
Patrick Georgi1d029b42023-10-06 20:19:15 +0200107 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;
Stefan Reinauerd650e992010-02-22 04:33:13 +0000111 }
Patrick Georgi1d029b42023-10-06 20:19:15 +0200112
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;
Stefan Reinauerd650e992010-02-22 04:33:13 +0000122 }
Stefan Reinauerd650e992010-02-22 04:33:13 +0000123
Patrick Georgi1d029b42023-10-06 20:19:15 +0200124 return 0;
Stefan Reinauerd650e992010-02-22 04:33:13 +0000125}