report_option(WITH_MEM_SRCDST "In-memory source/destination managers")
endif()
-set(SO_AGE 1)
+set(SO_AGE 2)
if(WITH_MEM_SRCDST)
- set(SO_AGE 2)
+ set(SO_AGE 3)
endif()
if(WITH_JPEG8)
###############################################################################
set(JPEG_SOURCES jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c
- jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c jcphuff.c
- jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c jdatadst.c jdatasrc.c
- jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c
- jdmaster.c jdmerge.c jdphuff.c jdpostct.c jdsample.c jdtrans.c jerror.c
- jfdctflt.c jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c
- jquant1.c jquant2.c jutils.c jmemmgr.c jmemnobs.c)
+ jcicc.c jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c
+ jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c jdatadst.c
+ jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c jdicc.c jdinput.c
+ jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c jdpostct.c jdsample.c
+ jdtrans.c jerror.c jfdctflt.c jfdctfst.c jfdctint.c jidctflt.c jidctfst.c
+ jidctint.c jidctred.c jquant1.c jquant2.c jutils.c jmemmgr.c jmemnobs.c)
if(WITH_ARITH_ENC OR WITH_ARITH_DEC)
set(JPEG_SOURCES ${JPEG_SOURCES} jaricom.c)
if(WITH_12BIT)
set(TESTORIG testorig12.jpg)
- set(MD5_JPEG_RGB_ISLOW 9620f424569594bb9242b48498ad801f)
+ set(MD5_JPEG_RGB_ISLOW 9d7369207c520d37f2c1cbfcb82b2964)
+ set(MD5_JPEG_RGB_ISLOW2 a00bd20d8ae49684640ef7177d2e0b64)
set(MD5_PPM_RGB_ISLOW f3301d2219783b8b3d942b7239fa50c0)
set(MD5_JPEG_422_IFAST_OPT 7322e3bd2f127f7de4b40d4480ce60e4)
set(MD5_PPM_422_IFAST 79807fa552899e66a04708f533e16950)
set(MD5_JPEG_CROP cdb35ff4b4519392690ea040c56ea99c)
else()
set(TESTORIG testorig.jpg)
- set(MD5_JPEG_RGB_ISLOW 768e970dd57b340ff1b83c9d3d47c77b)
+ set(MD5_JPEG_RGB_ISLOW 1d44a406f61da743b5fd31c0a9abdca3)
+ set(MD5_JPEG_RGB_ISLOW2 31d121e57b6c2934c890a7fc7763bcd4)
set(MD5_PPM_RGB_ISLOW 00a257f5393fef8821f2b88ac7421291)
set(MD5_BMP_RGB_ISLOW_565 f07d2e75073e4bb10f6c6f4d36e2e3be)
set(MD5_BMP_RGB_ISLOW_565D 4cfa0928ef3e6bb626d7728c924cfda4)
endmacro()
# CC: null SAMP: fullsize FDCT: islow ENT: huff
- add_bittest(cjpeg rgb-islow "-rgb;-dct;int"
+ add_bittest(cjpeg rgb-islow "-rgb;-dct;int;-icc;${TESTIMAGES}/test1.icc"
testout_rgb_islow.jpg ${TESTIMAGES}/testorig.ppm
${MD5_JPEG_RGB_ISLOW})
# CC: null SAMP: fullsize IDCT: islow ENT: huff
- add_bittest(djpeg rgb-islow "-dct;int;-ppm"
+ add_bittest(djpeg rgb-islow "-dct;int;-ppm;-icc;testout_rgb_islow.icc"
testout_rgb_islow.ppm testout_rgb_islow.jpg
${MD5_PPM_RGB_ISLOW} cjpeg-${libtype}-rgb-islow)
+ add_test(djpeg-${libtype}-rgb-islow-icc-cmp
+ ${MD5CMP} b06a39d730129122e85c1363ed1bbc9e testout_rgb_islow.icc)
+
+ add_bittest(jpegtran icc "-copy;all;-icc;${TESTIMAGES}/test2.icc"
+ testout_rgb_islow2.jpg testout_rgb_islow.jpg ${MD5_JPEG_RGB_ISLOW2})
+
if(NOT WITH_12BIT)
# CC: RGB->RGB565 SAMP: fullsize IDCT: islow ENT: huff
add_bittest(djpeg rgb-islow-565 "-dct;int;-rgb565;-dither;none;-bmp"
Extensive testing was conducted to ensure that all features provided by the
autotools-based build system are provided by the new build system.
+3. The libjpeg API in this version of libjpeg-turbo now includes two additional
+functions, `jpeg_read_icc_profile()` and `jpeg_write_icc_profile()`, that can
+be used to extract ICC profile data from a JPEG file while decompressing or to
+embed ICC profile data in a JPEG file while compressing or transforming. This
+eliminates the need for downstream projects, such as color management libraries
+and browsers, to include their own glueware for accomplishing this.
+
1.5.2
=====
-.TH CJPEG 1 "17 February 2016"
+.TH CJPEG 1 "19 January 2017"
.SH NAME
cjpeg \- compress an image file to a JPEG file
.SH SYNOPSIS
roundoff behavior, whereas the integer methods should give the same results on
all machines.
.TP
+.BI \-icc " file"
+Embed ICC color management profile contained in the specified file.
+.TP
.BI \-restart " N"
Emit a JPEG restart marker every N MCU rows, or every N MCU blocks if "B" is
attached to the number.
#include "jversion.h" /* for version message */
#include "jconfigint.h"
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
+extern void *malloc (size_t size);
+extern void free (void *ptr);
+#endif
+
#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
#ifdef __MWERKS__
#include <SIOUX.h> /* Metrowerks needs this */
static const char *progname; /* program name for error messages */
+static char *icc_filename; /* for -icc switch */
static char *outfilename; /* for -outfile switch */
boolean memdst; /* for -memdst switch */
fprintf(stderr, " -dct float Use floating-point DCT method%s\n",
(JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
#endif
+ fprintf(stderr, " -icc FILE Embed ICC profile contained in FILE\n");
fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n");
#ifdef INPUT_SMOOTHING_SUPPORTED
fprintf(stderr, " -smooth N Smooth dithered input (N=1..100 is strength)\n");
force_baseline = FALSE; /* by default, allow 16-bit quantizers */
simple_progressive = FALSE;
is_targa = FALSE;
+ icc_filename = NULL;
outfilename = NULL;
memdst = FALSE;
cinfo->err->trace_level = 0;
/* Force an RGB JPEG file to be generated. */
jpeg_set_colorspace(cinfo, JCS_RGB);
+ } else if (keymatch(arg, "icc", 1)) {
+ /* Set ICC filename. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ icc_filename = argv[argn];
+
} else if (keymatch(arg, "maxmemory", 3)) {
/* Maximum memory in Kb (or Mb with 'm'). */
long lval;
int file_index;
cjpeg_source_ptr src_mgr;
FILE *input_file;
+ FILE *icc_file;
+ JOCTET *icc_profile = NULL;
+ long icc_len = 0;
FILE *output_file = NULL;
unsigned char *outbuffer = NULL;
unsigned long outsize = 0;
output_file = write_stdout();
}
+ if (icc_filename != NULL) {
+ if ((icc_file = fopen(icc_filename, READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, icc_filename);
+ exit(EXIT_FAILURE);
+ }
+ if (fseek(icc_file, 0, SEEK_END) < 0 ||
+ (icc_len = ftell(icc_file)) < 1 ||
+ fseek(icc_file, 0, SEEK_SET) < 0) {
+ fprintf(stderr, "%s: can't determine size of %s\n", progname,
+ icc_filename);
+ exit(EXIT_FAILURE);
+ }
+ if ((icc_profile = (JOCTET *)malloc(icc_len)) == NULL) {
+ fprintf(stderr, "%s: can't allocate memory for ICC profile\n", progname);
+ fclose(icc_file);
+ exit(EXIT_FAILURE);
+ }
+ if (fread(icc_profile, icc_len, 1, icc_file) < 1) {
+ fprintf(stderr, "%s: can't read ICC profile from %s\n", progname,
+ icc_filename);
+ free(icc_profile);
+ fclose(icc_file);
+ exit(EXIT_FAILURE);
+ }
+ fclose(icc_file);
+ }
+
#ifdef PROGRESS_REPORT
start_progress_monitor((j_common_ptr) &cinfo, &progress);
#endif
/* Start compressor */
jpeg_start_compress(&cinfo, TRUE);
+ if (icc_profile != NULL)
+ jpeg_write_icc_profile(&cinfo, icc_profile, (unsigned int)icc_len);
+
/* Process data */
while (cinfo.next_scanline < cinfo.image_height) {
num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr);
free(outbuffer);
}
+ if (icc_profile != NULL)
+ free(icc_profile);
+
/* All done. */
exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
return 0; /* suppress no-return-value warnings */
-.TH DJPEG 1 "18 February 2016"
+.TH DJPEG 1 "19 January 2017"
.SH NAME
djpeg \- decompress a JPEG file to an image file
.SH SYNOPSIS
.B \-onepass
mode.
.TP
+.BI \-icc " file"
+Extract ICC color management profile to the specified file.
+.TP
.BI \-map " file"
Quantize to the colors used in the specified image file. This is useful for
producing multiple files with identical color maps, or for forcing a
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 2013 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010-2011, 2013-2016, D. R. Commander.
+ * Copyright (C) 2010-2011, 2013-2017, D. R. Commander.
* Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
#include "jconfigint.h"
#include "wrppm.h"
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare free() */
+extern void free (void *ptr);
+#endif
+
#include <ctype.h> /* to declare isprint() */
#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
static const char *progname; /* program name for error messages */
+static char *icc_filename; /* for -icc switch */
static char *outfilename; /* for -outfile switch */
boolean memsrc; /* for -memsrc switch */
boolean skip, crop;
fprintf(stderr, " -dither fs Use F-S dithering (default)\n");
fprintf(stderr, " -dither none Don't use dithering in quantization\n");
fprintf(stderr, " -dither ordered Use ordered dither (medium speed, quality)\n");
+ fprintf(stderr, " -icc FILE Extract ICC profile to FILE\n");
#ifdef QUANT_2PASS_SUPPORTED
fprintf(stderr, " -map FILE Map to colors used in named image file\n");
#endif
/* Set up default JPEG parameters. */
requested_fmt = DEFAULT_FMT; /* set default output file format */
+ icc_filename = NULL;
outfilename = NULL;
memsrc = FALSE;
skip = FALSE;
/* Force RGB565 output. */
cinfo->out_color_space = JCS_RGB565;
+ } else if (keymatch(arg, "icc", 1)) {
+ /* Set ICC filename. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ icc_filename = argv[argn];
+ jpeg_save_markers(cinfo, JPEG_APP0 + 2, 0xFFFF);
+
} else if (keymatch(arg, "map", 3)) {
/* Quantize to a color map taken from an input file. */
if (++argn >= argc) /* advance to next argument */
progress.pub.completed_passes = progress.pub.total_passes;
#endif
+ if (icc_filename != NULL) {
+ FILE *icc_file;
+ JOCTET *icc_profile;
+ unsigned int icc_len;
+
+ if ((icc_file = fopen(icc_filename, WRITE_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, icc_filename);
+ exit(EXIT_FAILURE);
+ }
+ if (jpeg_read_icc_profile(&cinfo, &icc_profile, &icc_len)) {
+ if (fwrite(icc_profile, icc_len, 1, icc_file) < 1) {
+ fprintf(stderr, "%s: can't read ICC profile from %s\n", progname,
+ icc_filename);
+ free(icc_profile);
+ fclose(icc_file);
+ exit(EXIT_FAILURE);
+ }
+ free(icc_profile);
+ fclose(icc_file);
+ } else if (cinfo.err->msg_code != JWRN_BOGUS_ICC)
+ fprintf(stderr, "%s: no ICC profile data in JPEG file\n", progname);
+ }
+
/* Finish decompression and release memory.
* I must do it in this order because output module has allocated memory
* of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
--- /dev/null
+/*
+ * jcicc.c
+ *
+ * Copyright (C) 1997-1998, Thomas G. Lane, Todd Newman.
+ * Copyright (C) 2017, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file provides code to write International Color Consortium (ICC) device
+ * profiles embedded in JFIF JPEG image files. The ICC has defined a standard
+ * for including such data in JPEG "APP2" markers. The code given here does
+ * not know anything about the internal structure of the ICC profile data; it
+ * just knows how to embed the profile data in a JPEG file while writing it.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h"
+
+
+/*
+ * Since an ICC profile can be larger than the maximum size of a JPEG marker
+ * (64K), we need provisions to split it into multiple markers. The format
+ * defined by the ICC specifies one or more APP2 markers containing the
+ * following data:
+ * Identifying string ASCII "ICC_PROFILE\0" (12 bytes)
+ * Marker sequence number 1 for first APP2, 2 for next, etc (1 byte)
+ * Number of markers Total number of APP2's used (1 byte)
+ * Profile data (remainder of APP2 data)
+ * Decoders should use the marker sequence numbers to reassemble the profile,
+ * rather than assuming that the APP2 markers appear in the correct sequence.
+ */
+
+#define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */
+#define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
+#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */
+#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
+
+
+/*
+ * This routine writes the given ICC profile data into a JPEG file. It *must*
+ * be called AFTER calling jpeg_start_compress() and BEFORE the first call to
+ * jpeg_write_scanlines(). (This ordering ensures that the APP2 marker(s) will
+ * appear after the SOI and JFIF or Adobe markers, but before all else.)
+ */
+
+GLOBAL(void)
+jpeg_write_icc_profile (j_compress_ptr cinfo, const JOCTET *icc_data_ptr,
+ unsigned int icc_data_len)
+{
+ unsigned int num_markers; /* total number of markers we'll write */
+ int cur_marker = 1; /* per spec, counting starts at 1 */
+ unsigned int length; /* number of bytes to write in this marker */
+
+ if (icc_data_ptr == NULL || icc_data_len == 0)
+ ERREXIT(cinfo, JERR_BUFFER_SIZE);
+ if (cinfo->global_state < CSTATE_SCANNING)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* Calculate the number of markers we'll need, rounding up of course */
+ num_markers = icc_data_len / MAX_DATA_BYTES_IN_MARKER;
+ if (num_markers * MAX_DATA_BYTES_IN_MARKER != icc_data_len)
+ num_markers++;
+
+ while (icc_data_len > 0) {
+ /* length of profile to put in this marker */
+ length = icc_data_len;
+ if (length > MAX_DATA_BYTES_IN_MARKER)
+ length = MAX_DATA_BYTES_IN_MARKER;
+ icc_data_len -= length;
+
+ /* Write the JPEG marker header (APP2 code and marker length) */
+ jpeg_write_m_header(cinfo, ICC_MARKER,
+ (unsigned int) (length + ICC_OVERHEAD_LEN));
+
+ /* Write the marker identifying string "ICC_PROFILE" (null-terminated). We
+ * code it in this less-than-transparent way so that the code works even if
+ * the local character set is not ASCII.
+ */
+ jpeg_write_m_byte(cinfo, 0x49);
+ jpeg_write_m_byte(cinfo, 0x43);
+ jpeg_write_m_byte(cinfo, 0x43);
+ jpeg_write_m_byte(cinfo, 0x5F);
+ jpeg_write_m_byte(cinfo, 0x50);
+ jpeg_write_m_byte(cinfo, 0x52);
+ jpeg_write_m_byte(cinfo, 0x4F);
+ jpeg_write_m_byte(cinfo, 0x46);
+ jpeg_write_m_byte(cinfo, 0x49);
+ jpeg_write_m_byte(cinfo, 0x4C);
+ jpeg_write_m_byte(cinfo, 0x45);
+ jpeg_write_m_byte(cinfo, 0x0);
+
+ /* Add the sequencing info */
+ jpeg_write_m_byte(cinfo, cur_marker);
+ jpeg_write_m_byte(cinfo, (int) num_markers);
+
+ /* Add the profile data */
+ while (length--) {
+ jpeg_write_m_byte(cinfo, *icc_data_ptr);
+ icc_data_ptr++;
+ }
+ cur_marker++;
+ }
+}
--- /dev/null
+/*
+ * jdicc.c
+ *
+ * Copyright (C) 1997-1998, Thomas G. Lane, Todd Newman.
+ * Copyright (C) 2017, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file provides code to read International Color Consortium (ICC) device
+ * profiles embedded in JFIF JPEG image files. The ICC has defined a standard
+ * for including such data in JPEG "APP2" markers. The code given here does
+ * not know anything about the internal structure of the ICC profile data; it
+ * just knows how to get the profile data from a JPEG file while reading it.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h"
+
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc() */
+extern void *malloc (size_t size);
+#endif
+
+
+#define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */
+#define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
+
+
+/*
+ * Handy subroutine to test whether a saved marker is an ICC profile marker.
+ */
+
+LOCAL(boolean)
+marker_is_icc (jpeg_saved_marker_ptr marker)
+{
+ return
+ marker->marker == ICC_MARKER &&
+ marker->data_length >= ICC_OVERHEAD_LEN &&
+ /* verify the identifying string */
+ GETJOCTET(marker->data[0]) == 0x49 &&
+ GETJOCTET(marker->data[1]) == 0x43 &&
+ GETJOCTET(marker->data[2]) == 0x43 &&
+ GETJOCTET(marker->data[3]) == 0x5F &&
+ GETJOCTET(marker->data[4]) == 0x50 &&
+ GETJOCTET(marker->data[5]) == 0x52 &&
+ GETJOCTET(marker->data[6]) == 0x4F &&
+ GETJOCTET(marker->data[7]) == 0x46 &&
+ GETJOCTET(marker->data[8]) == 0x49 &&
+ GETJOCTET(marker->data[9]) == 0x4C &&
+ GETJOCTET(marker->data[10]) == 0x45 &&
+ GETJOCTET(marker->data[11]) == 0x0;
+}
+
+
+/*
+ * See if there was an ICC profile in the JPEG file being read; if so,
+ * reassemble and return the profile data.
+ *
+ * TRUE is returned if an ICC profile was found, FALSE if not. If TRUE is
+ * returned, *icc_data_ptr is set to point to the returned data, and
+ * *icc_data_len is set to its length.
+ *
+ * IMPORTANT: the data at *icc_data_ptr is allocated with malloc() and must be
+ * freed by the caller with free() when the caller no longer needs it.
+ * (Alternatively, we could write this routine to use the IJG library's memory
+ * allocator, so that the data would be freed implicitly when
+ * jpeg_finish_decompress() is called. But it seems likely that many
+ * applications will prefer to have the data stick around after decompression
+ * finishes.)
+ */
+
+GLOBAL(boolean)
+jpeg_read_icc_profile (j_decompress_ptr cinfo, JOCTET **icc_data_ptr,
+ unsigned int *icc_data_len)
+{
+ jpeg_saved_marker_ptr marker;
+ int num_markers = 0;
+ int seq_no;
+ JOCTET *icc_data;
+ unsigned int total_length;
+#define MAX_SEQ_NO 255 /* sufficient since marker numbers are bytes */
+ char marker_present[MAX_SEQ_NO+1]; /* 1 if marker found */
+ unsigned int data_length[MAX_SEQ_NO+1]; /* size of profile data in marker */
+ unsigned int data_offset[MAX_SEQ_NO+1]; /* offset for data in marker */
+
+ if (icc_data_ptr == NULL || icc_data_len == NULL)
+ ERREXIT(cinfo, JERR_BUFFER_SIZE);
+ if (cinfo->global_state < DSTATE_READY)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ *icc_data_ptr = NULL; /* avoid confusion if FALSE return */
+ *icc_data_len = 0;
+
+ /* This first pass over the saved markers discovers whether there are
+ * any ICC markers and verifies the consistency of the marker numbering.
+ */
+
+ for (seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++)
+ marker_present[seq_no] = 0;
+
+ for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
+ if (marker_is_icc(marker)) {
+ if (num_markers == 0)
+ num_markers = GETJOCTET(marker->data[13]);
+ else if (num_markers != GETJOCTET(marker->data[13])) {
+ WARNMS(cinfo, JWRN_BOGUS_ICC); /* inconsistent num_markers fields */
+ return FALSE;
+ }
+ seq_no = GETJOCTET(marker->data[12]);
+ if (seq_no <= 0 || seq_no > num_markers) {
+ WARNMS(cinfo, JWRN_BOGUS_ICC); /* bogus sequence number */
+ return FALSE;
+ }
+ if (marker_present[seq_no]) {
+ WARNMS(cinfo, JWRN_BOGUS_ICC); /* duplicate sequence numbers */
+ return FALSE;
+ }
+ marker_present[seq_no] = 1;
+ data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN;
+ }
+ }
+
+ if (num_markers == 0)
+ return FALSE;
+
+ /* Check for missing markers, count total space needed,
+ * compute offset of each marker's part of the data.
+ */
+
+ total_length = 0;
+ for (seq_no = 1; seq_no <= num_markers; seq_no++) {
+ if (marker_present[seq_no] == 0) {
+ WARNMS(cinfo, JWRN_BOGUS_ICC); /* missing sequence number */
+ return FALSE;
+ }
+ data_offset[seq_no] = total_length;
+ total_length += data_length[seq_no];
+ }
+
+ if (total_length == 0) {
+ WARNMS(cinfo, JWRN_BOGUS_ICC); /* found only empty markers? */
+ return FALSE;
+ }
+
+ /* Allocate space for assembled data */
+ icc_data = (JOCTET *) malloc(total_length * sizeof(JOCTET));
+ if (icc_data == NULL)
+ ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 11); /* oops, out of memory */
+
+ /* and fill it in */
+ for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
+ if (marker_is_icc(marker)) {
+ JOCTET FAR *src_ptr;
+ JOCTET *dst_ptr;
+ unsigned int length;
+ seq_no = GETJOCTET(marker->data[12]);
+ dst_ptr = icc_data + data_offset[seq_no];
+ src_ptr = marker->data + ICC_OVERHEAD_LEN;
+ length = data_length[seq_no];
+ while (length--) {
+ *dst_ptr++ = *src_ptr++;
+ }
+ }
+ }
+
+ *icc_data_ptr = icc_data;
+ *icc_data_len = total_length;
+
+ return TRUE;
+}
* Copyright (C) 1994-1997, Thomas G. Lane.
* Modified 1997-2009 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2014, D. R. Commander.
+ * Copyright (C) 2014, 2017, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code")
#endif
#endif
+JMESSAGE(JWRN_BOGUS_ICC, "Corrupt JPEG data: bad ICC marker")
#ifdef JMAKE_ENUM_LIST
* Copyright (C) 1991-1998, Thomas G. Lane.
* Modified 2002-2009 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009-2011, 2013-2014, 2016, D. R. Commander.
+ * Copyright (C) 2009-2011, 2013-2014, 2016-2017, D. R. Commander.
* Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
/* Alternate compression function: just write an abbreviated table file */
EXTERN(void) jpeg_write_tables (j_compress_ptr cinfo);
+/* Write ICC profile. See libjpeg.txt for usage information. */
+EXTERN(void) jpeg_write_icc_profile (j_compress_ptr cinfo,
+ const JOCTET *icc_data_ptr,
+ unsigned int icc_data_len);
+
+
/* Decompression startup: read start of JPEG datastream to see what's there */
EXTERN(int) jpeg_read_header (j_decompress_ptr cinfo, boolean require_image);
/* Return value is one of: */
/* Default restart-marker-resync procedure for use by data source modules */
EXTERN(boolean) jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired);
+/* Read ICC profile. See libjpeg.txt for usage information. */
+EXTERN(boolean) jpeg_read_icc_profile (j_decompress_ptr cinfo,
+ JOCTET **icc_data_ptr,
+ unsigned int *icc_data_len);
+
/* These marker codes are exported since applications and data source modules
* are likely to want to use them.
-.TH JPEGTRAN 1 "18 February 2016"
+.TH JPEGTRAN 1 "19 January 2017"
.SH NAME
jpegtran \- lossless transformation of JPEG files
.SH SYNOPSIS
.PP
Additional switches recognized by jpegtran are:
.TP
+.BI \-icc " file"
+Embed ICC color management profile contained in the specified file. Note that
+this will cause \fBjpegtran\fR to ignore any APP2 markers in the input file,
+even if \fB-copy all\fR is specified.
+.TP
.BI \-maxmemory " N"
Set limit for amount of memory to use in processing large images. Value is
in thousands of bytes, or millions of bytes if "M" is attached to the
static const char *progname; /* program name for error messages */
+static char *icc_filename; /* for -icc switch */
static char *outfilename; /* for -outfile switch */
static JCOPY_OPTION copyoption; /* -copy switch */
static jpeg_transform_info transformoption; /* image transformation options */
#ifdef C_ARITH_CODING_SUPPORTED
fprintf(stderr, " -arithmetic Use arithmetic coding\n");
#endif
+ fprintf(stderr, " -icc FILE Embed ICC profile contained in FILE\n");
fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n");
fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
fprintf(stderr, " -outfile name Specify name for output file\n");
/* Set up default JPEG parameters. */
simple_progressive = FALSE;
+ icc_filename = NULL;
outfilename = NULL;
copyoption = JCOPYOPT_DEFAULT;
transformoption.transform = JXFORM_NONE;
select_transform(JXFORM_NONE); /* force an error */
#endif
+ } else if (keymatch(arg, "icc", 1)) {
+ /* Set ICC filename. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ icc_filename = argv[argn];
+
} else if (keymatch(arg, "maxmemory", 3)) {
/* Maximum memory in Kb (or Mb with 'm'). */
long lval;
* single file pointer for sequential input and output operation.
*/
FILE *fp;
+ FILE *icc_file;
+ JOCTET *icc_profile = NULL;
+ long icc_len = 0;
/* On Mac, fetch a command line. */
#ifdef USE_CCOMMAND
fp = read_stdin();
}
+ if (icc_filename != NULL) {
+ if ((icc_file = fopen(icc_filename, READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, icc_filename);
+ exit(EXIT_FAILURE);
+ }
+ if (fseek(icc_file, 0, SEEK_END) < 0 ||
+ (icc_len = ftell(icc_file)) < 1 ||
+ fseek(icc_file, 0, SEEK_SET) < 0) {
+ fprintf(stderr, "%s: can't determine size of %s\n", progname,
+ icc_filename);
+ exit(EXIT_FAILURE);
+ }
+ if ((icc_profile = (JOCTET *)malloc(icc_len)) == NULL) {
+ fprintf(stderr, "%s: can't allocate memory for ICC profile\n", progname);
+ fclose(icc_file);
+ exit(EXIT_FAILURE);
+ }
+ if (fread(icc_profile, icc_len, 1, icc_file) < 1) {
+ fprintf(stderr, "%s: can't read ICC profile from %s\n", progname,
+ icc_filename);
+ free(icc_profile);
+ fclose(icc_file);
+ exit(EXIT_FAILURE);
+ }
+ fclose(icc_file);
+ if (copyoption == JCOPYOPT_ALL)
+ copyoption = JCOPYOPT_ALL_EXCEPT_ICC;
+ }
+
#ifdef PROGRESS_REPORT
start_progress_monitor((j_common_ptr) &dstinfo, &progress);
#endif
/* Copy to the output file any extra markers that we want to preserve */
jcopy_markers_execute(&srcinfo, &dstinfo, copyoption);
+ if (icc_profile != NULL)
+ jpeg_write_icc_profile(&dstinfo, icc_profile, (unsigned int)icc_len);
+
/* Execute image transformation, if any */
#if TRANSFORMS_SUPPORTED
jtransform_execute_transformation(&srcinfo, &dstinfo,
end_progress_monitor((j_common_ptr) &dstinfo);
#endif
+ if (icc_profile != NULL)
+ free(icc_profile);
+
/* All done. */
exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS);
return 0; /* suppress no-return-value warnings */
This file was part of the Independent JPEG Group's software:
Copyright (C) 1994-2013, Thomas G. Lane, Guido Vollbeding.
libjpeg-turbo Modifications:
-Copyright (C) 2010, 2014-2016, D. R. Commander.
+Copyright (C) 2010, 2014-2017, D. R. Commander.
Copyright (C) 2015, Google, Inc.
For conditions of distribution and use, see the accompanying README.ijg file.
Buffered-image mode
Abbreviated datastreams and multiple images
Special markers
+ ICC profiles
Raw (downsampled) image data
Really raw data: DCT coefficients
Progress monitoring
Also, see jpegtran.c for an example of using jpeg_save_markers.
+ICC profiles
+------------
+
+Two functions are provided for writing and reading International Color
+Consortium (ICC) device profiles embedded in JFIF JPEG image files:
+
+ void jpeg_write_icc_profile (j_compress_ptr cinfo,
+ const JOCTET *icc_data_ptr,
+ unsigned int icc_data_len);
+ boolean jpeg_read_icc_profile (j_decompress_ptr cinfo,
+ JOCTET **icc_data_ptr,
+ unsigned int *icc_data_len);
+
+The ICC has defined a standard for including such data in JPEG "APP2" markers.
+The aforementioned functions do not know anything about the internal structure
+of the ICC profile data; they just know how to embed the profile data into a
+JPEG file while writing it, or to extract the profile data from a JPEG file
+while reading it.
+
+jpeg_write_icc_profile() must be called after calling jpeg_start_compress() and
+before the first call to jpeg_write_scanlines() or jpeg_write_raw_data(). This
+ordering ensures that the APP2 marker(s) will appear after the SOI and JFIF or
+Adobe markers, but before all other data.
+
+jpeg_read_icc_profile() returns TRUE if an ICC profile was found and FALSE
+otherwise. If an ICC profile was found, then the function will allocate a
+memory region containing the profile and will return a pointer to that memory
+region in *icc_data_ptr, as well as the length of the region in *icc_data_len.
+This memory region is allocated by the library using malloc() and must be freed
+by the caller using free() when the memory region is no longer needed. Callers
+wishing to use jpeg_read_icc_profile() must call
+
+ jpeg_save_markers(cinfo, JPEG_APP0 + 2, 0xFFFF);
+
+prior to calling jpeg_read_header(). jpeg_read_icc_profile() can be called at
+any point between jpeg_read_header() and jpeg_finish_decompress().
+
+
Raw (downsampled) image data
----------------------------
--- /dev/null
+Little CMS
+Copyright (c) 1998-2011 Marti Maria Saguer
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
--- /dev/null
+Little CMS
+Copyright (c) 1998-2011 Marti Maria Saguer
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF);
}
/* Save all types of APPn markers iff ALL option */
- if (option == JCOPYOPT_ALL) {
- for (m = 0; m < 16; m++)
+ if (option == JCOPYOPT_ALL || option == JCOPYOPT_ALL_EXCEPT_ICC) {
+ for (m = 0; m < 16; m++) {
+ if (option == JCOPYOPT_ALL_EXCEPT_ICC && m == 2)
+ continue;
jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF);
+ }
}
#endif /* SAVE_MARKERS_SUPPORTED */
}
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1997-2011, Thomas G. Lane, Guido Vollbeding.
- * It was modified by The libjpeg-turbo Project to include only code relevant
- * to libjpeg-turbo.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2017, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
typedef enum {
JCOPYOPT_NONE, /* copy no optional markers */
JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */
- JCOPYOPT_ALL /* copy all optional markers */
+ JCOPYOPT_ALL, /* copy all optional markers */
+ JCOPYOPT_ALL_EXCEPT_ICC /* copy all optional markers except APP2 */
} JCOPY_OPTION;
#define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */
jpeg_mem_src @ 103 ;
jpeg_skip_scanlines @ 104 ;
jpeg_crop_scanline @ 105 ;
+ jpeg_read_icc_profile @ 106 ;
+ jpeg_write_icc_profile @ 107 ;
jzero_far @ 101 ;
jpeg_skip_scanlines @ 102 ;
jpeg_crop_scanline @ 103 ;
+ jpeg_read_icc_profile @ 104 ;
+ jpeg_write_icc_profile @ 105 ;
jpeg_mem_src @ 105 ;
jpeg_skip_scanlines @ 106 ;
jpeg_crop_scanline @ 107 ;
+ jpeg_read_icc_profile @ 108 ;
+ jpeg_write_icc_profile @ 109 ;
jzero_far @ 103 ;
jpeg_skip_scanlines @ 104 ;
jpeg_crop_scanline @ 105 ;
+ jpeg_read_icc_profile @ 106 ;
+ jpeg_write_icc_profile @ 107 ;
jzero_far @ 106 ;
jpeg_skip_scanlines @ 107 ;
jpeg_crop_scanline @ 108 ;
+ jpeg_read_icc_profile @ 109 ;
+ jpeg_write_icc_profile @ 110 ;