1*b2055c35SXin Li // Copyright 2012 Google Inc. All Rights Reserved.
2*b2055c35SXin Li //
3*b2055c35SXin Li // Use of this source code is governed by a BSD-style license
4*b2055c35SXin Li // that can be found in the COPYING file in the root of the source
5*b2055c35SXin Li // tree. An additional intellectual property rights grant can be found
6*b2055c35SXin Li // in the file PATENTS. All contributing project authors may
7*b2055c35SXin Li // be found in the AUTHORS file in the root of the source tree.
8*b2055c35SXin Li // -----------------------------------------------------------------------------
9*b2055c35SXin Li //
10*b2055c35SXin Li // JPEG decode.
11*b2055c35SXin Li
12*b2055c35SXin Li #include "./jpegdec.h"
13*b2055c35SXin Li
14*b2055c35SXin Li #ifdef HAVE_CONFIG_H
15*b2055c35SXin Li #include "webp/config.h"
16*b2055c35SXin Li #endif
17*b2055c35SXin Li
18*b2055c35SXin Li #include <stdio.h>
19*b2055c35SXin Li
20*b2055c35SXin Li #ifdef WEBP_HAVE_JPEG
21*b2055c35SXin Li #include <jpeglib.h>
22*b2055c35SXin Li #include <jerror.h>
23*b2055c35SXin Li #include <setjmp.h>
24*b2055c35SXin Li #include <stdlib.h>
25*b2055c35SXin Li #include <string.h>
26*b2055c35SXin Li
27*b2055c35SXin Li #include "webp/encode.h"
28*b2055c35SXin Li #include "./imageio_util.h"
29*b2055c35SXin Li #include "./metadata.h"
30*b2055c35SXin Li
31*b2055c35SXin Li // -----------------------------------------------------------------------------
32*b2055c35SXin Li // Metadata processing
33*b2055c35SXin Li
34*b2055c35SXin Li #ifndef JPEG_APP1
35*b2055c35SXin Li # define JPEG_APP1 (JPEG_APP0 + 1)
36*b2055c35SXin Li #endif
37*b2055c35SXin Li #ifndef JPEG_APP2
38*b2055c35SXin Li # define JPEG_APP2 (JPEG_APP0 + 2)
39*b2055c35SXin Li #endif
40*b2055c35SXin Li
41*b2055c35SXin Li typedef struct {
42*b2055c35SXin Li const uint8_t* data;
43*b2055c35SXin Li size_t data_length;
44*b2055c35SXin Li int seq; // this segment's sequence number [1, 255] for use in reassembly.
45*b2055c35SXin Li } ICCPSegment;
46*b2055c35SXin Li
SaveMetadataMarkers(j_decompress_ptr dinfo)47*b2055c35SXin Li static void SaveMetadataMarkers(j_decompress_ptr dinfo) {
48*b2055c35SXin Li const unsigned int max_marker_length = 0xffff;
49*b2055c35SXin Li jpeg_save_markers(dinfo, JPEG_APP1, max_marker_length); // Exif/XMP
50*b2055c35SXin Li jpeg_save_markers(dinfo, JPEG_APP2, max_marker_length); // ICC profile
51*b2055c35SXin Li }
52*b2055c35SXin Li
CompareICCPSegments(const void * a,const void * b)53*b2055c35SXin Li static int CompareICCPSegments(const void* a, const void* b) {
54*b2055c35SXin Li const ICCPSegment* s1 = (const ICCPSegment*)a;
55*b2055c35SXin Li const ICCPSegment* s2 = (const ICCPSegment*)b;
56*b2055c35SXin Li return s1->seq - s2->seq;
57*b2055c35SXin Li }
58*b2055c35SXin Li
59*b2055c35SXin Li // Extract ICC profile segments from the marker list in 'dinfo', reassembling
60*b2055c35SXin Li // and storing them in 'iccp'.
61*b2055c35SXin Li // Returns true on success and false for memory errors and corrupt profiles.
StoreICCP(j_decompress_ptr dinfo,MetadataPayload * const iccp)62*b2055c35SXin Li static int StoreICCP(j_decompress_ptr dinfo, MetadataPayload* const iccp) {
63*b2055c35SXin Li // ICC.1:2010-12 (4.3.0.0) Annex B.4 Embedding ICC Profiles in JPEG files
64*b2055c35SXin Li static const char kICCPSignature[] = "ICC_PROFILE";
65*b2055c35SXin Li static const size_t kICCPSignatureLength = 12; // signature includes '\0'
66*b2055c35SXin Li static const size_t kICCPSkipLength = 14; // signature + seq & count
67*b2055c35SXin Li int expected_count = 0;
68*b2055c35SXin Li int actual_count = 0;
69*b2055c35SXin Li int seq_max = 0;
70*b2055c35SXin Li size_t total_size = 0;
71*b2055c35SXin Li ICCPSegment iccp_segments[255];
72*b2055c35SXin Li jpeg_saved_marker_ptr marker;
73*b2055c35SXin Li
74*b2055c35SXin Li memset(iccp_segments, 0, sizeof(iccp_segments));
75*b2055c35SXin Li for (marker = dinfo->marker_list; marker != NULL; marker = marker->next) {
76*b2055c35SXin Li if (marker->marker == JPEG_APP2 &&
77*b2055c35SXin Li marker->data_length > kICCPSkipLength &&
78*b2055c35SXin Li !memcmp(marker->data, kICCPSignature, kICCPSignatureLength)) {
79*b2055c35SXin Li // ICC_PROFILE\0<seq><count>; 'seq' starts at 1.
80*b2055c35SXin Li const int seq = marker->data[kICCPSignatureLength];
81*b2055c35SXin Li const int count = marker->data[kICCPSignatureLength + 1];
82*b2055c35SXin Li const size_t segment_size = marker->data_length - kICCPSkipLength;
83*b2055c35SXin Li ICCPSegment* segment;
84*b2055c35SXin Li
85*b2055c35SXin Li if (segment_size == 0 || count == 0 || seq == 0) {
86*b2055c35SXin Li fprintf(stderr, "[ICCP] size (%d) / count (%d) / sequence number (%d)"
87*b2055c35SXin Li " cannot be 0!\n",
88*b2055c35SXin Li (int)segment_size, seq, count);
89*b2055c35SXin Li return 0;
90*b2055c35SXin Li }
91*b2055c35SXin Li
92*b2055c35SXin Li if (expected_count == 0) {
93*b2055c35SXin Li expected_count = count;
94*b2055c35SXin Li } else if (expected_count != count) {
95*b2055c35SXin Li fprintf(stderr, "[ICCP] Inconsistent segment count (%d / %d)!\n",
96*b2055c35SXin Li expected_count, count);
97*b2055c35SXin Li return 0;
98*b2055c35SXin Li }
99*b2055c35SXin Li
100*b2055c35SXin Li segment = iccp_segments + seq - 1;
101*b2055c35SXin Li if (segment->data_length != 0) {
102*b2055c35SXin Li fprintf(stderr, "[ICCP] Duplicate segment number (%d)!\n" , seq);
103*b2055c35SXin Li return 0;
104*b2055c35SXin Li }
105*b2055c35SXin Li
106*b2055c35SXin Li segment->data = marker->data + kICCPSkipLength;
107*b2055c35SXin Li segment->data_length = segment_size;
108*b2055c35SXin Li segment->seq = seq;
109*b2055c35SXin Li total_size += segment_size;
110*b2055c35SXin Li if (seq > seq_max) seq_max = seq;
111*b2055c35SXin Li ++actual_count;
112*b2055c35SXin Li }
113*b2055c35SXin Li }
114*b2055c35SXin Li
115*b2055c35SXin Li if (actual_count == 0) return 1;
116*b2055c35SXin Li if (seq_max != actual_count) {
117*b2055c35SXin Li fprintf(stderr, "[ICCP] Discontinuous segments, expected: %d actual: %d!\n",
118*b2055c35SXin Li actual_count, seq_max);
119*b2055c35SXin Li return 0;
120*b2055c35SXin Li }
121*b2055c35SXin Li if (expected_count != actual_count) {
122*b2055c35SXin Li fprintf(stderr, "[ICCP] Segment count: %d does not match expected: %d!\n",
123*b2055c35SXin Li actual_count, expected_count);
124*b2055c35SXin Li return 0;
125*b2055c35SXin Li }
126*b2055c35SXin Li
127*b2055c35SXin Li // The segments may appear out of order in the file, sort them based on
128*b2055c35SXin Li // sequence number before assembling the payload.
129*b2055c35SXin Li qsort(iccp_segments, actual_count, sizeof(*iccp_segments),
130*b2055c35SXin Li CompareICCPSegments);
131*b2055c35SXin Li
132*b2055c35SXin Li iccp->bytes = (uint8_t*)malloc(total_size);
133*b2055c35SXin Li if (iccp->bytes == NULL) return 0;
134*b2055c35SXin Li iccp->size = total_size;
135*b2055c35SXin Li
136*b2055c35SXin Li {
137*b2055c35SXin Li int i;
138*b2055c35SXin Li size_t offset = 0;
139*b2055c35SXin Li for (i = 0; i < seq_max; ++i) {
140*b2055c35SXin Li memcpy(iccp->bytes + offset,
141*b2055c35SXin Li iccp_segments[i].data, iccp_segments[i].data_length);
142*b2055c35SXin Li offset += iccp_segments[i].data_length;
143*b2055c35SXin Li }
144*b2055c35SXin Li }
145*b2055c35SXin Li return 1;
146*b2055c35SXin Li }
147*b2055c35SXin Li
148*b2055c35SXin Li // Returns true on success and false for memory errors and corrupt profiles.
149*b2055c35SXin Li // The caller must use MetadataFree() on 'metadata' in all cases.
ExtractMetadataFromJPEG(j_decompress_ptr dinfo,Metadata * const metadata)150*b2055c35SXin Li static int ExtractMetadataFromJPEG(j_decompress_ptr dinfo,
151*b2055c35SXin Li Metadata* const metadata) {
152*b2055c35SXin Li static const struct {
153*b2055c35SXin Li int marker;
154*b2055c35SXin Li const char* signature;
155*b2055c35SXin Li size_t signature_length;
156*b2055c35SXin Li size_t storage_offset;
157*b2055c35SXin Li } kJPEGMetadataMap[] = {
158*b2055c35SXin Li // Exif 2.2 Section 4.7.2 Interoperability Structure of APP1 ...
159*b2055c35SXin Li { JPEG_APP1, "Exif\0", 6, METADATA_OFFSET(exif) },
160*b2055c35SXin Li // XMP Specification Part 3 Section 3 Embedding XMP Metadata ... #JPEG
161*b2055c35SXin Li // TODO(jzern) Add support for 'ExtendedXMP'
162*b2055c35SXin Li { JPEG_APP1, "http://ns.adobe.com/xap/1.0/", 29, METADATA_OFFSET(xmp) },
163*b2055c35SXin Li { 0, NULL, 0, 0 },
164*b2055c35SXin Li };
165*b2055c35SXin Li jpeg_saved_marker_ptr marker;
166*b2055c35SXin Li // Treat ICC profiles separately as they may be segmented and out of order.
167*b2055c35SXin Li if (!StoreICCP(dinfo, &metadata->iccp)) return 0;
168*b2055c35SXin Li
169*b2055c35SXin Li for (marker = dinfo->marker_list; marker != NULL; marker = marker->next) {
170*b2055c35SXin Li int i;
171*b2055c35SXin Li for (i = 0; kJPEGMetadataMap[i].marker != 0; ++i) {
172*b2055c35SXin Li if (marker->marker == kJPEGMetadataMap[i].marker &&
173*b2055c35SXin Li marker->data_length > kJPEGMetadataMap[i].signature_length &&
174*b2055c35SXin Li !memcmp(marker->data, kJPEGMetadataMap[i].signature,
175*b2055c35SXin Li kJPEGMetadataMap[i].signature_length)) {
176*b2055c35SXin Li MetadataPayload* const payload =
177*b2055c35SXin Li (MetadataPayload*)((uint8_t*)metadata +
178*b2055c35SXin Li kJPEGMetadataMap[i].storage_offset);
179*b2055c35SXin Li
180*b2055c35SXin Li if (payload->bytes == NULL) {
181*b2055c35SXin Li const char* marker_data = (const char*)marker->data +
182*b2055c35SXin Li kJPEGMetadataMap[i].signature_length;
183*b2055c35SXin Li const size_t marker_data_length =
184*b2055c35SXin Li marker->data_length - kJPEGMetadataMap[i].signature_length;
185*b2055c35SXin Li if (!MetadataCopy(marker_data, marker_data_length, payload)) return 0;
186*b2055c35SXin Li } else {
187*b2055c35SXin Li fprintf(stderr, "Ignoring additional '%s' marker\n",
188*b2055c35SXin Li kJPEGMetadataMap[i].signature);
189*b2055c35SXin Li }
190*b2055c35SXin Li }
191*b2055c35SXin Li }
192*b2055c35SXin Li }
193*b2055c35SXin Li return 1;
194*b2055c35SXin Li }
195*b2055c35SXin Li
196*b2055c35SXin Li #undef JPEG_APP1
197*b2055c35SXin Li #undef JPEG_APP2
198*b2055c35SXin Li
199*b2055c35SXin Li // -----------------------------------------------------------------------------
200*b2055c35SXin Li // JPEG decoding
201*b2055c35SXin Li
202*b2055c35SXin Li struct my_error_mgr {
203*b2055c35SXin Li struct jpeg_error_mgr pub;
204*b2055c35SXin Li jmp_buf setjmp_buffer;
205*b2055c35SXin Li };
206*b2055c35SXin Li
my_error_exit(j_common_ptr dinfo)207*b2055c35SXin Li static void my_error_exit(j_common_ptr dinfo) {
208*b2055c35SXin Li struct my_error_mgr* myerr = (struct my_error_mgr*)dinfo->err;
209*b2055c35SXin Li fprintf(stderr, "libjpeg error: ");
210*b2055c35SXin Li dinfo->err->output_message(dinfo);
211*b2055c35SXin Li longjmp(myerr->setjmp_buffer, 1);
212*b2055c35SXin Li }
213*b2055c35SXin Li
214*b2055c35SXin Li typedef struct {
215*b2055c35SXin Li struct jpeg_source_mgr pub;
216*b2055c35SXin Li const uint8_t* data;
217*b2055c35SXin Li size_t data_size;
218*b2055c35SXin Li } JPEGReadContext;
219*b2055c35SXin Li
ContextInit(j_decompress_ptr cinfo)220*b2055c35SXin Li static void ContextInit(j_decompress_ptr cinfo) {
221*b2055c35SXin Li JPEGReadContext* const ctx = (JPEGReadContext*)cinfo->src;
222*b2055c35SXin Li ctx->pub.next_input_byte = ctx->data;
223*b2055c35SXin Li ctx->pub.bytes_in_buffer = ctx->data_size;
224*b2055c35SXin Li }
225*b2055c35SXin Li
ContextFill(j_decompress_ptr cinfo)226*b2055c35SXin Li static boolean ContextFill(j_decompress_ptr cinfo) {
227*b2055c35SXin Li // we shouldn't get here.
228*b2055c35SXin Li ERREXIT(cinfo, JERR_FILE_READ);
229*b2055c35SXin Li return FALSE;
230*b2055c35SXin Li }
231*b2055c35SXin Li
ContextSkip(j_decompress_ptr cinfo,long jump_size)232*b2055c35SXin Li static void ContextSkip(j_decompress_ptr cinfo, long jump_size) {
233*b2055c35SXin Li JPEGReadContext* const ctx = (JPEGReadContext*)cinfo->src;
234*b2055c35SXin Li size_t jump = (size_t)jump_size;
235*b2055c35SXin Li if (jump > ctx->pub.bytes_in_buffer) { // Don't overflow the buffer.
236*b2055c35SXin Li jump = ctx->pub.bytes_in_buffer;
237*b2055c35SXin Li }
238*b2055c35SXin Li ctx->pub.bytes_in_buffer -= jump;
239*b2055c35SXin Li ctx->pub.next_input_byte += jump;
240*b2055c35SXin Li }
241*b2055c35SXin Li
ContextTerm(j_decompress_ptr cinfo)242*b2055c35SXin Li static void ContextTerm(j_decompress_ptr cinfo) {
243*b2055c35SXin Li (void)cinfo;
244*b2055c35SXin Li }
245*b2055c35SXin Li
ContextSetup(volatile struct jpeg_decompress_struct * const cinfo,JPEGReadContext * const ctx)246*b2055c35SXin Li static void ContextSetup(volatile struct jpeg_decompress_struct* const cinfo,
247*b2055c35SXin Li JPEGReadContext* const ctx) {
248*b2055c35SXin Li cinfo->src = (struct jpeg_source_mgr*)ctx;
249*b2055c35SXin Li ctx->pub.init_source = ContextInit;
250*b2055c35SXin Li ctx->pub.fill_input_buffer = ContextFill;
251*b2055c35SXin Li ctx->pub.skip_input_data = ContextSkip;
252*b2055c35SXin Li ctx->pub.resync_to_restart = jpeg_resync_to_restart;
253*b2055c35SXin Li ctx->pub.term_source = ContextTerm;
254*b2055c35SXin Li ctx->pub.bytes_in_buffer = 0;
255*b2055c35SXin Li ctx->pub.next_input_byte = NULL;
256*b2055c35SXin Li }
257*b2055c35SXin Li
ReadJPEG(const uint8_t * const data,size_t data_size,WebPPicture * const pic,int keep_alpha,Metadata * const metadata)258*b2055c35SXin Li int ReadJPEG(const uint8_t* const data, size_t data_size,
259*b2055c35SXin Li WebPPicture* const pic, int keep_alpha,
260*b2055c35SXin Li Metadata* const metadata) {
261*b2055c35SXin Li volatile int ok = 0;
262*b2055c35SXin Li int width, height;
263*b2055c35SXin Li int64_t stride;
264*b2055c35SXin Li volatile struct jpeg_decompress_struct dinfo;
265*b2055c35SXin Li struct my_error_mgr jerr;
266*b2055c35SXin Li uint8_t* volatile rgb = NULL;
267*b2055c35SXin Li JSAMPROW buffer[1];
268*b2055c35SXin Li JPEGReadContext ctx;
269*b2055c35SXin Li
270*b2055c35SXin Li if (data == NULL || data_size == 0 || pic == NULL) return 0;
271*b2055c35SXin Li
272*b2055c35SXin Li (void)keep_alpha;
273*b2055c35SXin Li memset(&ctx, 0, sizeof(ctx));
274*b2055c35SXin Li ctx.data = data;
275*b2055c35SXin Li ctx.data_size = data_size;
276*b2055c35SXin Li
277*b2055c35SXin Li memset((j_decompress_ptr)&dinfo, 0, sizeof(dinfo)); // for setjmp safety
278*b2055c35SXin Li dinfo.err = jpeg_std_error(&jerr.pub);
279*b2055c35SXin Li jerr.pub.error_exit = my_error_exit;
280*b2055c35SXin Li
281*b2055c35SXin Li if (setjmp(jerr.setjmp_buffer)) {
282*b2055c35SXin Li Error:
283*b2055c35SXin Li MetadataFree(metadata);
284*b2055c35SXin Li jpeg_destroy_decompress((j_decompress_ptr)&dinfo);
285*b2055c35SXin Li goto End;
286*b2055c35SXin Li }
287*b2055c35SXin Li
288*b2055c35SXin Li jpeg_create_decompress((j_decompress_ptr)&dinfo);
289*b2055c35SXin Li ContextSetup(&dinfo, &ctx);
290*b2055c35SXin Li if (metadata != NULL) SaveMetadataMarkers((j_decompress_ptr)&dinfo);
291*b2055c35SXin Li jpeg_read_header((j_decompress_ptr)&dinfo, TRUE);
292*b2055c35SXin Li
293*b2055c35SXin Li dinfo.out_color_space = JCS_RGB;
294*b2055c35SXin Li dinfo.do_fancy_upsampling = TRUE;
295*b2055c35SXin Li
296*b2055c35SXin Li jpeg_start_decompress((j_decompress_ptr)&dinfo);
297*b2055c35SXin Li
298*b2055c35SXin Li if (dinfo.output_components != 3) {
299*b2055c35SXin Li goto Error;
300*b2055c35SXin Li }
301*b2055c35SXin Li
302*b2055c35SXin Li width = dinfo.output_width;
303*b2055c35SXin Li height = dinfo.output_height;
304*b2055c35SXin Li stride = (int64_t)dinfo.output_width * dinfo.output_components * sizeof(*rgb);
305*b2055c35SXin Li
306*b2055c35SXin Li if (stride != (int)stride ||
307*b2055c35SXin Li !ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
308*b2055c35SXin Li goto Error;
309*b2055c35SXin Li }
310*b2055c35SXin Li
311*b2055c35SXin Li rgb = (uint8_t*)malloc((size_t)stride * height);
312*b2055c35SXin Li if (rgb == NULL) {
313*b2055c35SXin Li goto Error;
314*b2055c35SXin Li }
315*b2055c35SXin Li buffer[0] = (JSAMPLE*)rgb;
316*b2055c35SXin Li
317*b2055c35SXin Li while (dinfo.output_scanline < dinfo.output_height) {
318*b2055c35SXin Li if (jpeg_read_scanlines((j_decompress_ptr)&dinfo, buffer, 1) != 1) {
319*b2055c35SXin Li goto Error;
320*b2055c35SXin Li }
321*b2055c35SXin Li buffer[0] += stride;
322*b2055c35SXin Li }
323*b2055c35SXin Li
324*b2055c35SXin Li if (metadata != NULL) {
325*b2055c35SXin Li ok = ExtractMetadataFromJPEG((j_decompress_ptr)&dinfo, metadata);
326*b2055c35SXin Li if (!ok) {
327*b2055c35SXin Li fprintf(stderr, "Error extracting JPEG metadata!\n");
328*b2055c35SXin Li goto Error;
329*b2055c35SXin Li }
330*b2055c35SXin Li }
331*b2055c35SXin Li
332*b2055c35SXin Li jpeg_finish_decompress((j_decompress_ptr)&dinfo);
333*b2055c35SXin Li jpeg_destroy_decompress((j_decompress_ptr)&dinfo);
334*b2055c35SXin Li
335*b2055c35SXin Li // WebP conversion.
336*b2055c35SXin Li pic->width = width;
337*b2055c35SXin Li pic->height = height;
338*b2055c35SXin Li ok = WebPPictureImportRGB(pic, rgb, (int)stride);
339*b2055c35SXin Li if (!ok) {
340*b2055c35SXin Li pic->width = 0; // WebPPictureImportRGB() barely touches 'pic' on failure.
341*b2055c35SXin Li pic->height = 0; // Just reset dimensions but keep any 'custom_ptr' etc.
342*b2055c35SXin Li MetadataFree(metadata); // In case the caller forgets to free it on error.
343*b2055c35SXin Li }
344*b2055c35SXin Li
345*b2055c35SXin Li End:
346*b2055c35SXin Li free(rgb);
347*b2055c35SXin Li return ok;
348*b2055c35SXin Li }
349*b2055c35SXin Li #else // !WEBP_HAVE_JPEG
ReadJPEG(const uint8_t * const data,size_t data_size,struct WebPPicture * const pic,int keep_alpha,struct Metadata * const metadata)350*b2055c35SXin Li int ReadJPEG(const uint8_t* const data, size_t data_size,
351*b2055c35SXin Li struct WebPPicture* const pic, int keep_alpha,
352*b2055c35SXin Li struct Metadata* const metadata) {
353*b2055c35SXin Li (void)data;
354*b2055c35SXin Li (void)data_size;
355*b2055c35SXin Li (void)pic;
356*b2055c35SXin Li (void)keep_alpha;
357*b2055c35SXin Li (void)metadata;
358*b2055c35SXin Li fprintf(stderr, "JPEG support not compiled. Please install the libjpeg "
359*b2055c35SXin Li "development package before building.\n");
360*b2055c35SXin Li return 0;
361*b2055c35SXin Li }
362*b2055c35SXin Li #endif // WEBP_HAVE_JPEG
363*b2055c35SXin Li
364*b2055c35SXin Li // -----------------------------------------------------------------------------
365