Files
2026-08-20 20:28:40 +01:00

226 lines
5.6 KiB
C

/*
* Extract an ICC profile from a TIFF file.
*
* Author: Graeme W. Gill
* Date: 2008/5/18
* Version: 1.00
*
* Copyright 2008 Graeme W. Gill
* All rights reserved.
* This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
* see the License.txt file for licencing details.
*/
/*
* TTBD:
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h>
#include <setjmp.h>
#include <string.h>
#include <math.h>
#include "numlib.h"
#include "tiffio.h"
#include "jpeglib.h"
#include "iccjpeg.h"
#include "copyright.h"
#include "aconfig.h"
#include "icc.h"
void usage(char *diag, ...) {
int i;
fprintf(stderr,"Extract an ICC profile from a TIFF or JPEG file, Version %s\n",ARGYLL_VERSION_STR);
fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
if (diag != NULL) {
va_list args;
fprintf(stderr,"Diagnostic: ");
va_start(args, diag);
vfprintf(stderr, diag, args);
va_end(args);
fprintf(stderr,"\n");
}
fprintf(stderr,"usage: extracticc [-v] infile.tif/jpg outfile%s\n",ICC_FILE_EXT);
fprintf(stderr," -v Verbose\n");
exit(1);
}
/* ------------------------------------------------------ */
/* JPEG error information */
typedef struct {
jmp_buf env; /* setjmp/longjmp environment */
char message[JMSG_LENGTH_MAX];
} jpegerrorinfo;
/* JPEG error handler */
static void jpeg_error(j_common_ptr cinfo) {
jpegerrorinfo *p = (jpegerrorinfo *)cinfo->client_data;
(*cinfo->err->format_message) (cinfo, p->message);
longjmp(p->env, 1);
}
/* ------------------------------------------------------ */
int
main(int argc, char *argv[]) {
int fa,nfa; /* argument we're looking at */
static char in_name[MAXNAMEL+1]; /* TIFF input name */
static char out_name[MAXNAMEL+1]; /* ICC output name */
int verb = 0;
TIFFErrorHandler olderrh, oldwarnh;
TIFFErrorHandlerExt olderrhx, oldwarnhx;
TIFF *rh;
int size = 0;
void *buf = NULL;
icmFile *fp;
icmErr err = { 0, { '\000'} };
int rv = 0;
error_program = argv[0];
if (argc < 3)
usage("Too few parameters");
/* Process the arguments */
for (fa = 1;fa < argc;fa++) {
nfa = fa; /* skip to nfa if next argument is used */
if (argv[fa][0] == '-') { /* Look for any flags */
char *na = NULL; /* next argument after flag, null if none */
if (argv[fa][2] != '\000')
na = &argv[fa][2]; /* next is directly after flag */
else {
if ((fa+1) < argc) {
if (argv[fa+1][0] != '-') {
nfa = fa + 1;
na = argv[nfa]; /* next is seperate non-flag argument */
}
}
}
if (argv[fa][1] == '?')
usage(NULL);
/* Verbosity */
else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
verb = 1;
}
else
usage("Unknown flag '%c'",argv[fa][1]);
} else
break;
}
if (fa >= argc || argv[fa][0] == '-') usage("Missing input TIFF file");
strncpy(in_name,argv[fa++],MAXNAMEL); in_name[MAXNAMEL] = '\000';
if (fa >= argc || argv[fa][0] == '-') usage("Missing output ICC profile");
strncpy(out_name,argv[fa++],MAXNAMEL); out_name[MAXNAMEL] = '\000';
/* - - - - - - - - - - - - - - - */
/* Open up input tiff file ready for reading */
/* Got arguments, so setup to process the file */
olderrh = TIFFSetErrorHandler(NULL);
oldwarnh = TIFFSetWarningHandler(NULL);
olderrhx = TIFFSetErrorHandlerExt(NULL);
oldwarnhx = TIFFSetWarningHandlerExt(NULL);
if ((rh = TIFFOpen(in_name, "r")) != NULL) {
TIFFSetErrorHandler(olderrh);
TIFFSetWarningHandler(oldwarnh);
TIFFSetErrorHandlerExt(olderrhx);
TIFFSetWarningHandlerExt(oldwarnhx);
if (TIFFGetField(rh, TIFFTAG_ICCPROFILE, &size, &buf) == 0 || size == 0) {
error("unable to find ICC profile tag in TIFF file '%s'",in_name);
}
if ((fp = new_icmFileStd_name(&err,out_name, "w")) == NULL) {
error("unable to open output ICC profile '%s' (0x%x, '%s')",out_name,err.c,err.m);
}
if (fp->write(fp, buf, 1, size) != size) {
error("error writing file '%s'",out_name);
}
if (fp->del(fp) != 0) {
error("error closing file '%s'",out_name);
}
TIFFClose(rh); /* Close Input file and free field buffer */
} else {
jpegerrorinfo jpeg_rerr;
FILE *rf = NULL;
struct jpeg_decompress_struct rj;
struct jpeg_error_mgr jerr;
TIFFSetErrorHandler(olderrh);
TIFFSetWarningHandler(oldwarnh);
TIFFSetErrorHandlerExt(olderrhx);
TIFFSetWarningHandlerExt(oldwarnhx);
/* We cope with the horrible ijg jpeg library error handling */
/* by using a setjmp/longjmp. */
jpeg_std_error(&jerr);
jerr.error_exit = jpeg_error;
if (setjmp(jpeg_rerr.env)) {
jpeg_destroy_decompress(&rj);
fclose(rf);
error("error opening read file '%s'",in_name);
}
rj.err = &jerr;
rj.client_data = &jpeg_rerr;
jpeg_create_decompress(&rj);
#if defined(O_BINARY) || defined(_O_BINARY)
if ((rf = fopen(in_name,"rb")) == NULL)
#else
if ((rf = fopen(in_name,"r")) == NULL)
#endif
{
jpeg_destroy_decompress(&rj);
error("error opening read file '%s'",in_name);
}
jpeg_stdio_src(&rj, rf);
setup_read_icc_profile(&rj);
/* we'll longjmp on error */
jpeg_read_header(&rj, TRUE);
if (!read_icc_profile(&rj, (unsigned char **)&buf, (unsigned int *)&size)) {
jpeg_destroy_decompress(&rj);
fclose(rf);
error("unable to find ICC profile marker in JPEG file '%s'",in_name);
}
jpeg_destroy_decompress(&rj);
fclose(rf);
if ((fp = new_icmFileStd_name(&err,out_name, "w")) == NULL) {
error("unable to open output ICC profile '%s' (0x%x, '%s')",out_name,err.c,err.m);
}
if (fp->write(fp, buf, 1, size) != size) {
error("error writing file '%s'",out_name);
}
if (fp->del(fp) != 0) {
error("error closing file '%s'",out_name);
}
free(buf);
}
return 0;
}