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

353 lines
9.2 KiB
C

/*
* Create an ICC V2.4 compatible matrix display profile.
*
* Author: Graeme W. Gill
* Date: 8/2/2008
* Version: 1.00
*
* Copyright 2006 - 2014 Graeme W. Gill
*
* This material is licensed with an "MIT" free use license:-
* see the License4.txt file in this directory for licensing details.
*
* Based on icc/lutest.c
*/
/*
* TTBD:
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include "icc.h"
void error(char *fmt, ...), warning(char *fmt, ...);
void usage(void) {
fprintf(stderr,"Create a Matrix Display ICC profile\n");
fprintf(stderr,"Author: Graeme W. Gill\n");
fprintf(stderr,"usage: mkDispProf [-v level] outfile\n");
fprintf(stderr," -v Verbose\n");
exit(1);
}
/* sRGB like device gamma encoded value to linear value 0.0 .. 1.0 */
static double gdv2dv(double iv) {
double ov;
if (iv < 0.04045)
ov = iv/12.92;
else
ov = pow((iv + 0.055)/1.055, 2.4);
return ov;
}
int
main(
int argc,
char *argv[]
) {
int fa,nfa;
icmErr e = { 0, { '\000'} };
char out_name[1000];
icmFile *wr_fp;
icc *wr_icco;
int rv = 0;
int verb = 0;
if (argc < 2)
usage();
/* 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();
/* Verbosity */
else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
verb = 1;
}
else
usage();
}
else
break;
}
if (fa >= argc || argv[fa][0] == '-') usage();
strcpy(out_name,argv[fa]);
/* ---------------------------------------- */
/* Create a matrix/shaper based XYZ profile */
/* ---------------------------------------- */
icm_err_clear_e(&e);
/* Open up the file for writing */
if ((wr_fp = new_icmFileStd_name(&e, out_name,"w")) == NULL)
error ("Write: Can't open file '%s', failed with 0x%x, '%s'",out_name,e.c, e.m);
if ((wr_icco = new_icc(&e)) == NULL)
error ("Write: Creation of ICC object failed with 0x%x, '%s'",e.c, e.m);
/* Add all the tags required */
/* The header: */
{
icmHeader *wh = wr_icco->header;
/* Values that must be set before writing */
wh->deviceClass = icSigDisplayClass;
wh->colorSpace = icSigRgbData; /* It's RGB space */
wh->pcs = icSigXYZData;
wh->renderingIntent = icPerceptual;
/* Values that should be set before writing */
wh->manufacturer = icmstr2tag("????");
wh->model = icmstr2tag("????");
}
/* Profile Description Tag: */
{
icmCommonTextDescription *wo;
char *dst;
dst = "sRGB like Matrix Display profile";
if ((wo = (icmCommonTextDescription *)wr_icco->add_tag(
wr_icco, icSigProfileDescriptionTag, icmSigCommonTextDescriptionType)) == NULL)
error("add_tag failed: %d, %s",wr_icco->e.c,wr_icco->e.m);
wo->count = strlen(dst)+1; /* Allocated and used size of desc, inc null */
wo->allocate(wo);/* Allocate space */
strcpy(wo->desc, dst); /* Copy the string in */
}
/* Copyright Tag: */
{
icmCommonTextDescription *wo;
char *crt = "Copyright tag goes here";
if ((wo = (icmCommonTextDescription *)wr_icco->add_tag(
wr_icco, icSigCopyrightTag, icmSigCommonTextDescriptionType)) == NULL)
error("add_tag failed: %d, %s",wr_icco->e.c,wr_icco->e.m);
wo->count = strlen(crt)+1; /* Allocated and used size of text, inc null */
wo->allocate(wo);/* Allocate space */
strcpy(wo->desc, crt); /* Copy the text in */
}
/* Could add other relevant tags here, such as:
Device Manufacturers Description Tag
Device Model Description Tag
Device technology Tag
Viewing conditions Description Tag
Viewing conditions
Display Luminance Tag
Measurement information Tag
etc.
*/
/* Setup the primaries */
{
/* Compute primaries as XYZ */
double wrgb[4][3] = { /* Primaries in Yxy from the standard */
{ 1.0, 0.3127, 0.3290 }, /* White */
{ 1.0, 0.6400, 0.3300 }, /* Red */
{ 1.0, 0.3000, 0.6000 }, /* Green */
{ 1.0, 0.1500, 0.0600 } /* Blue */
};
double mat[3][3];
int i;
/* Convert yxy to normalised 3x3 matrix */
icmRGBYxyprim2matrix(wrgb[1], wrgb[2], wrgb[3], wrgb[0], mat, wrgb[0]);
icmTranspose3x3(mat, mat);
#ifdef NEVER /* Dump XYZ */
printf("sRGB: XYZ\n");
printf("{ %f, %f, %f }, /* Red */\n"
"{ %f, %f, %f }, /* Green */\n"
"{ %f, %f, %f }, /* Blue */\n"
"{ %f, %f, %f } /* White */\n",
mat[0][0], mat[0][1], mat[0][2],
mat[1][0], mat[1][1], mat[1][2],
mat[2][0], mat[2][1], mat[2][2],
wrgb[0][0], wrgb[0][1], wrgb[0][2]);
#endif
#ifdef NEVER /* Dump xyz */
{
double mat2[4][3];
double tt;
for (i = 0; i < 3; i++) {
tt = mat[i][0] + mat[i][1] + mat[i][2];
mat2[i][0] = mat[i][0] / tt;
mat2[i][1] = mat[i][1] / tt;
mat2[i][2] = mat[i][2] / tt;
}
tt = wrgb[0][0] + wrgb[0][1] + wrgb[0][2];
mat2[i][0] = wrgb[0][0] / tt;
mat2[i][1] = wrgb[0][1] / tt;
mat2[i][2] = wrgb[0][2] / tt;
printf("sRGB: xyz\n");
printf("{ %f, %f, %f }, /* Red */\n"
"{ %f, %f, %f }, /* Green */\n"
"{ %f, %f, %f }, /* Blue */\n"
"{ %f, %f, %f } /* White */\n",
mat2[0][0], mat2[0][1], mat2[0][2],
mat2[1][0], mat2[1][1], mat2[1][2],
mat2[2][0], mat2[2][1], mat2[2][2],
mat2[3][0], mat2[3][1], mat2[3][2]);
}
#endif
/* White Point Tag: */
{
icmXYZArray *wo;
if ((wo = (icmXYZArray *)wr_icco->add_tag(
wr_icco, icSigMediaWhitePointTag, icSigXYZArrayType)) == NULL)
error("add_tag failed: %d, %s",wr_icco->e.c,wr_icco->e.m);
wo->count = 1;
wo->allocate(wo); /* Allocate space */
wo->data[0].X = wrgb[0][0];
wo->data[0].Y = wrgb[0][1];
wo->data[0].Z = wrgb[0][2];
}
/* Black Point Tag: */
{
icmXYZArray *wo;
if ((wo = (icmXYZArray *)wr_icco->add_tag(
wr_icco, icSigMediaBlackPointTag, icSigXYZArrayType)) == NULL)
error("add_tag failed: %d, %s",wr_icco->e.c,wr_icco->e.m);
wo->count = 1;
wo->allocate(wo); /* Allocate space */
wo->data[0].X = 0.00;
wo->data[0].Y = 0.00;
wo->data[0].Z = 0.00;
}
/* Red, Green and Blue Colorant Tags: */
{
icmXYZNumber white;
icmXYZArray *wor, *wog, *wob;
double fromAbs[3][3];
double d50m[3][3];
/* Convert to D50 adapated */
icmAry2XYZ(white, wrgb[0]);
wr_icco->chromAdaptMatrix(wr_icco, ICM_CAM_NONE, NULL, fromAbs, icmD50, white);
icmMulBy3x3(d50m[0], fromAbs, mat[0]);
icmMulBy3x3(d50m[1], fromAbs, mat[1]);
icmMulBy3x3(d50m[2], fromAbs, mat[2]);
/* Make sure rounding doesn't wreck white point */
quantizeRGBprimsS15Fixed16(d50m);
if ((wor = (icmXYZArray *)wr_icco->add_tag(
wr_icco, icSigRedColorantTag, icSigXYZArrayType)) == NULL)
error("add_tag failed: %d, %s",rv,wr_icco->e.m);
if ((wog = (icmXYZArray *)wr_icco->add_tag(
wr_icco, icSigGreenColorantTag, icSigXYZArrayType)) == NULL)
error("add_tag failed: %d, %s",rv,wr_icco->e.m);
if ((wob = (icmXYZArray *)wr_icco->add_tag(
wr_icco, icSigBlueColorantTag, icSigXYZArrayType)) == NULL)
error("add_tag failed: %d, %s",rv,wr_icco->e.m);
wor->count = wog->count = wob->count = 1;
wor->allocate(wor); /* Allocate space */
wog->allocate(wog);
wob->allocate(wob);
wor->data[0].X = d50m[0][0]; wor->data[0].Y = d50m[0][1]; wor->data[0].Z = d50m[0][2];
wog->data[0].X = d50m[1][0]; wog->data[0].Y = d50m[1][1]; wog->data[0].Z = d50m[1][2];
wob->data[0].X = d50m[2][0]; wob->data[0].Y = d50m[2][1]; wob->data[0].Z = d50m[2][2];
}
}
/* Red, Green and Blue Gamma Curve Tags: */
{
icmCurve *wor, *wog, *wob;
int i;
if ((wor = (icmCurve *)wr_icco->add_tag(
wr_icco, icSigRedTRCTag, icSigCurveType)) == NULL)
error("add_tag failed: %d, %s",rv,wr_icco->e.m);
wor->ctype = icmCurveSpec;
wor->count = 1024;
wor->allocate(wor); /* Allocate space */
for (i = 0; i < wor->count; i++)
wor->data[i] = gdv2dv(i/(wor->count-1.0));
/* Link other channels to the red */
if ((wog = (icmCurve *)wr_icco->link_tag(
wr_icco, icSigGreenTRCTag, icSigRedTRCTag)) == NULL)
error("link_tag failed: %d, %s",rv,wr_icco->e.m);
if ((wob = (icmCurve *)wr_icco->link_tag(
wr_icco, icSigBlueTRCTag, icSigRedTRCTag)) == NULL)
error("link_tag failed: %d, %s",rv,wr_icco->e.m);
}
/* Write the file out */
if ((rv = wr_icco->write(wr_icco,wr_fp,0)) != 0)
error ("Write file: %d, %s",rv,wr_icco->e.m);
wr_icco->del(wr_icco);
wr_fp->del(wr_fp);
return 0;
}
/* ------------------------------------------------ */
/* Basic printf type error() and warning() routines */
void
error(char *fmt, ...) {
va_list args;
fprintf(stderr,"mkDispProf: Error - ");
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "\n");
exit (-1);
}
void
warning(char *fmt, ...) {
va_list args;
fprintf(stderr,"mkDispProf: Warning - ");
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "\n");
}