// Load non-uniform data file and build a table McoStatus Tweak_Patch::Load_Data(FILE *bf) { McoHandle tdH; McoHandle tdrH; double *td,*tdr; int32 i,num; if (bf == 0L) return MCO_FILE_OPEN_ERROR; fscanf(bf,"%d",&num); tdH = McoNewHandle(sizeof(double)*num*3); tdrH = McoNewHandle(sizeof(double)*num*3); td = (double *)McoLockHandle(tdH); tdr = (double *)McoLockHandle(tdrH); for (i=0; i<num; i++) { fscanf(bf,"%lf %lf %lf",&td[0],&td[1],&td[2]); td += 3; } for (i=0; i<num; i++) { fscanf(bf,"%lf %lf %lf",&tdr[0],&tdr[1],&tdr[2]); tdr += 3; } McoUnlockHandle(tdH); McoUnlockHandle(tdrH); Build_Table(tdH,tdrH,num); McoDeleteHandle(tdH); McoDeleteHandle(tdrH); return MCO_SUCCESS; }
// fix the L values when saturation is zero McoStatus FindBlack::fixmanyBlackL(void) { int i,j,k,l,sk; double h,a; double start_L,end_L; double *gammutSurfaceManyBlack,*gammutSurfaceManyBlackL; gammutSurfaceManyBlack = (double*)McoLockHandle(_gammutSurfaceManyBlackH); gammutSurfaceManyBlackL = (double*)McoLockHandle(_gammutSurfaceManyBlackLH); for (i=0; i<GAM_DIM_K; i++) { for (j=0; j<72; j++) { for (k=0; k<50; k++) { if (gammutSurfaceManyBlack[i*3600+j*50+k] > 0) break; } if (k != 50) { sk = k; end_L = gammutSurfaceManyBlackL[i*3600+j*50+k]; } for (k=49; k>=0; k--) { if (gammutSurfaceManyBlack[i*3600+j*50+k] > 0) break; } if ((k != -1) && (k != sk)) { h = (k-sk); start_L = gammutSurfaceManyBlackL[i*3600+j*50+k]; for (l=0; l<50; l++) { a = ((double)l-sk)/h; gammutSurfaceManyBlackL[i*3600+j*50+l] = end_L*(1-a)+start_L*a; } } else if (k == sk) { end_L = gammutSurfaceManyBlackL[i*3600+j*50+k]+2; start_L = gammutSurfaceManyBlackL[i*3600+j*50+k]-2; k +=1; sk -=1; h = (k-sk); for (l=0; l<50; l++) { a = ((double)l-sk)/h; gammutSurfaceManyBlackL[i*3600+j*50+l] = end_L*(1-a)+start_L*a; } } } } McoUnlockHandle(_gammutSurfaceManyBlackH); McoUnlockHandle(_gammutSurfaceManyBlackLH); return MCO_SUCCESS; }
// Build a table using non-uniform data McoStatus Tweak_Patch::Build_Table(McoHandle tdH,McoHandle tdrH, int32 num) { McoStatus status; double *tweakData; double *tweakDataRef; int i,j,k,m; double L, a, b; double *lab; double labt[3]; double stepL = 100.0/32.0; short end; Linearcal *calib; tweakData = (double*)McoLockHandle(tdH); tweakDataRef = (double*)McoLockHandle(tdrH); calib = new Linearcal(20,num,num); if (calib == 0L) return MCO_MEM_ALLOC_ERROR; end = 0; while(1){ //forword calibration(C(L,a,b)) status = calib->loaddirect(tweakData, tweakDataRef, &end); //reverse calibration(L(C,M,Y)) //status = calib->loaddirect(_patchref, _patch, &end); if(status != MCO_SUCCESS) return status; if(end == 1) //compute break; } status = calib->compute(); lab = (double *)McoLockHandle(labTableH); for(i = 0; i < 33; i++){ L = i*stepL; for(j = -16; j <= 16; j++){ if (j < 16) a = j*8; else a = 127.0; for(m = -16; m <= 16; m++){ if (m < 16) b = m*8; else b = 127.0; calib->_applyf(L,a,b,lab); lab +=3; } } } McoUnlockHandle(labTableH); McoUnlockHandle(tdH); McoUnlockHandle(tdrH); return MCO_SUCCESS; }
// Modify the table with an individual tweak McoStatus Tweak_Patch::Modify_Table(double *lab_d,double *lab_p,double Lr,double Cr) { int i,j,k,m,n = 0; double L_dist,a_dist,b_dist; double dL,da,db; double *lab,*labp; double L,a,b; double L2,a2,b2; double scale; double stepL; stepL = 100.0/32.0; lab = (double *)McoLockHandle(labTableH); labp = lab; dL = lab_p[0] - lab_d[0]; da = lab_p[1] - lab_d[1]; db = lab_p[2] - lab_d[2]; Cr = Cr * 2.55; if ((Lr == 0) || (Cr == 0)) return MCO_FAILURE; Lr = (12500*0.00008*100+100*(Lr*Lr)-12500*2.995732274)/(Lr*Lr); Cr = (12500*0.00008*100+100*(Cr*Cr)-12500*2.995732274)/(Cr*Cr); for(i = 0; i < 33; i++){ L = i*stepL; L_dist = L-lab_d[0]; L_dist *= L_dist; L_dist *= (100-Lr)*0.00008; for(j = -16; j <= 16; j++){ if (j < 16) a = j*8; else a = 127.0; a_dist = a - lab_d[1]; a_dist *= a_dist; a_dist *= (100-Cr)*0.00008; for(m = -16; m <= 16; m++){ if (m < 16) b = m*8; else b = 127.0; b_dist = b - lab_d[2]; b_dist *= b_dist; b_dist *= (100-Cr)*0.00008; scale = exp(-(L_dist+a_dist+b_dist)); //save to a structure L2 = L+dL; a2 = a+da; b2 = b+db; lab[0] = (1-scale)*lab[0]+scale*L2; lab[1] = (1-scale)*lab[1]+scale*a2; lab[2] = (1-scale)*lab[2]+scale*b2; lab +=3; n+=3; } } } McoUnlockHandle(labTableH); return MCO_SUCCESS; }
McoStatus Tweak_Patch::Init_Table(void) { int i,j,k,m,n; double L_dist,a_dist,b_dist; double dL,da,db; double *lab; double L,a,b; double stepL; stepL = 100.0/32.0; lab = (double *)McoLockHandle(labTableH); if (type == Calibrate_Tweak) for(i = 0; i < 33; i++){ L = i*stepL; for(j = -16; j <= 16; j++){ if (j < 16) a = j*8; else a = 127.0; for(m = -16; m <= 16; m++){ if (m < 16) b = m*8; else b = 127.0; lab[0] = L; lab[1] = a; lab[2] = b; lab +=3; } } } else // set to zero for(i = 0; i < 33; i++){ L = i*stepL; for(j = -16; j <= 16; j++){ if (j < 16) a = j*8; else a = 127.0; for(m = -16; m <= 16; m++){ if (m < 16) b = m*8; else b = 127.0; lab[0] = 0; lab[1] = 0; lab[2] = 0; lab +=3; } } } McoUnlockHandle(labTableH); return MCO_SUCCESS; }
//save to input black table when window is closed McoStatus PrinterType::setblack(McoHandle blacktableH) { short i; double *black; double *y2_hands; double ypn; y2_hands = new double[num_hands]; black = (double*)McoLockHandle(blacktableH); ypn=(y_hands[num_hands-1]-y_hands[num_hands-2])/ (x_hands[num_hands-1]-x_hands[num_hands-2]); spline_0(x_hands,y_hands,num_hands,1E30,1E30,y2_hands); //L to Black table for( i = 0; i <= 100; i++) splint_0(x_hands,y_hands,y2_hands,num_hands,i, black+i); //fix on 8/23 //clipping the _yd_points which on the left of letfmost hand //to the value of the leftmost hand //on the right of rightmost hand to the value of the rightmost hand for( i = 0; i <= 100; i++){ if( i <= x_hands[0] ) //left of the leftmost hand black[i] = y_hands[0]; if( i >= x_hands[num_hands-1] ) //left of the leftmost hand black[i] = y_hands[num_hands-1]; } //clipping the table and normaliz to 1 for( i = 0; i <= 100; i++){ if(black[i] < 0) black[i] = 0; else if(black[i] > 100) black[i] = 1.0; else black[i] /= 100.0; } McoUnlockHandle(blacktableH); delete y2_hands; return MCO_SUCCESS; }
// Save the table McoStatus Tweak_Patch::Save_Table(FileFormat *fileF) { McoStatus state; double *table; int32 magic = TWEAK_MAGIC_NUM; int32 version = TWEAK_VERSION_NUM; state = fileF->relWrite(sizeof(int32),(char*)&magic); if (state != MCO_SUCCESS) return state; state = fileF->relWrite(sizeof(int32),(char*)&version); if (state != MCO_SUCCESS) return state; table = (double *)McoLockHandle(labTableH); state = fileF->relWrite(sizeof(double)*33*33*33*3,(char*)table); if (state != MCO_SUCCESS) return state; McoUnlockHandle(labTableH); return MCO_SUCCESS; }
// Load a table McoStatus Tweak_Patch::Load_Table(FileFormat *fileF) { McoStatus state; double *table; int32 magic,version; state = fileF->relRead(sizeof(int32),(char*)&magic); if (state != MCO_SUCCESS) return state; if (magic != TWEAK_MAGIC_NUM) return MCO_FILE_DATA_ERROR; state = fileF->relRead(sizeof(int32),(char*)&version); if (state != MCO_SUCCESS) return state; if (version != TWEAK_VERSION_NUM) return MCO_FILE_DATA_ERROR; table = (double *)McoLockHandle(labTableH); state = fileF->relRead(sizeof(double)*33*33*33*3,(char*)table); if (state != MCO_SUCCESS) return state; McoUnlockHandle(labTableH); return MCO_SUCCESS; }
McoStatus FindBlack::findMinMaxOpt(double *lab, double *Kmin,double *Kmax,double *Kopt) { int32 i,km,kp,c; double *gammutSurfaceManyBlack; double *gammutSurfaceManyBlackL; double x23[2]; double lch[3]; double x11[101]; // find 100 black values double y[101]; double x2n[50]; double y2n[GAM_DIM_K*50]; Boolean start = TRUE; double best_s; double Kmint,Kmaxt; Kmint = -1; Kmaxt = -1; labtolch(lab,lch); km = floor(*Kmin); kp = ceil(*Kmax); if ((lab[1]*lab[1]+lab[2]*lab[2]) <= 1.0) { for (i=0; i<50; i++) x2n[i] = (double)i*2; for (i=km; i<=kp; i++) x11[i] = (double)i/100; c = 1+kp-km; spline2(x1,x2n,neutralmins,GAM_DIM_K,50,y2n); splint2_clip(x1,x2n,neutralmins,y2n,GAM_DIM_K,50,lab[0],x11,c,y); } else { gammutSurfaceManyBlack = (double*)McoLockHandle(_gammutSurfaceManyBlackH); gammutSurfaceManyBlackL = (double*)McoLockHandle(_gammutSurfaceManyBlackLH); x23[0] = lch[2]; x23[1] = lab[0]; for (i=km; i<=kp; i++) x11[i] = (double)i/100; c = 1+kp-km; splint3_s3_clip(x1,x2,gammutSurfaceManyBlackL,gammutSurfaceManyBlack,y2a,GAM_DIM_K,72,50,x23,x11,c,y); McoUnlockHandle(_gammutSurfaceManyBlackH); McoUnlockHandle(_gammutSurfaceManyBlackLH); } best_s = 0; c = 0; for (i=km; i<=kp; i++) { if ((y[c] > 0) && (y[c] + 0.8 > lch[1])) // insert a small tolerence here { if (start) { Kmint = (double)i; start = FALSE; } Kmaxt = (double)i; } if (y[c] > best_s) { best_s = y[c]; *Kopt = (double)i; } c++; } *Kmin = Kmint; *Kmax = Kmaxt; if (*Kmin == -1) *Kmin = *Kopt; if (*Kmax == -1) *Kmax = *Kopt; return MCO_SUCCESS; }
// extend the range of gammutsurfacemany black by convolving with a Gaussian kernal // interpolation errors often reduce the range of the gamut, this extends that range back out McoStatus FindBlack::extendRange(void) { int i,j,k,l,m; int count; double *gammutSurfaceManyBlack; double kernal[5]; double sum[6]; double temp[50]; double a; gammutSurfaceManyBlack = (double*)McoLockHandle(_gammutSurfaceManyBlackH); for (i=0; i<6; i++) sum[i] = 0.0; // create the kernal for (i=-2; i<3; i++) { kernal[i+2] = exp(-(double)(i*i)*0.9); sum[5] += kernal[i+2]; } // the sums at the edges sum[3] = 1+kernal[1]+kernal[0]; sum[4] = 1+kernal[1]*2+kernal[0]; for (i=0; i<GAM_DIM_K; i++) { // for all 72 hues for (j=0; j<72; j++) { // a temp buffer for (k=0; k<50; k++) temp[k] = gammutSurfaceManyBlack[k+j*50+i*50*72]; for (k=0; k<50; k++) { count = 0; a = 0; for (l=-2; l<3; l++) { m = l+k; if ((m >=0) && (m <50)) { count ++; a += temp[m]*kernal[l+2]; } } gammutSurfaceManyBlack[k+j*50+i*50*72] = a/sum[count]; } } // now do the same for the neutral data for (k=0; k<50; k++) temp[k] = neutralmins[k+i*50]; for (k=0; k<50; k++) { count = 0; a = 0; for (l=-2; l<3; l++) { m = l+k; if ((m >=0) && (m <50)) { count ++; a += temp[m]*kernal[l+2]; } } neutralmins[k+i*50] = a/sum[count]; } } McoUnlockHandle(_gammutSurfaceManyBlackH); return MCO_SUCCESS; }
FindBlack::FindBlack(double *bL, double *bK, double *a, double *b, int32 nB, double u_g, double miL, double maL, double *bT, McoHandle gsmbH,McoHandle gsmbLH,double minGam, double maxGam,calib_base *cal) { double *tx,*ty,yd1,ydn; int i; double *gammutSurfaceManyBlack; double *gammutSurfaceManyBlackL; double gam_dim_k_vals[] = GAM_DIM_K_VALS; _gammutSurfaceManyBlackH = gsmbH; _gammutSurfaceManyBlackLH = gsmbLH; numB = nB; calib = cal; blackL = 0L; /* blackL = new double[numB]; for (i=0; i<numB; i++) { blackL[i] = 100-bL[i]; } */ //blackL = bL; blackK = bK; blacka = a; blackb = b; // tx = blackL; ty = blackK; K2 = new double[numB]; if (!K2) goto bail; a2 = new double[numB]; if (!a2) goto bail; b2 = new double[numB]; if (!b2) goto bail; // yd1=(ty[2]-ty[1])/(tx[2]-tx[1])/4; // ydn=(ty[numB-1]-ty[numB-2])/(tx[numB-1]-tx[numB-2])/4; // spline(tx-1,ty-1,numB,yd1,ydn,K2-1); tx = blackK; ty = blacka; yd1=(ty[2]-ty[1])/(tx[2]-tx[1])/4; ydn=(ty[numB-1]-ty[numB-2])/(tx[numB-1]-tx[numB-2])/4; spline(tx-1,ty-1,numB,yd1,ydn,a2-1); tx = blackK; ty = blackb; yd1=(ty[2]-ty[1])/(tx[2]-tx[1])/4; ydn=(ty[numB-1]-ty[numB-2])/(tx[numB-1]-tx[numB-2])/4; spline(tx-1,ty-1,numB,yd1,ydn,b2-1); ucrgcr = u_g; //ucrgcr = u_g; minL = miL; maxL = maL; blackTable = bT; y2a = new double[GAM_DIM_K*50*72]; if (!y2a) goto bail; fixmanyBlackL(); gammutSurfaceManyBlack = (double*)McoLockHandle(_gammutSurfaceManyBlackH); gammutSurfaceManyBlackL = (double*)McoLockHandle(_gammutSurfaceManyBlackLH); x1 = new double[GAM_DIM_K]; if (!x1) goto bail; x2 = new double[72]; if (!x2) goto bail; x3 = new double[72]; if (!x3) goto bail; for (i=0; i<GAM_DIM_K; i++) { x1[i] = gam_dim_k_vals[i]/100.0; } for (i=0; i<72; i++) x2[i] = (double)i*5.0; spline3_s3(x1,x2,gammutSurfaceManyBlackL,gammutSurfaceManyBlack,GAM_DIM_K,72,50, y2a); McoUnlockHandle(_gammutSurfaceManyBlackH); McoUnlockHandle(_gammutSurfaceManyBlackH); findNeutralMins(); extendRange(); error = MCO_SUCCESS; return; bail: error = MCO_MEM_ALLOC_ERROR; return; }
// evaluate using the table (for gamut compression) // labo = the original lab value // labg = the gamut compressed lab value // labt = the tweaked compressed value McoStatus Tweak_Patch::eval(double *labo,double *labg,double *labt,int32 num) { int i; double a,b,c; int32 a1,a2,b1,b2,c1,c2; int32 ai1,ai2,bi1,bi2,ci1,ci2; double t,u,v; double r1,r2,r3,r4,r5,r6,r7,r8; double *p1,*p2,*p3,*p4,*p5,*p6,*p7,*p8; double *table; double lch[3]; if (type == Calibrate_Tweak) return MCO_FAILURE; table = (double *)McoLockHandle(labTableH); for (i=0; i<num; i++) { a = labo[0]*0.32; b = 16 + labo[1]*0.125; c = 16 + labo[2]*0.125; if (a >= 32) a = 31.999999; if (a < 0) a = 0; if (b >= 32) b = 31.999999; if (b < 0) b = 0; if (c >= 32) c = 31.999999; if (c < 0) c = 0; a1 = ((int32)a)*3267; a2 = a1 + 3267; b1 = ((int32)b)*99; b2 = b1 + 99; c1 = ((int32)c)*3; c2 = c1 + 3; t = a - (int32)a; u = b - (int32)b; v = c - (int32)c; r1 = (1-u)*(1-v); r2 = (1-u)*v; r3 = u*(1-v); r4 = u*v; r5 = t*r1; r6 = t*r2; r7 = t*r3; r8 = t*r4; a = (1-t); r1 = a*r1; r2 = a*r2; r3 = a*r3; r4 = a*r4; p1 = table +a1+b1+c1; p2 = table +a1+b1+c2; p3 = table +a1+b2+c1; p4 = table +a1+b2+c2; p5 = table +a2+b1+c1; p6 = table +a2+b1+c2; p7 = table +a2+b2+c1; p8 = table +a2+b2+c2; labtolch(labg,lch); lch[0] += r1*(*(p1++)) + r2*(*(p2++)) + r3*(*(p3++)) + r4*(*(p4++)) + r5*(*(p5++)) + r6*(*(p6++)) + r7*(*(p7++)) + r8*(*(p8++)); lch[1] += r1*(*(p1++)) + r2*(*(p2++)) + r3*(*(p3++)) + r4*(*(p4++)) + r5*(*(p5++)) + r6*(*(p6++)) + r7*(*(p7++)) + r8*(*(p8++)); lch[2] += r1*(*(p1)) + r2*(*(p2)) + r3*(*(p3)) + r4*(*(p4)) + r5*(*(p5)) + r6*(*(p6)) + r7*(*(p7)) + r8*(*(p8)); if (lch[2] <0) lch[2] = 360 + lch[2]; if (lch[2] >=360) lch[2] = lch[2] - 360; lchtolab(lch,labt); labo+=3; labg+=3; labt+=3; } McoUnlockHandle(labTableH); return MCO_SUCCESS; }
// Modify the table with a list of tweaks McoStatus Tweak_Patch::Modify_Table(int num_tw,Tweak_Element **tweaks) { int i,j,k,m,n = 0; double L_dist,a_dist,b_dist; double dL,da,db,dc,dh; double *lab,*labp; double L,a,b; double L2,a2,b2; double scale; double stepL; double Lr,Cr; double lch1[3],lch2[3],labt[3]; stepL = 100.0/32.0; lab = (double *)McoLockHandle(labTableH); labp = lab; if (type == Calibrate_Tweak) { for (k=0; k<num_tw; k++) if (tweaks[k]->type == Calibrate_Tweak) { lab = labp; dL = tweaks[k]->lab_p[0] - tweaks[k]->lab_g[0]; da = tweaks[k]->lab_p[1] - tweaks[k]->lab_g[1]; db = tweaks[k]->lab_p[2] - tweaks[k]->lab_g[2]; Lr = tweaks[k]->Lr; Cr = tweaks[k]->Cr; Cr = Cr * 2.55; if ((Lr == 0) || (Cr == 0)) return MCO_FAILURE; Lr = (12500*0.00008*100+100*(Lr*Lr)-12500*2.995732274)/(Lr*Lr); Cr = (12500*0.00008*100+100*(Cr*Cr)-12500*2.995732274)/(Cr*Cr); for(i = 0; i < 33; i++){ L = i*stepL; L_dist = L-tweaks[k]->lab_g[0]; L_dist *= L_dist; L_dist *= (100-Lr)*0.00008; for(j = -16; j <= 16; j++){ if (j < 16) a = j*8; else a = 127.0; a_dist = a - tweaks[k]->lab_g[1]; a_dist *= a_dist; a_dist *= (100-Cr)*0.00008; for(m = -16; m <= 16; m++){ if (m < 16) b = m*8; else b = 127.0; b_dist = b - tweaks[k]->lab_g[2]; b_dist *= b_dist; b_dist *= (100-Cr)*0.00008; scale = exp(-(L_dist+a_dist+b_dist)); //save to a structure L2 = L+dL; a2 = a+da; b2 = b+db; lab[0] = (1-scale)*lab[0]+scale*L2; lab[1] = (1-scale)*lab[1]+scale*a2; lab[2] = (1-scale)*lab[2]+scale*b2; lab +=3; n+=3; } } } } } else if (type == GamutComp_Tweak) { for (k=0; k<num_tw; k++) if (tweaks[k]->type == GamutComp_Tweak) { lab = labp; labtolch(tweaks[k]->lab_p,lch1); labtolch(tweaks[k]->lab_g,lch2); dL = lch2[0] - lch1[0]; dc = lch2[1] - lch1[1]; dh = lch2[2] - lch1[2]; if (dh > 180) dh = dh - 360; if (dh < -180) dh = 360 + dh; Lr = tweaks[k]->Lr; Cr = tweaks[k]->Cr; Cr = Cr * 2.55; if ((Lr == 0) || (Cr == 0)) return MCO_FAILURE; Lr = (12500*0.00008*100+100*(Lr*Lr)-12500*2.995732274)/(Lr*Lr); Cr = (12500*0.00008*100+100*(Cr*Cr)-12500*2.995732274)/(Cr*Cr); for(i = 0; i < 33; i++){ L = i*stepL; L_dist = L-tweaks[k]->lab_d[0]; L_dist *= L_dist; L_dist *= (100-Lr)*0.00008; for(j = -16; j <= 16; j++){ if (j < 16) a = j*8; else a = 127.0; a_dist = a - tweaks[k]->lab_d[1]; a_dist *= a_dist; a_dist *= (100-Cr)*0.00008; for(m = -16; m <= 16; m++){ if (m < 16) b = m*8; else b = 127.0; b_dist = b - tweaks[k]->lab_d[2]; b_dist *= b_dist; b_dist *= (100-Cr)*0.00008; scale = exp(-(L_dist+a_dist+b_dist)); //save to a structure lab[0] = (1-scale)*lab[0]+scale*dL; lab[1] = (1-scale)*lab[1]+scale*dc; lab[2] = (1-scale)*lab[2]+scale*dh; lab +=3; n+=3; } } } } } McoUnlockHandle(labTableH); return MCO_SUCCESS; }