536 lines
15 KiB
C
536 lines
15 KiB
C
|
|
/*
|
|
* Create a synthetic .ti3 file for a CMY "device",
|
|
* that exactly maps to the surface points and neutral
|
|
* axis of the CMYK profile it is derived from.
|
|
*
|
|
* Author: Graeme W. Gill
|
|
* Date: 2004/6/27
|
|
* Version: 1.00
|
|
*
|
|
* Copyright 2004 Graeme W. Gill
|
|
* Please refer to License.txt file for details.
|
|
*/
|
|
|
|
/* TTBD:
|
|
*
|
|
* Add a flag to create RGB instead, by simply inverting the CMY values
|
|
* when writing to the .ti3 file.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include "copyright.h"
|
|
#include "aconfig.h"
|
|
#include "numlib.h"
|
|
#include "icc.h"
|
|
#include "conv.h"
|
|
#include "xicc.h"
|
|
#include "cgats.h"
|
|
#include "targen.h"
|
|
|
|
#define EXTRA_NEUTRAL 50 /* Crude way of increasing weighting */
|
|
|
|
/* ---------------------------------------- */
|
|
|
|
void usage(char *diag) {
|
|
fprintf(stderr,"Create a fake CMY data file from a CMYK profile, Version %s\n",ARGYLL_VERSION_STR);
|
|
fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
|
|
fprintf(stderr,"usage: fakeCMY [option] profile.icm fake.ti3\n");
|
|
if (diag != NULL)
|
|
fprintf(stderr,"Diagnostic: %s\n",diag);
|
|
fprintf(stderr," -v verbose\n");
|
|
fprintf(stderr," -r res set surface point resolution (default 3)\n");
|
|
fprintf(stderr," -l tlimit set total ink limit, 0 - 400%% (estimate by default)\n");
|
|
fprintf(stderr," -L klimit set black ink limit, 0 - 100%% (estimate by default)\n");
|
|
fprintf(stderr," -g output fake RGB values instead of CMY\n");
|
|
fprintf(stderr,"profile%s CMYK ICC input profile to use\n",ICC_FILE_EXT);
|
|
fprintf(stderr,"outfile.ti3 Name for output .ti3 file\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* Fake up a vector direction clip in Lab space */
|
|
static void visect(
|
|
icxLuBase *luo, /* xicc lookup object */
|
|
double *pout, /* PCS result (may be NULL) */
|
|
double *dout, /* Device result (may be NULL) */
|
|
double *orig, /* Origin of vector (PCS) */
|
|
double *vec /* Input vector (PCS) */
|
|
) {
|
|
int i;
|
|
int rv;
|
|
double sum, step, inc[3]; /* 1 Delta E increment */
|
|
double try[3]; /* Trial PCS */
|
|
double res[4]; /* Trial result device values */
|
|
|
|
for (sum = 0.0, i = 0; i < 3; i++) {
|
|
double tt = vec[i] - orig[i];
|
|
sum += tt * tt;
|
|
}
|
|
sum = sqrt(sum);
|
|
for (i = 0; i < 3; i++) {
|
|
inc[i] = (vec[i] - orig[i])/sum;
|
|
}
|
|
//printf("~1 orig %f %f %f, vec %f %f %f\n",orig[0],orig[1],orig[2],vec[0],vec[1],vec[3]);
|
|
//printf("~1 inc %f %f %f\n",inc[0],inc[1],inc[2]);
|
|
|
|
/* Increment in vector direction until we clip */
|
|
for (i = 0; i < 3; i++)
|
|
try[i] = 0.5 * (orig[i] + vec[i]);
|
|
|
|
for (step = 20.0;;) {
|
|
rv = luo->inv_lookup(luo, res, try);
|
|
if (rv > 1)
|
|
error ("inv_lookup failed");
|
|
//printf("~1 trial %f %f %f returned %d\n",try[0],try[1],try[2],rv);
|
|
if (rv == 1) {
|
|
if (step <= 0.1)
|
|
break;
|
|
/* Back off, and use smaller steps */
|
|
for (i = 0; i < 3; i++)
|
|
try[i] -= step * inc[i];
|
|
step *= 0.5;
|
|
}
|
|
for (i = 0; i < 3; i++)
|
|
try[i] += step * inc[i];
|
|
}
|
|
|
|
if (dout != NULL)
|
|
for (i = 0; i < 3; i++)
|
|
dout[i] = res[i];
|
|
|
|
/* Lookup the clipped PCS */
|
|
if (pout != NULL)
|
|
luo->lookup(luo, pout, res);
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
int fa,nfa; /* argument we're looking at */
|
|
int verb = 0;
|
|
int dorgb = 0; /* Create fake RGB values */
|
|
double tlimit = -1.0; /* Total ink limit */
|
|
double klimit = -1.0; /* Black ink limit */
|
|
int tres = 3; /* Resolution of suface grid */
|
|
int gres = tres+2; /* Resolution of grey points */
|
|
static char in_name[MAXNAMEL+1];
|
|
static char out_name[MAXNAMEL+1];
|
|
icmFile *rd_fp;
|
|
icc *rd_icco;
|
|
icmErr err = { 0, { '\000'} };
|
|
int rv = 0;
|
|
icColorSpaceSignature ins, outs; /* Type of input and output spaces */
|
|
xicc *xicco;
|
|
icxLuBase *luo;
|
|
icxInk ink; /* Ink parameters */
|
|
fxpos *fxlist = NULL; /* Fixed point list for full spread */
|
|
int fxlist_a = 0; /* Fixed point list allocation */
|
|
int fxno = 0; /* The number of fixed points */
|
|
int gc[MXTD]; /* Grid coordinate */
|
|
|
|
cgats *ocg; /* output cgats structure */
|
|
time_t clk = time(0);
|
|
struct tm *tsp = localtime(&clk);
|
|
char *atm = asctime(tsp); /* Ascii time */
|
|
int i, j;
|
|
|
|
|
|
error_program = argv[0];
|
|
|
|
if (argc < 2)
|
|
usage("Not enough arguments");
|
|
|
|
/* 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 */
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Verbosity */
|
|
if (argv[fa][1] == 'v') {
|
|
verb = 1;
|
|
}
|
|
|
|
/* Ink limits */
|
|
else if (argv[fa][1] == 'l') {
|
|
fa = nfa;
|
|
if (na == NULL) usage("No parameter after flag -l");
|
|
tlimit = atoi(na)/100.0;
|
|
}
|
|
|
|
else if (argv[fa][1] == 'L') {
|
|
fa = nfa;
|
|
if (na == NULL) usage("No parameter after flag -L");
|
|
klimit = atoi(na)/100.0;
|
|
}
|
|
|
|
/* Resolution */
|
|
else if (argv[fa][1] == 'r') {
|
|
fa = nfa;
|
|
if (na == NULL) usage("No parameter after flag -r");
|
|
tres = atoi(na);
|
|
}
|
|
|
|
/* RGB ? */
|
|
else if (argv[fa][1] == 'g') {
|
|
dorgb = 1;
|
|
}
|
|
|
|
else if (argv[fa][1] == '?')
|
|
usage(NULL);
|
|
else
|
|
usage("Unknown flag");
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (fa >= argc || argv[fa][0] == '-') usage("Expected input profile name");
|
|
strncpy(in_name,argv[fa++],MAXNAMEL); in_name[MAXNAMEL] = '\000';
|
|
|
|
if (fa >= argc || argv[fa][0] == '-') usage("Expected output .ti3 name");
|
|
strncpy(out_name,argv[fa++],MAXNAMEL); out_name[MAXNAMEL] = '\000';
|
|
|
|
|
|
/* Open up the file for reading */
|
|
if ((rd_fp = new_icmFileStd_name(&err,in_name,"r")) == NULL)
|
|
error ("Read: Can't open file '%s' (0x%x, '%s')",in_name,err.c,err.m);
|
|
|
|
if ((rd_icco = new_icc(&err)) == NULL)
|
|
error ("Read: Creation of ICC object failed (0x%x, '%s')",err.c,err.m);
|
|
|
|
/* Read the header and tag list */
|
|
if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
|
|
error ("Read: %d, %s",rv,rd_icco->e.m);
|
|
|
|
|
|
/* Wrap with an expanded icc */
|
|
if ((xicco = new_xicc(rd_icco)) == NULL)
|
|
error ("Creation of xicc failed");
|
|
|
|
/* Setup ink limit */
|
|
|
|
/* Set the default ink limits if not set on command line */
|
|
icxDefaultLimits(xicco, &ink.tlimit, tlimit, &ink.klimit, klimit);
|
|
|
|
if (verb) {
|
|
if (ink.tlimit >= 0.0)
|
|
printf("Total ink limit assumed is %3.0f%%\n",100.0 * ink.tlimit);
|
|
if (ink.klimit >= 0.0)
|
|
printf("Black ink limit assumed is %3.0f%%\n",100.0 * ink.klimit);
|
|
}
|
|
|
|
ink.c.Ksmth = ICXINKDEFSMTH; /* Default smoothing */
|
|
ink.c.Kskew = ICXINKDEFSKEW; /* default curve skew */
|
|
ink.c.Kstle = 0.5; /* Min K at white end */
|
|
ink.c.Kstpo = 0.5; /* Start of transition is at white */
|
|
ink.c.Kenle = 0.5; /* Max K at black end */
|
|
ink.c.Kenpo = 0.5; /* End transition at black */
|
|
ink.c.Kshap = 1.0; /* Linear transition */
|
|
|
|
gres = tres + 2;
|
|
|
|
/* Get a Device to PCS conversion object */
|
|
if ((luo = xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmFwd, icAbsoluteColorimetric, icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL) {
|
|
error ("%d, %s",rd_icco->e.c, rd_icco->e.m);
|
|
}
|
|
/* Get details of conversion */
|
|
luo->spaces(luo, &ins, NULL, &outs, NULL, NULL, NULL, NULL, NULL);
|
|
|
|
if (ins != icSigCmykData) {
|
|
error("Expecting CMYK device");
|
|
}
|
|
|
|
/* Make a default allocation */
|
|
fxlist_a = 4;
|
|
if ((fxlist = (fxpos *)malloc(sizeof(fxpos) * fxlist_a)) == NULL)
|
|
error ("Failed to malloc fxlist");
|
|
|
|
/* init coords */
|
|
for (j = 0; j < 3; j++)
|
|
gc[j] = 0;
|
|
|
|
|
|
/* Add CMY grid surface points */
|
|
for (;;) { /* Generate all grid points */
|
|
|
|
/* Check if this position is on the CMY surface */
|
|
for (j = 0; j < 3; j++) {
|
|
if (gc[j] == 0 || gc[j] == (tres-1))
|
|
break;
|
|
}
|
|
if (j < 3) { /* On the surface, so add a point */
|
|
|
|
/* Make sure there is room */
|
|
if (fxno >= fxlist_a) {
|
|
fxlist_a *= 2;
|
|
if ((fxlist = (fxpos *)realloc(fxlist, sizeof(fxpos) * fxlist_a)) == NULL)
|
|
error ("Failed to malloc fxlist");
|
|
}
|
|
for (j = 0; j < 3; j++)
|
|
fxlist[fxno].p[j] = gc[j]/(tres-1.0);
|
|
fxlist[fxno].p[3] = 0.0; /* K = 0 */
|
|
fxno++;
|
|
}
|
|
|
|
/* Increment grid index and position */
|
|
for (j = 0; j < 3; j++) {
|
|
gc[j]++;
|
|
if (gc[j] < tres)
|
|
break; /* No carry */
|
|
gc[j] = 0;
|
|
}
|
|
if (j >= 3)
|
|
break; /* Done grid */
|
|
}
|
|
|
|
/* Add neutral axis points */
|
|
for (i = 1; i < ((EXTRA_NEUTRAL * gres)-1); i++) {
|
|
|
|
/* Make sure there is room */
|
|
if (fxno >= fxlist_a) {
|
|
fxlist_a *= 2;
|
|
if ((fxlist = (fxpos *)realloc(fxlist, sizeof(fxpos) * fxlist_a)) == NULL)
|
|
error ("Failed to malloc fxlist");
|
|
}
|
|
for (j = 0; j < 3; j++)
|
|
fxlist[fxno].p[j] = i/((EXTRA_NEUTRAL * gres)-1.0);
|
|
fxlist[fxno].p[3] = 0.0; /* K = 0 */
|
|
fxno++;
|
|
}
|
|
|
|
/* Convert CMY values into CMY0 Lab values */
|
|
for (i = 0; i < fxno; i++) {
|
|
if ((rv = luo->lookup(luo, fxlist[i].v, fxlist[i].p)) > 1)
|
|
error ("%d, %s",rd_icco->e.c,rd_icco->e.m);
|
|
//printf("~1 initial lookup %f %f %f -> %f %f %f\n", fxlist[i].p[0], fxlist[i].p[1], fxlist[i].p[2], fxlist[i].v[0], fxlist[i].v[1], fxlist[i].v[2]);
|
|
}
|
|
|
|
/* A CMYK black will be deeper than CMY0, so we need to figure out */
|
|
/* how to scale the initial values to fully occupy the CMYK gamut. */
|
|
|
|
/* Figure out the general scale at the black end */
|
|
{
|
|
double dval[4];
|
|
double wt[3] = { 100.0, 0, 0 }; /* Approximate white PCS */
|
|
double ac[3] = { 50.0, 0, 0 }; /* Adjustment center */
|
|
|
|
double lab_wt[3]; /* Media Whitepoint PCS */
|
|
double xyz_wt[3]; /* Media Whitepoint PCS */
|
|
icmXYZNumber XYZ_WT;
|
|
double k_bk[3]; /* K black PCS */
|
|
double cmyk_bk[3]; /* CMYK black PCS */
|
|
double toAbs[3][3];
|
|
double fromAbs[3][3];
|
|
|
|
/* Discover the Lab of the CMYK media */
|
|
for (j = 0; j < 4; j++)
|
|
dval[j] = 0.0;
|
|
luo->lookup(luo, lab_wt, dval);
|
|
icmLab2XYZ(&icmD50, xyz_wt, lab_wt);
|
|
icmAry2XYZ(XYZ_WT, xyz_wt);
|
|
|
|
/* Create the XYZ chromatic transform from relative to absolute and back */
|
|
icmChromAdaptMatrix(ICM_CAM_BRADFORD, XYZ_WT, icmD50, toAbs);
|
|
icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, XYZ_WT, fromAbs);
|
|
|
|
/* Discover the Lab of the CMY black and CMYK black */
|
|
for (j = 0; j < 3; j++)
|
|
dval[j] = 0.0;
|
|
dval[j] = 1.0;
|
|
luo->lookup(luo, k_bk, dval);
|
|
visect(luo, cmyk_bk, NULL, wt, k_bk);
|
|
if (verb)
|
|
printf("K black %f %f %f, CMYK black %f %f %f\n", k_bk[0], k_bk[1], k_bk[2], cmyk_bk[0], cmyk_bk[1], cmyk_bk[2]);
|
|
|
|
/* Scale the CMY values that will be influenced by the K component to a darker */
|
|
/* black. */
|
|
|
|
for (i = 0; i < fxno; i++) {
|
|
|
|
/* Treat grey axis points differently */
|
|
if (fxlist[i].p[0] != 0.0
|
|
&& fxlist[i].p[0] == fxlist[i].p[1]
|
|
&& fxlist[i].p[0] == fxlist[i].p[2]) {
|
|
double xyz[3]; /* Temporary */
|
|
double lab[3]; /* Temporary */
|
|
|
|
//printf("~1 scaled neutral L value from %f",fxlist[i].v[0]);
|
|
|
|
/* Scale L value from K to CMYK black */
|
|
fxlist[i].v[0] = lab_wt[0] + (fxlist[i].v[0] - lab_wt[0]) *
|
|
(cmyk_bk[0] - lab_wt[0])/(k_bk[0] - lab_wt[0]);
|
|
//printf(" to %f\n",fxlist[i].v[0]);
|
|
|
|
#ifdef NEVER
|
|
/* Make a & b values same as CMYK black */
|
|
/* Pivot around white point */
|
|
fxlist[i].v[1] = wt[1] + (cmyk_bk[1] - wt[1]) *
|
|
(fxlist[i].v[0] - wt[0])/(cmyk_bk[0] - wt[0]);
|
|
fxlist[i].v[2] = wt[2] + (cmyk_bk[2] - wt[2]) *
|
|
(fxlist[i].v[0] - wt[0])/(cmyk_bk[0] - wt[0]);
|
|
#else
|
|
/* Convert absolute target Lab to relative Lab */
|
|
icmLab2XYZ(&icmD50, xyz, fxlist[i].v);
|
|
icmMulBy3x3(xyz, fromAbs, xyz);
|
|
icmXYZ2Lab(&icmD50, lab, xyz);
|
|
|
|
/* Make sure the equivalent relative value is neutral */
|
|
lab[1] = lab[2] = 0.0;
|
|
|
|
/* Convert back to absolute Lab */
|
|
icmLab2XYZ(&icmD50, xyz, lab);
|
|
icmMulBy3x3(xyz, toAbs, xyz);
|
|
icmXYZ2Lab(&icmD50, lab, xyz);
|
|
|
|
//printf("~1 corrected neutral value from Lab %f %f %f to %f %f %f\n", fxlist[i].v[0], fxlist[i].v[1], fxlist[i].v[2], lab[0], lab[1], lab[2]);
|
|
|
|
for (j = 0; j < 3; j++)
|
|
fxlist[i].v[j] = lab[j];
|
|
#endif
|
|
|
|
} else {
|
|
|
|
for (j = 0; j < 3; j++) {
|
|
if (fxlist[i].p[j] == 0.0)
|
|
break; /* Not a dark color */
|
|
}
|
|
if (j >= 3) {
|
|
/* Scale by CMYK/K black vector */
|
|
for (j = 0; j < 3; j++) {
|
|
fxlist[i].v[j] = lab_wt[j] + (fxlist[i].v[j] - lab_wt[j]) *
|
|
(cmyk_bk[j] - lab_wt[j])/(k_bk[j] - lab_wt[j]);
|
|
}
|
|
}
|
|
|
|
//printf("[%4.2f %4.2f %4.2f] %f %f %f becomes",
|
|
//fxlist[i].p[0], fxlist[i].p[1], fxlist[i].p[2], fxlist[i].v[0], fxlist[i].v[1], fxlist[i].v[2]);
|
|
/* Now clip non-neutrals to the gamut surface */
|
|
visect(luo, fxlist[i].v, NULL, ac, fxlist[i].v);
|
|
//printf("%f %f %f\n", fxlist[i].v[0], fxlist[i].v[1], fxlist[i].v[2]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (verb) {
|
|
for (i = 0; i < fxno; i++) {
|
|
if (dorgb) {
|
|
printf("Point %d = %f %f %f -> %f %f %f\n",i,
|
|
1.0 - fxlist[i].p[0], 1.0 - fxlist[i].p[1], 1.0 - fxlist[i].p[2],
|
|
fxlist[i].v[0], fxlist[i].v[1], fxlist[i].v[2]);
|
|
} else {
|
|
printf("Point %d = %f %f %f -> %f %f %f\n",i,
|
|
fxlist[i].p[0], fxlist[i].p[1], fxlist[i].p[2],
|
|
fxlist[i].v[0], fxlist[i].v[1], fxlist[i].v[2]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Setup output cgats file */
|
|
{
|
|
char buf[1000];
|
|
cgats_set_elem *setel; /* Array of set value elements */
|
|
|
|
ocg = new_cgats(); /* Create a CGATS structure */
|
|
ocg->add_other(ocg, "CTI3"); /* our special type is Calibration Target Information 3 */
|
|
ocg->add_table(ocg, tt_other, 0); /* Start the first table */
|
|
|
|
ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 3",NULL);
|
|
if (dorgb)
|
|
ocg->add_kword(ocg, 0, NULL, NULL, "Fake RGB device data for profile or RGB->CMYK link");
|
|
else
|
|
ocg->add_kword(ocg, 0, NULL, NULL, "Fake CMY device data for profile or CMY->CMYK link");
|
|
ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll fakeCMY", NULL);
|
|
atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
|
|
ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
|
|
|
|
ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL);
|
|
|
|
if (dorgb)
|
|
ocg->add_kword(ocg, 0, "COLOR_REP","RGB_LAB", NULL);
|
|
else
|
|
ocg->add_kword(ocg, 0, "COLOR_REP","CMY_LAB", NULL);
|
|
|
|
if (!dorgb) {
|
|
if (tlimit >= 0) {
|
|
sprintf(buf,"%.0f",tlimit * 100.0);
|
|
ocg->add_kword(ocg, 0, "TOTAL_INK_LIMIT",buf, NULL);
|
|
}
|
|
|
|
if (klimit >= 0) {
|
|
sprintf(buf,"%.0f",klimit * 100.0);
|
|
ocg->add_kword(ocg, 0, "BLACK_INK_LIMIT",buf, NULL);
|
|
}
|
|
}
|
|
|
|
/* Fields we want */
|
|
ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
|
|
if (dorgb) {
|
|
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);
|
|
} else {
|
|
ocg->add_field(ocg, 0, "CMY_C", r_t);
|
|
ocg->add_field(ocg, 0, "CMY_M", r_t);
|
|
ocg->add_field(ocg, 0, "CMY_Y", r_t);
|
|
}
|
|
ocg->add_field(ocg, 0, "LAB_L", r_t);
|
|
ocg->add_field(ocg, 0, "LAB_A", r_t);
|
|
ocg->add_field(ocg, 0, "LAB_B", r_t);
|
|
|
|
if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * 7)) == NULL)
|
|
error("Malloc failed!");
|
|
|
|
/* Write out test values. */
|
|
for (i = 0; i < fxno; i++) {
|
|
|
|
sprintf(buf, "%d", i+1);
|
|
setel[0].c = buf;
|
|
|
|
if (dorgb) {
|
|
setel[1].d = 100.0 * (1.0 - fxlist[i].p[0]);
|
|
setel[2].d = 100.0 * (1.0 - fxlist[i].p[1]);
|
|
setel[3].d = 100.0 * (1.0 - fxlist[i].p[2]);
|
|
} else {
|
|
setel[1].d = 100.0 * fxlist[i].p[0];
|
|
setel[2].d = 100.0 * fxlist[i].p[1];
|
|
setel[3].d = 100.0 * fxlist[i].p[2];
|
|
}
|
|
setel[4].d = fxlist[i].v[0];
|
|
setel[5].d = fxlist[i].v[1];
|
|
setel[6].d = fxlist[i].v[2];
|
|
|
|
ocg->add_setarr(ocg, 0, setel);
|
|
}
|
|
|
|
free(setel);
|
|
if (ocg->write_name(ocg, out_name))
|
|
error("Write error : %s",ocg->e.m);
|
|
ocg->del(ocg);
|
|
}
|
|
|
|
luo->del(luo);
|
|
xicco->del(xicco);
|
|
rd_icco->del(rd_icco);
|
|
rd_fp->del(rd_fp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|