diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-09-01 13:56:46 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-09-01 13:56:46 +0200 |
commit | 22f703cab05b7cd368f4de9e03991b7664dc5022 (patch) | |
tree | 6f4d50beaa42328e24b1c6b56b6ec059e4ef21a5 /target/filmtarg.c |
Initial import of argyll version 1.5.1-8debian/1.5.1-8
Diffstat (limited to 'target/filmtarg.c')
-rw-r--r-- | target/filmtarg.c | 458 |
1 files changed, 458 insertions, 0 deletions
diff --git a/target/filmtarg.c b/target/filmtarg.c new file mode 100644 index 0000000..af341dd --- /dev/null +++ b/target/filmtarg.c @@ -0,0 +1,458 @@ +/* + * Argyll Color Correction System + * Film recorder chart generator module. + * + * Author: Neil Okamoto + * Date: 1/3/2001 + * + * Copyright 2001, DreamWorks LLC + * All rights reserved. + * + * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 :- + * see the License2.txt file for licencing details. + */ + +/* This program generates a set of TIFF images containing color test patches, + * given the .ti1 file specifying what the colors are. + * + * The output is designed to facilitate output on a 35mm motion picture film + * recorder such as those manufactured by Cineon, Celco, MGI, ARRI, etc. */ + +/* Description: + * + */ + +/* TTBD: + * + * - eliminate gamma hack -- do it correctly in targen. + * - write a proper description + * - multi-patch mosaics on a single tiff image + * - render text labels into images + */ + +#undef DEBUG + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#if defined(__IBMC__) +#include <float.h> +#endif +#include <string.h> +#include <sys/types.h> +#include <time.h> +#include <ctype.h> +#include "copyright.h" +#include "aconfig.h" +#include "cgats.h" +#include "randix.h" +#include "tiffio.h" + +#include <stdarg.h> +void error(char *fmt, ...), warning(char *fmt, ...), verbose(int level, char *fmt, ...); + +/* A color structure */ +/* This can hold all representations simultaniously */ +typedef struct { + int t; /* Tag */ +#define T_W 0x1 +#define T_RGB 0x2 +#define T_CMYK 0x4 + double gy; + double r,g,b; + double c,m,y,k; + char *id; /* Id string */ + char loc[5]; /* Location ID string */ +} col; + + +void +generate_tiffs( +char *basename, /* Base file name for output tiffs */ +col *cols, /* Array of colors to be put on target chart */ +int npat, /* Number of test targets needed */ +char *label, /* Per set label */ +int pw, int ph, /* Patch width and height */ +int rand, /* Randomise flag */ +int rstart, /* Starting index for random */ +int verb) /* Verbose flag */ +{ + randix *r = NULL; /* Random index order object */ + int ix; /* Patch index in target list */ + int i; /* Logical patch in target list */ + char slab[6]; /* Strip label */ + char fname[200]; /* File name */ + TIFF *tiff; /* TIFF file handle */ + unsigned short* scanline; /* scanline buffer */ + int x,y; /* position in TIFF image */ + + if (rand) + r = new_randix(npat, rstart); + + i = 0; + while (i < npat) { + + if (rand) + ix = r->next(r); /* Next pseudo random index */ + else + ix = i; + + sprintf(slab, "P%04d",i+1); + strcpy(cols[ix].loc, slab); + sprintf(fname, "%s.%04d.tiff", basename, i+1); + + if ((tiff = TIFFOpen(fname, "w")) == NULL) { + fprintf(stderr,"Failed to open output %s\n", fname); + exit(-1); + } + + if (!(scanline = (unsigned short*)malloc(3*sizeof(short)*pw))) { + fprintf(stderr,"Failed to malloc a scanline buffer\n"); + exit(-1); + } + + TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, pw); + TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, ph); + TIFFSetField(tiff, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 3); + TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 16); + TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_LZW); + + if (verb) { + printf("writing patch %4d (%4.2f %4.2f %4.2f) to %s\n", + ix, cols[ix].r, cols[ix].g, cols[ix].b, fname); + } + + /* fill scanline */ + for (x=0; x<pw; x++) { + int xx = 3*x; + scanline[xx++] = (unsigned short)((cols[ix].r * 65535.0) + 0.5); + scanline[xx++] = (unsigned short)((cols[ix].g * 65535.0) + 0.5); + scanline[xx] = (unsigned short)((cols[ix].b * 65535.0) + 0.5); + } + for (y=0; y<ph; y++) { + if (TIFFWriteScanline(tiff, (tdata_t)scanline, y, 0) < 0) { + fprintf(stderr,"WriteScanline Failed at line %d\n",y); + exit (-1); + } + } + TIFFClose(tiff); + free(scanline); + + i++; + } + + if (rand) + r->del(r); + +} + +/* film size structure */ +typedef struct { + char *name; /* User name (lower case) */ + int w,h; /* Width and height in pixels */ +} film; + +static film filmsizes[] = { + { "Acad_Full", 3656, 2664 }, + { "Acad_Half", 1828, 1332 }, + { "Cscope_Full", 3656, 3112 }, + { "Cscope_Half", 1828, 1556 }, + { "FullAp_Full", 4096, 3112 }, + { "FullAp_Half", 2048, 1556 }, + { "Vista_Full", 4096, 6144 }, + { "Vista_Half", 2048, 3072 }, + { NULL, 0, 0 } +}; + +/* Case independent string compare */ +int +cistrcmp(char *s1, char *s2) { + for (;;s1++, s2++) { + if (tolower(*s1) != tolower(*s2)) + return 1; + if (*s1 == '\000') + return 0; + } +} + +void +usage(void) { + film *ff; + fprintf(stderr,"Generate Film Target image sequence, Version %s\n",ARGYLL_VERSION_STR); + fprintf(stderr,"Licensed under the GPL\n"); + fprintf(stderr,"usage: filmtarg [-v] [-r] [-g gamma] [-f format] basename\n"); + fprintf(stderr," -v Verbose mode\n"); + fprintf(stderr," -r Don't randomise patch location\n"); + fprintf(stderr," -g gamma Gamma correction / linearization\n"); + fprintf(stderr," -f format Select format from:\n"); + for (ff = filmsizes; ff->name != NULL; ff++) + fprintf(stderr," \t%s\t[%d x %d]\n", ff->name, ff->w, ff->h); + fprintf(stderr," basename Base name for input(.ti1)/output(.ti2)\n"); + exit(1); +} + + +int +main(argc,argv) +int argc; +char *argv[]; +{ + int fa,nfa; /* current argument we're looking at */ + int verb = 0; + int rand = 1; + double gamma = 1.0; + static char inname[200] = { 0 }; /* Input cgats file base name */ + static char outname[200] = { 0 }; /* Output cgats file base name */ + static char tiffname[200] = { 0 }; /* Output postscrip file base name */ + cgats *icg; /* input cgats structure */ + cgats *ocg; /* output cgats structure */ + int i; + int si, fi, wi; /* sample id index, field index, keyWord index */ + char *label = "Argyll Color Correction System - Development chart"; + film *flm = &filmsizes[1]; /* Default film format = Academy Half */ + col *cols; + int npat; /* Number of patches */ + time_t clk = time(0); + struct tm *tsp = localtime(&clk); + char *atm = asctime(tsp); /* Ascii time */ + char buf[100]; /* general sprintf buffer */ + int rstart = 0; /* Random sequence start value */ + +#if defined(__IBMC__) + _control87(EM_UNDERFLOW, EM_UNDERFLOW); + _control87(EM_OVERFLOW, EM_OVERFLOW); +#endif + + if (argc <= 1) + 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; + /* Randomisation */ + else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') + rand = 0; + /* Gamma */ + else if (argv[fa][1] == 'g' || argv[fa][1] == 'G') { + fa = nfa; + if (na == NULL) usage(); + gamma = atof(na); + } + /* Image format */ + else if (argv[fa][1] == 'f' || argv[fa][1] == 'F') { + fa = nfa; + if (na == NULL) usage(); + for (flm = filmsizes; flm->name != NULL; flm++) { + if (cistrcmp(na, flm->name) == 0) + break; + } + if (flm->name == NULL) + usage(); + } else + usage(); + } + else + break; + } + + /* Get the file name argument */ + if (fa >= argc || argv[fa][0] == '-') usage(); + strcpy(inname,argv[fa]); + strcat(inname,".ti1"); + strcpy(outname,argv[fa]); + strcat(outname,".ti2"); + strcpy(tiffname,argv[fa]); + + icg = new_cgats(); /* Create a CGATS structure */ + icg->add_other(icg, "CTI1"); /* our special input type is Calibration Target Information 1 */ + + if (icg->read_name(icg, inname)) + error("CGATS file read error : %s",icg->err); + + if (icg->t[0].tt != tt_other || icg->t[0].oi != 0) + error ("Input file isn't a CTI1 format file"); + if (icg->ntables < 1) + error ("Input file doesn't contain at least one table"); + + if ((npat = icg->t[0].nsets) <= 0) + error ("No sets of data"); + + if ((cols = (col *)malloc(sizeof(col) * npat)) == NULL) + error("Malloc failed!"); + + /* Setup output cgats file */ + ocg = new_cgats(); /* Create a CGATS structure */ + ocg->add_other(ocg, "CTI2"); /* our special type is Calibration Target Information 2 */ + ocg->add_table(ocg, tt_other, 0); /* Start the first table */ + + ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 2",NULL); + ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll filmtarg", NULL); + atm[strlen(atm)-1] = '\000'; /* Remove \n from end */ + ocg->add_kword(ocg, 0, "CREATED",atm, NULL); + + /* Note what instrument this chart is setup for */ + ocg->add_kword(ocg, 0, "TARGET_INSTRUMENT", "GretagMacbeth SpectroScanT", NULL); + + /* Copy various parameters through */ + if ((wi = icg->find_kword(icg, 0, "SINGLE_DIM_STEPS")) >= 0) + ocg->add_kword(ocg, 0, "SINGLE_DIM_STEPS",icg->t[0].kdata[wi], NULL); + + if ((wi = icg->find_kword(icg, 0, "COMP_GREY_STEPS")) >= 0) + ocg->add_kword(ocg, 0, "COMP_GREY_STEPS",icg->t[0].kdata[wi], NULL); + + if ((wi = icg->find_kword(icg, 0, "MULTI_DIM_STEPS")) >= 0) + ocg->add_kword(ocg, 0, "MULTI_DIM_STEPS",icg->t[0].kdata[wi], NULL); + + if ((wi = icg->find_kword(icg, 0, "FULL_SPREAD_PATCHES")) >= 0) + ocg->add_kword(ocg, 0, "FULL_SPREAD_PATCHES",icg->t[0].kdata[wi], NULL); + + + /* Fields we want */ + ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t); + ocg->add_field(ocg, 0, "SAMPLE_LOC", cs_t); + + if ((si = icg->find_field(icg, 0, "SAMPLE_ID")) < 0) + error ("Input file doesn't contain field SAMPLE_ID"); + if (icg->t[0].ftype[si] != nqcs_t) + error ("Field SAMPLE_ID is wrong type"); + + /* Figure out the color space */ + if ((fi = icg->find_kword(icg, 0, "COLOR_REP")) < 0) + error ("Input file doesn't contain keyword COLOR_REPS"); + if (strcmp(icg->t[0].kdata[fi],"CMYK") == 0) { + error ("We don't support CMYK yet"); + } else if (strcmp(icg->t[0].kdata[fi],"RGB") == 0) { + int ri, gi, bi; + if ((ri = icg->find_field(icg, 0, "RGB_R")) < 0) + error ("Input file doesn't contain field RGB_R"); + if (icg->t[0].ftype[ri] != r_t) + error ("Field RGB_R is wrong type"); + if ((gi = icg->find_field(icg, 0, "RGB_G")) < 0) + error ("Input file doesn't contain field RGB_G"); + if (icg->t[0].ftype[gi] != r_t) + error ("Field RGB_G is wrong type"); + if ((bi = icg->find_field(icg, 0, "RGB_B")) < 0) + error ("Input file doesn't contain field RGB_B"); + if (icg->t[0].ftype[bi] != r_t) + error ("Field RGB_B is wrong type"); + ocg->add_field(ocg, 0, "RGB_R", r_t); + ocg->add_field(ocg, 0, "RGB_G", r_t); + ocg->add_field(ocg, 0, "RGB_B", r_t); + ocg->add_kword(ocg, 0, "COLOR_REP","RGB", NULL); + if (gamma != 1.0) { + sprintf(buf, "%6.4f", gamma); + ocg->add_kword(ocg, 0, "GAMMA", buf, NULL); + } + for (i = 0; i < npat; i++) { + cols[i].t = T_RGB; + cols[i].id = ((char *)icg->t[0].fdata[i][si]); + /* normalized and possibly gamma corrected */ + cols[i].r = pow(*((double *)icg->t[0].fdata[i][ri]) / 100.0, gamma); + cols[i].g = pow(*((double *)icg->t[0].fdata[i][gi]) / 100.0, gamma); + cols[i].b = pow(*((double *)icg->t[0].fdata[i][bi]) / 100.0, gamma); + } + } else if (strcmp(icg->t[0].kdata[fi],"W") == 0) { + error ("We don't support GRAY yet"); + } else + error ("Input file keyword COLOR_REPS has unknown value"); + + + if (verb) + printf("Film format chosen is %s [%d x %d]\n", flm->name, flm->w, flm->h); + + if (rand) { + rstart = clk % npat; + sprintf(buf,"%d",rstart); + ocg->add_kword(ocg, 0, "RANDOM_START", buf, NULL); + } + + generate_tiffs(tiffname, cols, npat, label, flm->w, flm->h, rand, rstart, verb); + + /* Write out the patch info to the output CGATS file */ + for (i = 0; i < npat; i++) { + if (cols[i].t & T_CMYK) + ocg->add_set(ocg, 0, cols[i].id, cols[i].loc, 100.0 * cols[i].c, 100.0 * cols[i].m, + 100.0 * cols[i].y, 100.0 * cols[i].k); + else if (cols[i].t & T_RGB) + ocg->add_set(ocg, 0, cols[i].id, cols[i].loc, 100.0 * cols[i].r, + 100.0 * cols[i].g, 100.0 * cols[i].b); + else if (cols[i].t & T_W) + ocg->add_set(ocg, 0, cols[i].id, cols[i].loc, 100.0 * cols[i].gy); + } + + if (ocg->write_name(ocg, outname)) + error("Write error : %s",ocg->err); + + free(cols); + ocg->del(ocg); /* Clean up */ + icg->del(icg); /* Clean up */ + + return 0; +} + +/******************************************************************/ +/* Error/debug output routines */ +/******************************************************************/ + + +/* Basic printf type error() and warning() routines */ + +void +error(char *fmt, ...) +{ + va_list args; + + fprintf(stderr,"filmtarg: 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,"filmtarg: Warning - "); + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr, "\n"); +} + + + + + + + |