paste in cmyk2srgbjpeg

many thanks Nicolas
This commit is contained in:
John Cupitt 2013-12-10 09:23:34 +00:00
parent c0b8b67987
commit aede2cafce
3 changed files with 438 additions and 0 deletions

View File

@ -26,6 +26,7 @@
- added --vips-profile, records and dumps thread timing and memory use info
- added vipsprofile, visualises --vips-profile output
- auto-vectorization-friendly inner loops
- pasted in Nicolas's cmyk2srgbjpeg program, many thanks
20/11/13 started 7.36.5
- better cache sizing in unbuffered sequential mode

View File

@ -4,6 +4,7 @@ bin_PROGRAMS = \
vips \
edvips \
vipsthumbnail \
cmyk2srgbjpeg \
header
vips_SOURCES = vips.c

436
tools/cmyk2srgbjpeg.c Normal file
View File

@ -0,0 +1,436 @@
/*
* C program cmyk2srgbjpeg (CMYK image conversion to sRGB JPEG)
*
* Version 2.4
*
* USAGE
*
* cmyk2srgbjpeg INPUT_IMAGE OUTPUT_IMAGE_NAME_BEFORE_EXTENSION
*
* where
*
* INPUT_IMAGE_FILE is an image
*
* OUTPUT_IMAGE_NAME_BEFORE_EXTENSION is the desired name (possibly
* including path) of the converted image if it is created, to
* which a configurable extension identifying a JPEG image will be
* appended (.jpg, as delivered).
*
* WHAT IT DOES
*
* cmyk2srgbjpeg first attempts to detect whether its file argument is
* a CMYK image.
*
* If it does not identify the file as being CMYK, cmyk2srgbjpeg does
* not do anything.
*
* If it determines INPUT_IMAGE_FILE to be CMYK, it converts it to
* sRGB JPEG using the embedded colour profile if possible,
* substituting a default ICC otherwise.
*
* The result of the conversion is saved into
* OUTPUT_IMAGE_NAME_BEFORE_EXTENSION.jpg (if .jpg is the configured
* extension), provided it points elsewhere than INPUT_IMAGE_FILE.
*
* CUSTOMISATION
*
* Numerous compile time options are set with #defines. See below.
*
* NON-LIBRARY REQUIREMENTS:
*
* The program expects to find a "backstop" CMYK ICC profile at the
* location specified by CMYK2SRGBJPEG_BACKUP_CMYK_ICC. It also
* expects to find an ICM profile specifying sRGB at the location
* specified by CMYK2SRGBJPEG_SRGB_ICM. Full paths may be given.
*
* CREDITS
*
* The development of cmyk2srgb was partially funded by Booking.com.
*
* HISTORY
*
* 10/12/13
* - pasted into vips source tree
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* This program uses the "classic" (pre-vips8) API of the VIPS
* library.
*/
#include <vips/vips.h>
/*
* Copyright 2011 Nicolas Robidoux, Adam Turcotte and John Cupitt. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY NICOLAS ROBIDOUX, ADAM TURCOTTE AND
* JOHN CUPITT ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NICOLAS ROBIDOUX AND ADAM TURCOTTE OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* COMPILING
*
* Provided you have installed libvips and its dependencies (this can
* be done by installing nip2 through your package manager, for
* example) and pkg-config is configured correctly (package managers
* generally do this for you), something like
*
* gcc -Wall -o cmyk2srgbjpeg cmyk2srgbjpeg.c \
* `pkg-config --libs --cflags vips`
*
* should work. This gcc call assumes that pkg-config can find
* vips. To find out the version(s) of the VIPS library that
* pkg-config sees:
*
* pkg-config --list-all | grep vips
*
* If you prefer to leave the code alone, you may use the gcc -D
* method of setting macro values instead of changing the values
* below.
*
* Because cmyk2srgbjpeg is a driver and as such does very little,
* there is little benefit to compiling it with "higher" optimisation
* flags (like "-march=native -O2", appropriate if you are compiling
* on the machine the code is to run on). If you want speed, compile
* the libvips library itself (and its main dependencies) with
* optimisation flags matched to your hardware. Better yet, install
* lcms2-dev so libvips can link to it (unlike its predecessor,
* lcms2-dev can convert in parallel).
*
* It is easy to add the capability to set VIPS runtime options to
* this program. Depending on the target use, this may make a have a
* big impact on speed and/or memory usage. As configured,
* cmyk2srgbjpeg program will use little RAM at the expense of more
* temporary disk space. Contact nicolas dot robidoux at gmail dot
* com for details.
*
* Note that the program may emit error messages, for example
*
* vips warning: im_icc_import: intent 1 (RELATIVE) not ...
* ... supported by profile; falling back to default intent ...
* ... (usually PERCEPTUAL)
*
* Such messages do not directly affect the return codes.
*/
////////////////////////////////////////////////////////////////////////////////
/* BEGINNING OF USER CONFIGURABLE #DEFINES */
////////////////////////////////////////////////////////////////////////////////
/*
* BACKSTOP CMYK ICC COLOUR PROFILE
*
* Path+name of a "Backstop" CMYK compatible ICC profile. It is used
* when an image detected to be CMYK is not found to have an embedded
* profile. You may specify a full path. Many nip2 installs put a
* usable one, namely HP5000_UVDuraImageGlossMaxQ.icc, in
* /usr/local/share/nip2/data/.
*
* (Put in double quotes: It is a string.)
*/
#ifndef CMYK2SRGBJPEG_BACKSTOP_CMYK_ICC
#define CMYK2SRGBJPEG_BACKSTOP_CMYK_ICC \
"/usr/local/share/nip2/data/HP5000_UVDuraImageGlossMaxQ.icc"
#endif
////////////////////////////////////////////////////////////////////////////////
/*
* SRGB ICM COLOUR PROFILE
*
* Path+name of sRGB.icm. Many nip2 installs put a copy in
* /usr/local/share/nip2/data/. Many ImageMagick installs put a copy
* in /usr/local/etc/ImageMagick/.
*
* (Put in double quotes: It is a string.)
*/
#ifndef CMYK2SRGBJPEG_SRGB_ICM
#define CMYK2SRGBJPEG_SRGB_ICM "/usr/local/share/nip2/data/sRGB.icm"
#endif
////////////////////////////////////////////////////////////////////////////////
/*
* RETURN CODES
*
* Modify to suit. They do not need to be different from each
* other. For example, you could set all but
* CMYK2SRGBJPEG_FATAL_ERROR to 0. Integers between 0 and 255 are
* generally considered safer (although -1 for fatal errors is
* somewhat traditional).
*
* The one return code identifier which is not self-explanatory is
* CMYK2SRGBJPEG_CMYK_WITH_UNUSABLE_ICC. This return code is issued
* when the program does not succeed in using an embedded ICC, but
* successfully converts the image with the backstop ICC.
*
* Look into things when CMYK2SRGBJPEG_FATAL_ERROR,
* CMYK2SRGBJPEG_CMYK_NO_ICC or CMYK2SRGBJPEG_CMYK_WITH_UNUSABLE_ICC
* are returned.
*/
/*
* Nothing was done (not detected as CMYK).
*/
#ifndef CMYK2SRGBJPEG_PROBABLY_NOT_CMYK
#define CMYK2SRGBJPEG_PROBABLY_NOT_CMYK 0
#endif
/*
* The program failed.
*/
#ifndef CMYK2SRGBJPEG_FATAL_ERROR
#define CMYK2SRGBJPEG_FATAL_ERROR 1
#endif
/*
* The program could not import with the embedded ICC profile, so the
* backstop profile was substituted.
*/
#ifndef CMYK2SRGBJPEG_CMYK_WITH_UNUSABLE_ICC
#define CMYK2SRGBJPEG_CMYK_WITH_UNUSABLE_ICC 2
#endif
/*
* No embedded ICC profile was detected, so the backstop profile was
* substituted.
*/
#ifndef CMYK2SRGBJPEG_CMYK_NO_ICC
#define CMYK2SRGBJPEG_CMYK_NO_ICC 3
#endif
/*
* Import was performed with the embedded ICC profile.
*/
#ifndef CMYK2SRGBJPEG_CMYK_WITH_USABLE_ICC
#define CMYK2SRGBJPEG_CMYK_WITH_USABLE_ICC 4
#endif
////////////////////////////////////////////////////////////////////////////////
/*
* JPEG QUALITY SETTING
*
* Set to an integer value between 0 and 100. 99 is basically as good
* as it gets. 95 should be good enough for natural images only shown
* at a fraction of their original size.
*/
#ifndef CMYK2SRGBJPEG_JPEG_QUALITY
#define CMYK2SRGBJPEG_JPEG_QUALITY 99
#endif
////////////////////////////////////////////////////////////////////////////////
/*
* JPEG EXTENSION USED WHEN SAVING TO DISK
*
* Must be recognised as a JPEG extension by VIPS. (A period is
* inserted before it, of course.)
*
* (Put in double quotes.)
*/
#ifndef CMYK2SRGBJPEG_JPEG_EXTENSION
#define CMYK2SRGBJPEG_JPEG_EXTENSION "jpg"
#endif
////////////////////////////////////////////////////////////////////////////////
/*
* COLOUR CONVERSION INTENT
*
* Use IM_INTENT_RELATIVE_COLORIMETRIC unless you know what you are
* doing or you visually check the results.
*/
#ifndef CMYK2SRGBJPEG_CONVERSION_INTENT
#define CMYK2SRGBJPEG_CONVERSION_INTENT IM_INTENT_RELATIVE_COLORIMETRIC
#endif
////////////////////////////////////////////////////////////////////////////////
/* END OF USER CONFIGURABLE #DEFINES */
////////////////////////////////////////////////////////////////////////////////
static int
cmyk2srgb( IMAGE *input_image, IMAGE *output_image )
{
int icc_profile_handling;
/*
* Does the input image have an embedded profile?
*/
if ( vips_image_get_typeof( input_image, "icc-profile-data" ) ) {
/*
* Yes. Try to import with the embedded ICC.
*/
/*
* Intermediate result image to import to and export from.
*/
IMAGE *t1;
if ( !( t1 = im_open_local( output_image, "intermediate", "p" ) )
||
( im_icc_import_embedded( input_image,
t1,
CMYK2SRGBJPEG_CONVERSION_INTENT ) )
||
( im_icc_export( t1,
output_image,
CMYK2SRGBJPEG_SRGB_ICM,
CMYK2SRGBJPEG_CONVERSION_INTENT ) ) ) {
/*
* Unsuccessful.
*/
icc_profile_handling = CMYK2SRGBJPEG_CMYK_WITH_UNUSABLE_ICC;
}
else {
/*
* The embedded ICC worked.
*/
return CMYK2SRGBJPEG_CMYK_WITH_USABLE_ICC;
}
}
else {
/*
* No embedded ICC.
*/
icc_profile_handling = CMYK2SRGBJPEG_CMYK_NO_ICC;
}
/*
* Import with the backstop ICC profile.
*/
if ( im_icc_transform( input_image,
output_image,
CMYK2SRGBJPEG_BACKSTOP_CMYK_ICC,
CMYK2SRGBJPEG_SRGB_ICM,
CMYK2SRGBJPEG_CONVERSION_INTENT ) ) {
return CMYK2SRGBJPEG_FATAL_ERROR;
}
return icc_profile_handling;
}
int
main( int argc, char **argv )
{
IMAGE *input_image;
int type;
/*
* Start up VIPS, check that there is only one argument (the
* input file), and open it as an image.
*/
if ( ( vips_init( argv[0] ) )
||
( argc != 3 )
||
( !( input_image = im_open( argv[1], "r" ) ) ) ) {
return CMYK2SRGBJPEG_FATAL_ERROR;
}
/*
* Read the type and only do something if the input image is CMYK
* (type 15).
*/
if ( ( !( vips_image_get_int( input_image, "Type", &type ) ) )
&&
( type == 15 ) ) {
/*
* Is OUTPUT_IMAGE_NAME_BEFORE_EXTENSION so long that we
* can't safely add a period, an extension and JPEG quality
* specifier (longest is ":100")?
*/
if ( strlen( argv[2] ) >
VIPS_PATH_MAX - ( strlen( CMYK2SRGBJPEG_JPEG_EXTENSION ) + 5 ) ) {
im_close( input_image );
return CMYK2SRGBJPEG_FATAL_ERROR;
}
/*
* Assemble the output filename from the second argument,
* adding a period, the extension, and the JPEG quality
* specifier.
*/
char output_filename[VIPS_PATH_MAX];
vips_snprintf( output_filename,
VIPS_PATH_MAX,
"%s.%s:%d",
argv[2],
CMYK2SRGBJPEG_JPEG_EXTENSION,
CMYK2SRGBJPEG_JPEG_QUALITY );
/*
* Open the output image.
*/
IMAGE *output_image;
if ( !( output_image = im_open( output_filename, "w" ) ) ) {
im_close( input_image );
return CMYK2SRGBJPEG_FATAL_ERROR;
}
/*
* The conversion occurs (or fails) here:
*/
const int return_code = cmyk2srgb( input_image, output_image );
im_close( output_image );
im_close( input_image );
return return_code;
}
/*
* Not detected as a CMYK image. Do nothing.
*/
im_close( input_image );
return CMYK2SRGBJPEG_PROBABLY_NOT_CMYK;
}