summaryrefslogtreecommitdiffstats
path: root/debian/lcms/lcms-1.19.dfsg2/jpegicc/jpegicc.c
diff options
context:
space:
mode:
authorMichele Calgaro <michele.calgaro@yahoo.it>2020-09-11 14:38:47 +0900
committerMichele Calgaro <michele.calgaro@yahoo.it>2020-09-11 14:38:47 +0900
commit884c8093d63402a1ad0b502244b791e3c6782be3 (patch)
treea600d4ab0d431a2bdfe4c15b70df43c14fbd8dd0 /debian/lcms/lcms-1.19.dfsg2/jpegicc/jpegicc.c
parent14e1aa2006796f147f3f4811fb908a6b01e79253 (diff)
downloadextra-dependencies-884c8093d63402a1ad0b502244b791e3c6782be3.tar.gz
extra-dependencies-884c8093d63402a1ad0b502244b791e3c6782be3.zip
Added debian extra dependency packages.
Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
Diffstat (limited to 'debian/lcms/lcms-1.19.dfsg2/jpegicc/jpegicc.c')
-rwxr-xr-xdebian/lcms/lcms-1.19.dfsg2/jpegicc/jpegicc.c1087
1 files changed, 1087 insertions, 0 deletions
diff --git a/debian/lcms/lcms-1.19.dfsg2/jpegicc/jpegicc.c b/debian/lcms/lcms-1.19.dfsg2/jpegicc/jpegicc.c
new file mode 100755
index 00000000..38a793c5
--- /dev/null
+++ b/debian/lcms/lcms-1.19.dfsg2/jpegicc/jpegicc.c
@@ -0,0 +1,1087 @@
+//
+// Little cms
+// Copyright (C) 1998-2007 Marti Maria
+//
+// 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.
+
+
+// This program does apply profiles to (some) JPEG files
+
+
+#include "lcms.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+
+#ifndef NON_WINDOWS
+# include <io.h>
+#endif
+
+#include "jpeglib.h"
+#include "iccjpeg.h"
+
+#define PROGNAME "JPEGICC"
+
+// xgetopt() interface -----------------------------------------------------
+
+extern int xoptind;
+extern char *xoptarg;
+extern int xopterr;
+extern char SW;
+int cdecl xgetopt(int argc, char *argv[], char *optionS);
+
+// ------------------------------------------------------------------------
+
+extern cmsHPROFILE OpenStockProfile(const char* File);
+
+
+// Flags
+
+static LCMSBOOL Verbose = FALSE;
+static LCMSBOOL BlackPointCompensation = FALSE;
+static LCMSBOOL IgnoreEmbedded = FALSE;
+static LCMSBOOL GamutCheck = FALSE;
+static LCMSBOOL lIsITUFax = FALSE;
+static LCMSBOOL lIsPhotoshopApp13 = FALSE;
+static LCMSBOOL lIsDeviceLink = FALSE;
+static LCMSBOOL EmbedProfile = FALSE;
+static int PreserveBlack = 0;
+
+static const char* SaveEmbedded = NULL;
+
+static int Intent = INTENT_PERCEPTUAL;
+static int ProofingIntent = INTENT_PERCEPTUAL;
+static int PrecalcMode = 1;
+
+static int jpegQuality = 75;
+
+static double ObserverAdaptationState = 0;
+
+static char *cInpProf = NULL;
+static char *cOutProf = NULL;
+static char *cProofing = NULL;
+
+static FILE * InFile;
+static FILE * OutFile;
+
+static struct jpeg_decompress_struct Decompressor;
+static struct jpeg_compress_struct Compressor;
+
+
+static struct my_error_mgr {
+
+ struct jpeg_error_mgr pub; // "public" fields
+ LPVOID Cargo; // "private" fields
+
+} ErrorHandler;
+
+static
+void ConsoleWarningHandler(const char* module, const char* fmt, va_list ap)
+{
+ char e[512] = { '\0' };
+ if (module != NULL)
+ strcat(strcpy(e, module), ": ");
+
+ vsprintf(e+strlen(e), fmt, ap);
+ strcat(e, ".");
+ if (Verbose) {
+
+ fprintf(stderr, "\nWarning");
+ fprintf(stderr, " %s\n", e);
+ }
+}
+
+static
+void ConsoleErrorHandler(const char* module, const char* fmt, va_list ap)
+{
+ char e[512] = { '\0' };
+
+ if (module != NULL)
+ strcat(strcpy(e, module), ": ");
+
+ vsprintf(e+strlen(e), fmt, ap);
+ strcat(e, ".");
+ fprintf(stderr, "\nError");
+ fprintf(stderr, " %s\n", e);
+}
+
+// Force an error and exit w/ return code 1
+
+static
+void FatalError(const char *frm, ...)
+{
+ va_list args;
+
+ va_start(args, frm);
+ ConsoleErrorHandler(PROGNAME, frm, args);
+ va_end(args);
+ exit(1);
+}
+
+static
+int MyErrorHandler(int ErrorCode, const char *ErrorText)
+{
+ FatalError("%s", ErrorText);
+ return 0;
+}
+
+
+// Out of mem
+static
+void OutOfMem(size_t size)
+{
+ FatalError("Out of memory on allocating %d bytes.", size);
+}
+
+
+METHODDEF(void)
+my_output_message (j_common_ptr cinfo)
+{
+ char buffer[JMSG_LENGTH_MAX];
+
+ (*cinfo->err->format_message) (cinfo, buffer);
+ FatalError("%s %s", PROGNAME, buffer);
+}
+
+
+METHODDEF(void)
+my_error_exit (j_common_ptr cinfo)
+{
+ // struct my_error_mgr *myerr = (struct my_error_mgr *) cinfo->err;
+ char buffer[JMSG_LENGTH_MAX];
+
+ (*cinfo->err->format_message) (cinfo, buffer);
+ FatalError(buffer);
+}
+
+
+
+static
+LCMSBOOL IsITUFax(jpeg_saved_marker_ptr ptr)
+{
+ while (ptr) {
+
+ if (ptr -> marker == (JPEG_APP0 + 1) && ptr -> data_length > 5)
+ {
+ JOCTET FAR* data = ptr -> data;
+
+ if (GETJOCTET(data[0]) == 0x47 &&
+ GETJOCTET(data[1]) == 0x33 &&
+ GETJOCTET(data[2]) == 0x46 &&
+ GETJOCTET(data[3]) == 0x41 &&
+ GETJOCTET(data[4]) == 0x58)
+ return TRUE;
+ }
+
+ ptr = ptr -> next;
+ }
+
+ return FALSE;
+
+}
+
+#define PS_FIXED_TO_FLOAT(h, l) ((float) (h) + ((float) (l)/(1<<16)))
+
+static
+LCMSBOOL ProcessPhotoshopAPP13(JOCTET FAR *data, int datalen)
+{
+ int i;
+
+ for (i = 14; i < datalen; )
+ {
+ long len;
+ unsigned int type;
+
+ if (!(GETJOCTET(data[i] ) == 0x38 &&
+ GETJOCTET(data[i+1]) == 0x42 &&
+ GETJOCTET(data[i+2]) == 0x49 &&
+ GETJOCTET(data[i+3]) == 0x4D)) break; // Not recognized
+
+ i += 4; // identifying string
+
+ type = (unsigned int) (GETJOCTET(data[i]<<8) + GETJOCTET(data[i+1]));
+
+ i += 2; // resource type
+
+ i += GETJOCTET(data[i]) + ((GETJOCTET(data[i]) & 1) ? 1 : 2); // resource name
+
+ len = ((((GETJOCTET(data[i]<<8) + GETJOCTET(data[i+1]))<<8) +
+ GETJOCTET(data[i+2]))<<8) + GETJOCTET(data[i+3]);
+
+ i += 4; // Size
+
+ if (type == 0x03ED && len >= 16) {
+
+ Decompressor.X_density = (int) PS_FIXED_TO_FLOAT(GETJOCTET(data[i]<<8) + GETJOCTET(data[i+1]),
+ GETJOCTET(data[i+2]<<8) + GETJOCTET(data[i+3]));
+ Decompressor.Y_density = (int) PS_FIXED_TO_FLOAT(GETJOCTET(data[i+8]<<8) + GETJOCTET(data[i+9]),
+ GETJOCTET(data[i+10]<<8) + GETJOCTET(data[i+11]));
+
+ // Set the density unit to 1 since the
+ // Vertical and Horizontal resolutions
+ // are specified in Pixels per inch
+
+ Decompressor.density_unit = 0x01;
+ return TRUE;
+
+ }
+
+ i += len + ((len & 1) ? 1 : 0); // Alignment
+ }
+ return FALSE;
+}
+
+
+static
+LCMSBOOL HandlePhotoshopAPP13(jpeg_saved_marker_ptr ptr)
+{
+ while (ptr) {
+
+ if (ptr -> marker == (JPEG_APP0 + 13) && ptr -> data_length > 9)
+ {
+ JOCTET FAR* data = ptr -> data;
+
+ if(GETJOCTET(data[0]) == 0x50 &&
+ GETJOCTET(data[1]) == 0x68 &&
+ GETJOCTET(data[2]) == 0x6F &&
+ GETJOCTET(data[3]) == 0x74 &&
+ GETJOCTET(data[4]) == 0x6F &&
+ GETJOCTET(data[5]) == 0x73 &&
+ GETJOCTET(data[6]) == 0x68 &&
+ GETJOCTET(data[7]) == 0x6F &&
+ GETJOCTET(data[8]) == 0x70) {
+
+ ProcessPhotoshopAPP13(data, ptr -> data_length);
+ return TRUE;
+ }
+ }
+
+ ptr = ptr -> next;
+ }
+
+ return FALSE;
+}
+
+
+
+static
+LCMSBOOL OpenInput(const char* FileName)
+{
+ int m;
+
+ lIsITUFax = FALSE;
+ InFile = fopen(FileName, "rb");
+ if (InFile == NULL) {
+ FatalError("Cannot open '%s'", FileName);
+ return FALSE;
+ }
+
+ // Now we can initialize the JPEG decompression object.
+
+ Decompressor.err = jpeg_std_error(&ErrorHandler.pub);
+ ErrorHandler.pub.error_exit = my_error_exit;
+ ErrorHandler.pub.output_message = my_output_message;
+
+ jpeg_create_decompress(&Decompressor);
+ jpeg_stdio_src(&Decompressor, InFile);
+
+ for (m = 0; m < 16; m++)
+ jpeg_save_markers(&Decompressor, JPEG_APP0 + m, 0xFFFF);
+
+ setup_read_icc_profile(&Decompressor);
+
+ fseek(InFile, 0, SEEK_SET);
+ jpeg_read_header(&Decompressor, TRUE);
+
+ return TRUE;
+}
+
+
+static
+LCMSBOOL OpenOutput(const char* FileName)
+{
+
+ OutFile = fopen(FileName, "wb");
+ if (OutFile == NULL) {
+ FatalError("Cannot create '%s'", FileName);
+ return FALSE;
+ }
+
+ Compressor.err = jpeg_std_error(&ErrorHandler.pub);
+ ErrorHandler.pub.error_exit = my_error_exit;
+ ErrorHandler.pub.output_message = my_output_message;
+
+ Compressor.input_components = Compressor.num_components = 4;
+
+ jpeg_create_compress(&Compressor);
+ jpeg_stdio_dest(&Compressor, OutFile);
+
+ return TRUE;
+}
+
+static
+LCMSBOOL Done()
+{
+ jpeg_destroy_decompress(&Decompressor);
+ jpeg_destroy_compress(&Compressor);
+ return fclose(InFile) + fclose(OutFile);
+
+}
+
+
+// Build up the pixeltype descriptor
+
+static
+DWORD GetInputPixelType(void)
+{
+ int space, bps, extra, ColorChannels, Flavor;
+
+
+ lIsITUFax = IsITUFax(Decompressor.marker_list);
+ lIsPhotoshopApp13 = HandlePhotoshopAPP13(Decompressor.marker_list);
+
+ ColorChannels = Decompressor.num_components;
+ extra = 0; // Alpha = None
+ bps = 1; // 8 bits
+ Flavor = 0; // Vanilla
+
+ if (lIsITUFax) {
+
+ space = PT_Lab;
+ Decompressor.out_color_space = JCS_YCbCr; // Fake to don't touch
+ }
+ else
+ switch (Decompressor.jpeg_color_space) {
+
+ case JCS_GRAYSCALE: // monochrome
+ space = PT_GRAY;
+ Decompressor.out_color_space = JCS_GRAYSCALE;
+ break;
+
+ case JCS_RGB: // red/green/blue
+ space = PT_RGB;
+ Decompressor.out_color_space = JCS_RGB;
+ break;
+
+ case JCS_YCbCr: // Y/Cb/Cr (also known as YUV)
+ space = PT_RGB; // Let IJG code to do the conversion
+ Decompressor.out_color_space = JCS_RGB;
+ break;
+
+ case JCS_CMYK: // C/M/Y/K
+ space = PT_CMYK;
+ Decompressor.out_color_space = JCS_CMYK;
+ if (Decompressor.saw_Adobe_marker) // Adobe keeps CMYK inverted, so change flavor
+ Flavor = 1; // from vanilla to chocolate
+ break;
+
+ case JCS_YCCK: // Y/Cb/Cr/K
+ space = PT_CMYK;
+ Decompressor.out_color_space = JCS_CMYK;
+ if (Decompressor.saw_Adobe_marker) // ditto
+ Flavor = 1;
+ break;
+
+ default:
+ FatalError("Unsupported color space (0x%x)", Decompressor.jpeg_color_space);
+ return 0;
+ }
+
+ return (EXTRA_SH(extra)|CHANNELS_SH(ColorChannels)|BYTES_SH(bps)|COLORSPACE_SH(space)|FLAVOR_SH(Flavor));
+}
+
+
+
+
+
+// Rearrange pixel type to build output descriptor
+
+static
+DWORD ComputeOutputFormatDescriptor(DWORD dwInput, int OutColorSpace)
+{
+ int IsPlanar = T_PLANAR(dwInput);
+ int Channels = 0;
+ int Flavor = 0;
+
+ switch (OutColorSpace) {
+
+ case PT_GRAY:
+ Channels = 1;
+ break;
+ case PT_RGB:
+ case PT_CMY:
+ case PT_Lab:
+ case PT_YUV:
+ case PT_YCbCr:
+ Channels = 3;
+ break;
+
+ case PT_CMYK:
+ if (Compressor.write_Adobe_marker) // Adobe keeps CMYK inverted, so change flavor to chocolate
+ Flavor = 1;
+
+ Channels = 4;
+ break;
+ default:
+ FatalError("Unsupported output color space");
+ }
+
+ return (COLORSPACE_SH(OutColorSpace)|PLANAR_SH(IsPlanar)|CHANNELS_SH(Channels)|BYTES_SH(1)|FLAVOR_SH(Flavor));
+}
+
+
+// Equivalence between ICC color spaces and lcms color spaces
+
+static
+int GetProfileColorSpace(cmsHPROFILE hProfile)
+{
+ icColorSpaceSignature ProfileSpace = cmsGetColorSpace(hProfile);
+
+ switch (ProfileSpace) {
+
+ case icSigGrayData: return PT_GRAY;
+ case icSigRgbData: return PT_RGB;
+ case icSigCmyData: return PT_CMY;
+ case icSigCmykData: return PT_CMYK;
+ case icSigYCbCrData:return PT_YCbCr;
+ case icSigLuvData: return PT_YUV;
+ case icSigXYZData: return PT_XYZ;
+ case icSigLabData: return PT_Lab;
+ case icSigLuvKData: return PT_YUVK;
+ case icSigHsvData: return PT_HSV;
+ case icSigHlsData: return PT_HLS;
+ case icSigYxyData: return PT_Yxy;
+
+ case icSigHexachromeData: return PT_HiFi;
+
+
+ default: return icMaxEnumData;
+ }
+}
+
+// From TRANSUPP
+
+static
+void jcopy_markers_execute(j_decompress_ptr srcinfo, j_compress_ptr dstinfo)
+{
+ jpeg_saved_marker_ptr marker;
+
+ /* In the current implementation, we don't actually need to examine the
+ * option flag here; we just copy everything that got saved.
+ * But to avoid confusion, we do not output JFIF and Adobe APP14 markers
+ * if the encoder library already wrote one.
+ */
+ for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {
+ if (dstinfo->write_JFIF_header &&
+ marker->marker == JPEG_APP0 &&
+ marker->data_length >= 5 &&
+ GETJOCTET(marker->data[0]) == 0x4A &&
+ GETJOCTET(marker->data[1]) == 0x46 &&
+ GETJOCTET(marker->data[2]) == 0x49 &&
+ GETJOCTET(marker->data[3]) == 0x46 &&
+ GETJOCTET(marker->data[4]) == 0)
+ continue; /* reject duplicate JFIF */
+
+ if (dstinfo->write_Adobe_marker &&
+ marker->marker == JPEG_APP0+14 &&
+ marker->data_length >= 5 &&
+ GETJOCTET(marker->data[0]) == 0x41 &&
+ GETJOCTET(marker->data[1]) == 0x64 &&
+ GETJOCTET(marker->data[2]) == 0x6F &&
+ GETJOCTET(marker->data[3]) == 0x62 &&
+ GETJOCTET(marker->data[4]) == 0x65)
+ continue; /* reject duplicate Adobe */
+
+#ifdef NEED_FAR_POINTERS
+ /* We could use jpeg_write_marker if the data weren't FAR... */
+ {
+ unsigned int i;
+
+ jpeg_write_m_header(dstinfo, marker->marker, marker->data_length);
+ for (i = 0; i < marker->data_length; i++)
+ jpeg_write_m_byte(dstinfo, marker->data[i]);
+ }
+#else
+ jpeg_write_marker(dstinfo, marker->marker,
+ marker->data, marker->data_length);
+#endif
+ }
+}
+
+static
+void WriteOutputFields(int OutputColorSpace)
+{
+ J_COLOR_SPACE in_space, jpeg_space;
+ int components;
+
+ switch (OutputColorSpace) {
+
+ case PT_GRAY: in_space = jpeg_space = JCS_GRAYSCALE;
+ components = 1;
+ break;
+
+ case PT_RGB: in_space = JCS_RGB;
+ jpeg_space = JCS_YCbCr;
+ components = 3;
+ break; // red/green/blue
+
+ case PT_YCbCr: in_space = jpeg_space = JCS_YCbCr;
+ components = 3;
+ break; // Y/Cb/Cr (also known as YUV)
+
+ case PT_CMYK: in_space = JCS_CMYK;
+ jpeg_space = JCS_YCCK;
+ components = 4;
+ break; // C/M/Y/components
+
+ case PT_Lab: in_space = jpeg_space = JCS_YCbCr;
+ components = 3;
+ break; // Fake to don't touch
+ default:
+ FatalError("Unsupported output color space");
+ return;
+ }
+
+
+ if (jpegQuality >= 100) {
+
+ // avoid destructive conversion when asking for lossless compression
+ jpeg_space = in_space;
+ }
+
+ Compressor.in_color_space = in_space;
+ Compressor.jpeg_color_space = jpeg_space;
+ Compressor.input_components = Compressor.num_components = components;
+ jpeg_set_defaults(&Compressor);
+ jpeg_set_colorspace(&Compressor, jpeg_space);
+
+ // Make sure to pass resolution through
+ if (OutputColorSpace == PT_CMYK)
+ Compressor.write_JFIF_header = 1;
+
+ //avoid subsampling on high quality factor
+ jpeg_set_quality(&Compressor, jpegQuality, 1);
+ if (jpegQuality >= 70) {
+
+ int i;
+ for(i=0; i < Compressor.num_components; i++) {
+
+ Compressor.comp_info[i].h_samp_factor = 1;
+ Compressor.comp_info[i].v_samp_factor = 1;
+ }
+
+ }
+
+}
+
+// A replacement for (the nonstandard) filelenght
+
+static
+int xfilelength(int fd)
+{
+#ifdef _MSC_VER
+ return _filelength(fd);
+#else
+ struct stat sb;
+ if (fstat(fd, &sb) < 0)
+ return(-1);
+ return(sb.st_size);
+#endif
+
+
+}
+
+static
+void DoEmbedProfile(const char* ProfileFile)
+{
+ FILE* f;
+ size_t size, EmbedLen;
+ LPBYTE EmbedBuffer;
+
+ f = fopen(ProfileFile, "rb");
+ if (f == NULL) return;
+
+ size = xfilelength(fileno(f));
+ EmbedBuffer = (LPBYTE) _cmsMalloc(size + 1);
+ EmbedLen = fread(EmbedBuffer, 1, size, f);
+ fclose(f);
+ EmbedBuffer[EmbedLen] = 0;
+
+ write_icc_profile (&Compressor, EmbedBuffer, EmbedLen);
+ _cmsFree(EmbedBuffer);
+}
+
+
+
+static
+int DoTransform(cmsHTRANSFORM hXForm)
+{
+ JSAMPROW ScanLineIn;
+ JSAMPROW ScanLineOut;
+
+
+ //Preserve resolution values from the original
+ // (Thanks to robert bergs for finding out this bug)
+
+ Compressor.density_unit = Decompressor.density_unit;
+ Compressor.X_density = Decompressor.X_density;
+ Compressor.Y_density = Decompressor.Y_density;
+
+ // Compressor.write_JFIF_header = 1;
+
+ jpeg_start_decompress(&Decompressor);
+ jpeg_start_compress(&Compressor, TRUE);
+
+ // Embed the profile if needed
+ if (EmbedProfile && cOutProf)
+ DoEmbedProfile(cOutProf);
+
+ ScanLineIn = (JSAMPROW) _cmsMalloc(Decompressor.output_width * Decompressor.num_components);
+ ScanLineOut = (JSAMPROW) _cmsMalloc(Compressor.image_width * Compressor.num_components);
+
+ while (Decompressor.output_scanline <
+ Decompressor.output_height) {
+
+ jpeg_read_scanlines(&Decompressor, &ScanLineIn, 1);
+
+ cmsDoTransform(hXForm, ScanLineIn, ScanLineOut, Decompressor.output_width);
+
+ jpeg_write_scanlines(&Compressor, &ScanLineOut, 1);
+
+ }
+
+ _cmsFree(ScanLineIn);
+ _cmsFree(ScanLineOut);
+
+ jpeg_finish_decompress(&Decompressor);
+ jpeg_finish_compress(&Compressor);
+
+ return TRUE;
+}
+
+
+
+
+static
+void SaveMemoryBlock(const BYTE* Buffer, DWORD dwLen, const char* Filename)
+{
+ FILE* out = fopen(Filename, "wb");
+ if (out == NULL)
+ FatalError("Cannot create '%s'", Filename);
+
+ if (fwrite(Buffer, 1, dwLen, out) != dwLen)
+ FatalError("Cannot write %ld bytes to %s", dwLen, Filename);
+
+ if (fclose(out) != 0)
+ FatalError("Error flushing file '%s'", Filename);
+}
+
+
+
+// Transform one image
+
+static
+int TransformImage(char *cDefInpProf, char *cOutProf)
+{
+ cmsHPROFILE hIn, hOut, hProof;
+ cmsHTRANSFORM xform;
+ DWORD wInput, wOutput;
+ int OutputColorSpace;
+ DWORD dwFlags = 0;
+ DWORD EmbedLen;
+ LPBYTE EmbedBuffer;
+
+ // Observer adaptation state (only meaningful on absolute colorimetric intent)
+
+ cmsSetAdaptationState(ObserverAdaptationState);
+
+
+ if (BlackPointCompensation) {
+
+ dwFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
+ }
+
+
+ if (PreserveBlack) {
+ dwFlags |= cmsFLAGS_PRESERVEBLACK;
+ if (PrecalcMode == 0) PrecalcMode = 1;
+ cmsSetCMYKPreservationStrategy(PreserveBlack-1);
+ }
+
+
+ switch (PrecalcMode) {
+
+ case 0: dwFlags |= cmsFLAGS_NOTPRECALC; break;
+ case 2: dwFlags |= cmsFLAGS_HIGHRESPRECALC; break;
+ case 3: dwFlags |= cmsFLAGS_LOWRESPRECALC; break;
+ default:;
+ }
+
+
+ if (GamutCheck)
+ dwFlags |= cmsFLAGS_GAMUTCHECK;
+
+
+ if (lIsDeviceLink) {
+
+ hIn = cmsOpenProfileFromFile(cDefInpProf, "r");
+ hOut = NULL;
+ hProof = NULL;
+ }
+ else {
+
+ if (!IgnoreEmbedded && read_icc_profile(&Decompressor, &EmbedBuffer, &EmbedLen))
+ {
+ hIn = cmsOpenProfileFromMem(EmbedBuffer, EmbedLen);
+
+ if (Verbose) {
+
+ fprintf(stdout, " (Embedded profile found)\n");
+ fprintf(stdout, "Product name: %s\n", cmsTakeProductName(hIn));
+ fprintf(stdout, "Description : %s\n", cmsTakeProductDesc(hIn));
+ fflush(stdout);
+ }
+
+ if (hIn != NULL && SaveEmbedded != NULL)
+ SaveMemoryBlock(EmbedBuffer, EmbedLen, SaveEmbedded);
+
+ _cmsFree(EmbedBuffer);
+ }
+ else
+ {
+ hIn = OpenStockProfile(cDefInpProf);
+ }
+
+ hOut = OpenStockProfile(cOutProf);
+
+
+ hProof = NULL;
+ if (cProofing != NULL) {
+
+ hProof = OpenStockProfile(cProofing);
+ dwFlags |= cmsFLAGS_SOFTPROOFING;
+ }
+ }
+
+ // Take input color space
+
+ wInput = GetInputPixelType();
+
+ // Assure both, input profile and input JPEG are on same colorspace
+
+
+ if (cmsGetColorSpace(hIn) != _cmsICCcolorSpace(T_COLORSPACE(wInput)))
+ FatalError("Input profile is not operating in proper color space");
+
+
+ // Output colorspace is given by output profile
+
+ if (lIsDeviceLink) {
+ OutputColorSpace = T_COLORSPACE(wInput);
+ }
+ else {
+ OutputColorSpace = GetProfileColorSpace(hOut);
+ }
+
+ jpeg_copy_critical_parameters(&Decompressor, &Compressor);
+
+ WriteOutputFields(OutputColorSpace);
+
+ wOutput = ComputeOutputFormatDescriptor(wInput, OutputColorSpace);
+
+ xform = cmsCreateProofingTransform(hIn, wInput,
+ hOut, wOutput,
+ hProof, Intent,
+ ProofingIntent, dwFlags);
+
+ // Handle tile by tile or strip by strip strtok
+
+ DoTransform(xform);
+
+
+ jcopy_markers_execute(&Decompressor, &Compressor);
+
+ cmsDeleteTransform(xform);
+ cmsCloseProfile(hIn);
+ cmsCloseProfile(hOut);
+ if (hProof) cmsCloseProfile(hProof);
+
+ return 1;
+}
+
+
+// Simply print help
+
+static
+void Help(int level)
+{
+ fprintf(stderr, "little cms ICC profile applier for JPEG - v2.1\n\n");
+
+ switch(level) {
+
+ default:
+ case 0:
+
+ fprintf(stderr, "usage: jpegicc [flags] input.jpg output.jpg\n");
+
+ fprintf(stderr, "\nflags:\n\n");
+ fprintf(stderr, "%cv - Verbose\n", SW);
+ fprintf(stderr, "%ci<profile> - Input profile (defaults to sRGB)\n", SW);
+ fprintf(stderr, "%co<profile> - Output profile (defaults to sRGB)\n", SW);
+ fprintf(stderr, "%ct<0,1,2,3> - Intent (0=Perceptual, 1=Colorimetric, 2=Saturation, 3=Absolute)\n", SW);
+
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "%cb - Black point compensation\n", SW);
+ fprintf(stderr, "%cf<n> - Preserve black (CMYK only) 0=off, 1=black ink only, 2=full K plane\n", SW);
+ fprintf(stderr, "%cn - Ignore embedded profile\n", SW);
+ fprintf(stderr, "%ce - Embed destination profile\n", SW);
+ fprintf(stderr, "%cs<new profile> - Save embedded profile as <new profile>\n", SW);
+
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "%cc<0,1,2,3> - Precalculates transform (0=Off, 1=Normal, 2=Hi-res, 3=LoRes) [defaults to 1]\n", SW);
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "%cp<profile> - Soft proof profile\n", SW);
+ fprintf(stderr, "%cm<0,1,2,3> - SoftProof intent\n", SW);
+ fprintf(stderr, "%cg - Marks out-of-gamut colors on softproof\n", SW);
+
+ fprintf(stderr, "\n");
+ fprintf(stderr, "%cq<0..100> - Output JPEG quality\n", SW);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "%cd<0..1> - Observer adaptation state (abs.col. only)\n", SW);
+
+ fprintf(stderr, "\n");
+ fprintf(stderr, "%ch<0,1,2> - More help\n", SW);
+ break;
+
+ case 1:
+
+
+ fprintf(stderr, "Examples:\n\n"
+ "To color correct from scanner to sRGB:\n"
+ "\tjpegicc %ciscanner.icm in.jpg out.jpg\n"
+ "To convert from monitor1 to monitor2:\n"
+ "\tjpegicc %cimon1.icm %comon2.icm in.jpg out.jpg\n"
+ "To make a CMYK separation:\n"
+ "\tjpegicc %coprinter.icm inrgb.jpg outcmyk.jpg\n"
+ "To recover sRGB from a CMYK separation:\n"
+ "\tjpegicc %ciprinter.icm incmyk.jpg outrgb.jpg\n"
+ "To convert from CIELab ITU/Fax JPEG to sRGB\n"
+ "\tjpegicc %ciitufax.icm in.jpg out.jpg\n\n",
+ SW, SW, SW, SW, SW, SW);
+ break;
+
+ case 2:
+
+ fprintf(stderr, "This program is intended to be a demo of the little cms\n"
+ "engine. Both lcms and this program are freeware. You can\n"
+ "obtain both in source code at http://www.littlecms.com\n"
+ "For suggestions, comments, bug reports etc. send mail to\n"
+ "marti@littlecms.com\n\n");
+ break;
+ }
+
+ exit(0);
+}
+
+
+// The toggles stuff
+
+static
+void HandleSwitches(int argc, char *argv[])
+{
+ int s;
+
+ while ((s=xgetopt(argc,argv,"bBnNvVGgh:H:i:I:o:O:P:p:t:T:c:C:Q:q:M:m:L:l:eEs:S:F:f:D:d:")) != EOF) {
+
+ switch (s)
+ {
+
+ case 'b':
+ case 'B':
+ BlackPointCompensation = TRUE;
+ break;
+
+ case 'v':
+ case 'V':
+ Verbose = TRUE;
+ break;
+
+ case 'i':
+ case 'I':
+
+ if (lIsDeviceLink)
+ FatalError("Device-link already specified");
+
+ cInpProf = xoptarg;
+ break;
+
+ case 'o':
+ case 'O':
+
+ if (lIsDeviceLink)
+ FatalError("Device-link already specified");
+
+ cOutProf = xoptarg;
+ break;
+
+ case 'l':
+ case 'L':
+ cInpProf = xoptarg;
+ lIsDeviceLink = TRUE;
+ break;
+
+ case 'p':
+ case 'P':
+ cProofing = xoptarg;
+ break;
+
+ case 't':
+ case 'T':
+ Intent = atoi(xoptarg);
+ if (Intent > 3) Intent = 3;
+ if (Intent < 0) Intent = 0;
+ break;
+
+ case 'N':
+ case 'n':
+ IgnoreEmbedded = TRUE;
+ break;
+
+ case 'e':
+ case 'E':
+ EmbedProfile = TRUE;
+ break;
+
+ case 'f':
+ case 'F':
+ PreserveBlack = atoi(xoptarg);
+ if (PreserveBlack < 0 || PreserveBlack > 2)
+ FatalError("Unknown PreserveBlack '%d'", PreserveBlack);
+ break;
+
+ case 'g':
+ case 'G':
+ GamutCheck = TRUE;
+ break;
+
+ case 'c':
+ case 'C':
+ PrecalcMode = atoi(xoptarg);
+ if (PrecalcMode < 0 || PrecalcMode > 2)
+ FatalError("Unknown precalc mode '%d'", PrecalcMode);
+ break;
+
+ case 'H':
+ case 'h': {
+
+ int a = atoi(xoptarg);
+ Help(a);
+ }
+ break;
+
+ case 'q':
+ case 'Q':
+ jpegQuality = atoi(xoptarg);
+ if (jpegQuality > 100) jpegQuality = 100;
+ if (jpegQuality < 0) jpegQuality = 0;
+ break;
+
+ case 'm':
+ case 'M':
+ ProofingIntent = atoi(xoptarg);
+ if (ProofingIntent > 3) ProofingIntent = 3;
+ if (ProofingIntent < 0) ProofingIntent = 0;
+ break;
+
+ case 's':
+ case 'S': SaveEmbedded = xoptarg;
+ break;
+
+ case 'd':
+ case 'D': ObserverAdaptationState = atof(xoptarg);
+ if (ObserverAdaptationState != 0 &&
+ ObserverAdaptationState != 1.0)
+ fprintf(stderr, "Warning: Adaptation states other that 0 or 1 are not yet implemented\n");
+ break;
+
+ default:
+
+ FatalError("Unknown option - run without args to see valid ones");
+ }
+
+ }
+}
+
+
+// The main sink
+
+int main(int argc, char* argv[])
+{
+ char *Intents[] = {"perceptual",
+ "relative colorimetric",
+ "saturation",
+ "absolute colorimetric" };
+
+ HandleSwitches(argc, argv);
+
+ cmsSetErrorHandler(MyErrorHandler);
+
+ if ((argc - xoptind) != 2) {
+
+ Help(0);
+ }
+
+
+
+ if (Verbose) {
+
+ if (lIsDeviceLink)
+ fprintf(stdout, "%s(device link) -> %s [%s]",
+ argv[xoptind],
+ argv[xoptind+1],
+ Intents[Intent]);
+
+ else
+ fprintf(stdout, "%s(%s) -> %s(%s) [%s]", argv[xoptind],
+ (cInpProf == NULL ? "sRGB": cInpProf),
+ argv[xoptind+1],
+ (cOutProf == NULL ? "sRGB" : cOutProf),
+ Intents[Intent]);
+ }
+
+ OpenInput(argv[xoptind]);
+ OpenOutput(argv[xoptind+1]);
+ TransformImage(cInpProf, cOutProf);
+
+
+ if (Verbose) fprintf(stdout, "\n");
+
+ Done();
+
+ return 0;
+}
+
+
+