%ffp Category :"RC Filters" Title :"Adaptive Contrast Curve" Filename :"AdaptiveContrastCurve.8bf" Description:"Dynamic contrast and detail enhancement." Copyright :"© 2019 by Russell Cottrell; released under the Gnu General Public License." Author :"Russell Cottrell" Version :"1.202" URL :"http://www.russellcottrell.com/RCFilters" About :"Thank you for using !C!\n!t v!V by !A.\n!D\nPlease visit russellcottrell.com/RCFilters." // 6/28/2019 Dialog: Size=(590,406), MaxBox, MinBox, Theme=on, Initevent SupportedModes: RGBMode, RGB48Mode, GrayScaleMode, Gray16Mode Embed: Bitmap="logo.bmp" ctl(0): Standard, "Regions", Range=(1,200), pos=(400,16), Val=20 ctl(1): Standard, "Amount", Range=(0,100), pos=(400,28), Val=30 ctl(11): Standard, "AmountL", Range=(0,100), pos=(400,40), Val=30, invisible ctl(12): checkbox(Pushlike), text="Linked", Pos=(525,26), Size=(40,12), val=1 ctl(6): Scrollbar, "", pos=(523,15), size=(20,10), range=(0,1), val=0, line=1, invisible ctl(3): Standard, "Color", Range=(0,200), pos=(400,60), Val=0 ctl(5): Standard, "Vibrance", Range=(0,100), pos=(400,72), Val=0 ctl(2): Standard, "Level", Range=(-100,100), pos=(400,84), Val=0 ctl(10): checkbox(Pushlike, 3State), text="Normal", Pos=(525,57), Size=(56,12), val=1, Action=Preview ctl(7): RadioButton(Group), pos=(536,72), size=(60,*), val=1, Action=Preview, "Median" ctl(8): RadioButton, pos=(536,84), size=(60,*), Action=Preview, "Mean" ctl(9): GroupBox(Group), pos=(530,72), size=(0,0), Invisible ctl(4): Standard, "Dark/Light Mixer", Range=(-100,100), pos=(425,104), Val=0 ctl(30): StaticText, "Shadows/Highlights:", pos=(365,124), size=(160,10) ctl(31): Standard, "Tonal Width", Range=(0,255), pos=(400,140), size=(115,*), Val=0, Color=Black ctl(32): Standard, "Radius", Range=(0,1000), Divisor=100, pos=(400,152), size=(115,*), Val=100, Color=Black ctl(33): Standard, "Lighten", Range=(0,100), pos=(400,164), size=(115,*), Val=0, Color=Black ctl(34): Standard, "Tonal Width", Range=(0,255), pos=(400,180), size=(115,*), Val=0, Color=White ctl(35): Standard, "Radius", Range=(0,1000), Divisor=100, pos=(400,192), size=(115,*), Val=100, Color=White ctl(36): Standard, "Darken", Range=(0,100), pos=(400,204), size=(115,*), Val=0, Color=White ctl(37): checkbox(Pushlike), text="Enabled", Pos=(398,217), Size=(34,12), val=1 ctl(39): checkbox(Pushlike), text="Show", Pos=(434,217), Size=(34,12), val=0 ctl(70): StaticText, "Blend Ranges:", pos=(365,240), size=(160,10) ctl(71): GroupBox, pos=(363,247), size=(204,28) ctl(72): Trackbar(Noticks,Bottom,Toptip), Pos=(365,252), Size=(200,11), Range=(0,255), Val=0, Color=Black ctl(73): Trackbar(Noticks,Top,Toptip), Pos=(365,262), Size=(200,11), Range=(0,255), Val=127, Color=Black ctl(74): Trackbar(Noticks,Bottom,Toptip), Pos=(365,277), Size=(200,11), Range=(0,255), Val=127, Color=White ctl(75): Trackbar(Noticks,Top,Toptip), Pos=(365,287), Size=(200,11), Range=(0,255), Val=255, Color=White ctl(76): GroupBox, pos=(363,272), size=(204,28) ctl(77): checkbox(Pushlike), text="Midtones", Pos=(484,238), Size=(40,12), val=1 ctl(78): checkbox(Pushlike), text="Enabled", Pos=(526,238), Size=(40,12), val=1 ctl(40): OwnerDraw(drawitem), pos=(370,312), size=(256,100) // histogram ctl(41): Rect(Modalframe, White), pos=(0,0), size=(292, 149), Anchor=ANCHOR_LEFT|ANCHOR_TOP, Invisible ctl(42): Rect(Gray), pos=(3, 3), size=(286,87), Anchor=ANCHOR_LEFT|ANCHOR_TOP, Invisible ctl(43): StaticText(CENTER), pos=(3,94), size=(286, 8), Anchor=ANCHOR_LEFT|ANCHOR_TOP, Invisible, "Thank you for using RC Filters!" ctl(44): StaticText(CENTER), pos=(3,102), size=(286, 16), Anchor=ANCHOR_LEFT|ANCHOR_TOP, Invisible, "" ctl(45): StaticText(CENTER,NOTIFY), pos=(3,124), size=(286, 10), Anchor=ANCHOR_LEFT|ANCHOR_TOP, FontColor=blue, Invisible, "Please visit russellcottrell.com/RCFilters for more information." ctl(46): StaticText(CENTER,NOTIFY), pos=(3,134), size=(286, 10), Anchor=ANCHOR_LEFT|ANCHOR_TOP, FontColor=blue, Invisible, "Click here to open the plugin folder." ctl[CTL_PREVIEW]: Modify, Size=(333,383) ctl[CTL_PROGRESS]: Modify, Pos=(4,394) ctl[CTL_ZOOM]: Modify, Pos=(91,394), Invisible // AdaptiveContrastCurveHelp.htm ctl(53): checkbox(Pushlike), text="About", Pos=(431,389), Size=(34,14), val=0, Anchor=ANCHOR_RIGHT|ANCHOR_BOTTOM ctl(54): Pushbutton, text="Reset", Pos=(474,389), Size=(34,14), val=0, Anchor=ANCHOR_RIGHT|ANCHOR_BOTTOM, Action=Preview ctl[CTL_OK]: Pushbutton, text="Apply", Pos=(517,389), Size=(34,14), Anchor=ANCHOR_RIGHT|ANCHOR_BOTTOM ctl[CTL_CANCEL]: Pushbutton, text="Cancel", Pos=(552,389), Size=(34,14), Anchor=ANCHOR_RIGHT|ANCHOR_BOTTOM OnFilterstart: { switch(imageMode) { case RGBMode: sprintf(str0, "8-bit RGB Color"); break; case RGB48Mode: sprintf(str0, "16-bit RGB Color"); break; case GrayScaleMode: sprintf(str0, "8-bit Grayscale"); break; case Gray16Mode: sprintf(str0, "16-bit Grayscale"); break; } sprintf(str1, formatString("!t (%s, !f)"), str0); setDialogText(str1); if (e==FME_INIT) { if ((imageMode == RGBMode) || (imageMode == RGB48Mode)) { enableCtl(3, 3); enableCtl(5, 3); enableCtl(10, 3); } else { enableCtl(3, 1); enableCtl(5, 1); enableCtl(10, 1); } j0 = getCtlRange(3, 1); } if (ctl(6)==1) setCtlRange(0, 1, max(imageWidth,imageHeight)/2); else setCtlRange(0, 1, 200); setCtlPos(40, -1, -1, PixelsToHDBUs(259), PixelsToVDBUs(103)); setCtlText(44, formatString("!t v!V by !A.\n!D")); isTileable=false; refreshWindow(); return false; } OnCtl(n): { int jTemp; int logoL, logoT; void *TXT_FILE; int bctl0 = 72; // the blend range sliders int bctl1 = 73; int wctl0 = 74; int wctl1 = 75; if ((n==bctl0 || n==bctl1 || n==wctl0 || n==wctl1) && (e==FME_CHANGED)) { switch(n) { case 72: // can't use variables here if (ctl(bctl1) < ctl(bctl0)) setCtlVal(bctl1,ctl(bctl0)); if (ctl(wctl0) < ctl(bctl0)) setCtlVal(wctl0,ctl(bctl0)); if (ctl(wctl1) < ctl(bctl0)) setCtlVal(wctl1,ctl(bctl0)); break; case 73: if (ctl(bctl0) > ctl(bctl1)) setCtlVal(bctl0,ctl(bctl1)); if (ctl(wctl0) < ctl(bctl1)) setCtlVal(wctl0,ctl(bctl1)); if (ctl(wctl1) < ctl(bctl1)) setCtlVal(wctl1,ctl(bctl1)); break; case 74: if (ctl(bctl0) > ctl(wctl0)) setCtlVal(bctl0,ctl(wctl0)); if (ctl(bctl1) > ctl(wctl0)) setCtlVal(bctl1,ctl(wctl0)); if (ctl(wctl1) < ctl(wctl0)) setCtlVal(wctl1,ctl(wctl0)); break; case 75: if (ctl(bctl0) > ctl(wctl1)) setCtlVal(bctl0,ctl(wctl1)); if (ctl(bctl1) > ctl(wctl1)) setCtlVal(bctl1,ctl(wctl1)); if (ctl(wctl0) > ctl(wctl1)) setCtlVal(wctl0,ctl(wctl1)); break; } } if (n==77) { if (ctl(77)==0) { setCtlVal(bctl0,0); setCtlVal(bctl1,0); setCtlVal(wctl0,255); setCtlVal(wctl1,255); setCtlText(77, "All"); } else { setCtlVal(bctl0,0); setCtlVal(bctl1,127); setCtlVal(wctl0,127); setCtlVal(wctl1,255); setCtlText(77, "Midtones"); } } if (n==78) setCtlText(78, ctl(78) ? "Enabled" : "Off"); if (n==10) { switch(ctl(10)) { case 1: setCtlText(10, "Normal"); if ((imageMode == RGBMode) || (imageMode == RGB48Mode)) enableCtl(3, 3); jTemp = ctl(3); setCtlVal(3,j0); j0 = jTemp; break; case 2: setCtlText(10, "Grayscale Only"); enableCtl(3, 1); break; case 0: setCtlText(10, "Color Only"); enableCtl(3, 3); jTemp = ctl(3); setCtlVal(3,j0); j0 = jTemp; break; } } if (n==37) setCtlText(37, ctl(37) ? "Enabled" : "Off"); else if (n==39) setCtlText(39, ctl(39) ? "Hide" : "Show"); if (n==12) { switch(ctl(12)) { case 0: setCtlText(12, "Unlinked"); setCtlText(1, "AmountH"); enableCtl(11, 3); break; case 1: setCtlText(12, "Linked"); setCtlText(1, "Amount"); enableCtl(11, 0); break; } } if (e==FME_CLICKED) { if (ctl(53)) // About { logoL = (getDialogWidth() - getCtlPos(41, 2))/2; logoT = (getDialogHeight() - getCtlPos(41, 3))/2 - 10; setCtlPos(41, logoL, logoT, -1, -1); setCtlPos(42, logoL+3, logoT+3, -1, -1); setCtlPos(43, logoL+3, logoT+94, -1, -1); setCtlPos(44, logoL+3, logoT+102, -1, -1); setCtlPos(45, logoL+3, logoT+124, -1, -1); setCtlPos(46, logoL+3, logoT+134, -1, -1); for (i=41; i<=46; i++) { enableCtl(i, 3); setCtlOrder(i, 1); } } else // close About { for (i=41; i<=46; i++) enableCtl(i, 0); } if ((n==45) && (ctlEnabled(45)!=0)) shellExec("open", "http://www.russellcottrell.com/RCFilters", NULL, filterInstallDir); if ((n==46) && (ctlEnabled(46)!=0)) shellExec("open", filterInstallDir, NULL, NULL); if (ctl(54)) // Reset { setCtlVal(0,20); setCtlRange(0, 1, 200); setCtlVal(1,30); setCtlVal(2,0); if ((imageMode == RGBMode) || (imageMode == RGB48Mode)) { setCtlVal(3,0); setCtlVal(5,0); } setCtlVal(4,0); setCtlVal(6,0); setCtlVal(7,1); setCtlVal(10,1); setCtlVal(11,30); setCtlVal(12,1); setCtlVal(31,0); setCtlVal(32,100); setCtlVal(33,0); setCtlVal(34,0); setCtlVal(35,100); setCtlVal(36,0); setCtlVal(37,1); setCtlVal(39,0); setCtlVal(72,0); setCtlVal(73,127); setCtlVal(74,127); setCtlVal(75,255); setCtlVal(77,1); setCtlVal(78,1); setCtlVal(53,0); setCtlVal(54,0); triggerEvent(54, FME_CLICKED, 0); j0 = ctl(3); if (ctlEnabled(10) != 1) triggerEvent(10, FME_CLICKED, 0); // ***AFTER*** 54 j0 = getCtlRange(3, 1); triggerEvent(12, FME_CLICKED, 0); triggerEvent(37, FME_CLICKED, 0); triggerEvent(39, FME_CLICKED, 0); triggerEvent(77, FME_CLICKED, 0); triggerEvent(78, FME_CLICKED, 0); triggerEvent(53, FME_CLICKED, 0); } } if (n==0 && ctl(0)==200) enableCtl(6,3); if (n==6 && e==FME_VALUECHANGED) setCtlRange(25, 0, 200+ctl(6)); if (e==FME_INIT) // only works on the full-size image setZoom(-888); if (e==FME_SIZE) setZoom(-888); return false; } ForEveryTile: { int C=imageMode iH) { regionsW = regions; rW = ceil((double)iW/regionsW); regionsH = round((double)iH/rW); rH = ceil((double)iH/regionsH); } else { regionsH = regions; rH = ceil((double)iH/regionsH); regionsW = round((double)iW/rH); rW = ceil((double)iW/regionsW); } if (ctl(12)) { amountL = amountH; ssL = ssH; } minD = min(X/2, Y/2); if (radiusS > (double)minD) radiusS = (double)minD; //rcS = (int)ceil(radiusS); if (radiusH > (double)minD) radiusH = (double)minD; //rcH = (int)ceil(radiusH); allocArray(20, 256, 0, 0, 4); // histograms allocArray(21, 256, 0, 0, 4); allocArray(22, 256, 0, 0, 4); if (doingProxy) { // save the preview dimensions k0 = X; k1 = Y; y0 = radiusS; y1 = radiusH; } if (doingProxy) // need to save it due to a bug in AfhFM04dx64mt5c06.8bf j1 = getCtlRange(0, 1); allocArray(10, j1+1, j1+1, 3, 4); // averages sprintf(str1, "Blend Ranges: %d-%d %d-%d", ctl(72), ctl(73), ctl(74), ctl(75)); setCtlText(70, str1); // mode: 0 = grayscale, 1 = RGB “Grayscale Only,” 2 = RGB “Normal,” 3 = RGB “Color Only.” // Array(2) is the new src, modified by Lighten/Darken. // Array(2,x,y,0) is a virtual Y channel when mode = 1 (same as grayscale when mode = 0). // In “Grayscale Only” mode, all changes target the virtual Y channel to minimize runtime calculations, // and the color components of src (Cb and Cr) are added back at the very end. // Array(2,x,y,3) is an unmodified Y channel used by the dark/light mixer and histogram (beyond zmax). if ((imageMode==GrayScaleMode) || (imageMode==Gray16Mode)) mode = 0; else if (ctl(10)==2) // “Grayscale Only” mode = 1; else if (ctl(10)==1) // “Normal” mode = 2; else // “Color Only” mode = 3; zmax = ((mode < 2) ? 0 : 2); allocArray(2, X, Y, 4, 2); // the new src plus unmodified Y channel for (y=y_start; y 0)) { // begin masks ////////// masks ////////// for (y=y_start; y twH) putArray(0,x,y,1, 0); } } if (radiusS + radiusH > 0) { // can blur ////////// reduce masks ////////// if (!doingProxy) { Xnew = k0; // scale to the preview dimensions Ynew = k1; for (y=y_start; y 0.0) { // can blur qr = (z==zz0 ? radiusS : radiusH); b0 = 1.57825 + 2.44413*qr + 1.4281*qr*qr + 0.422205*qr*qr*qr; b1 = 2.44413*qr + 2.85619*qr*qr + 1.26661*qr*qr*qr; b2 = -(1.4281*qr*qr + 1.26661*qr*qr*qr ); b3 = 0.422205*qr*qr*qr; b1_b0 = b1/b0; b2_b0 = b2/b0; b3_b0 = b3/b0; BB = 1.0 - (b1_b0+b2_b0+b3_b0); for (y=y_start; yx_start; x--) { wn = BB*((double)getArray(0,x,y,z)) + (b1_b0*wn1 + b2_b0*wn2 + b3_b0*wn3); wn3=wn2; wn2=wn1; wn1=wn; } // for x for (x=x_start; xx_end_new-2-2*rcN; x--) // chill down forward { wn = BB*((double)getArray(0,x,y,z)) + (b1_b0*wn1 + b2_b0*wn2 + b3_b0*wn3); t2set(x,y,0, (int)wn); wn3=wn2; wn2=wn1; wn1=wn; } // for x // warmup backward - no write for (x=x_end_new-1-2*rcN; x=x_start; x--) // backward pass { wn = BB*(double)(tget(x,y,0)) + (b1_b0*wn1 + b2_b0*wn2 + b3_b0*wn3); putArray(0,x,y,z, (int)wn); wn3=wn2; wn2=wn1; wn1=wn; } // for x } // for y // NOW DO COLUMNS for (x=x_start; xy_start; y--) { wn = BB*((double)getArray(0,x,y,z)) + (b1_b0*wn1 + b2_b0*wn2 + b3_b0*wn3); wn3=wn2; wn2=wn1; wn1=wn; } // for y for (y=y_start; yy_end_new-2-2*rcN; y--) // chill down forward { wn = BB*((double)getArray(0,x,y,z)) + (b1_b0*wn1 + b2_b0*wn2 + b3_b0*wn3); t2set(x,y,0, (int)wn); wn3=wn2; wn2=wn1; wn1=wn; } // for y // warmup backward - no write for (y=y_end_new-1-2*rcN; y=y_start; y--) // backward pass { wn = BB*(double)(tget(x,y,0)) + (b1_b0*wn1 + b2_b0*wn2 + b3_b0*wn3); if (!doingProxy) t3set(x,y,z-2, (int)wn); // enlargement else putArray(0,x,y,z, (int)wn); // no enlargement wn3=wn2; wn2=wn1; wn1=wn; } // for y } // for x } // can blur } // for z ////////// enlarge masks ////////// if (!doingProxy) { Xold = Xnew; Yold = Ynew; Xnew = (X*X)/(Xnew); // enlarge to original size Ynew = (Y*Y)/(Ynew); for (y=y_start; y 0) && (mode < 3)) { for (z=0; z<=zmax; z++) { // apply curve before generating the unsharp mask bg = (double)getArray(2,x,y,z); fg = pow((bg/dC), curveS) * dC; fg = alpha4*bg + (1.0-alpha4)*fg; putArray(2,x,y,z, (int)fg); } } alpha4 = fmin(fmax((double)getArray(0,x,y,1)/dC, 0.0), 1.0); if (ctl(37) && (ctl(36) > 0) && (mode < 3)) { for (z=0; z<=zmax; z++) { // apply curve before generating the unsharp mask bg = (double)getArray(2,x,y,z); fg = (1.0 - pow(1.0 - (bg/dC), curveH)) * dC; // inverted fg = alpha4*bg + (1.0-alpha4)*fg; putArray(2,x,y,z, (int)fg); } } for (z=0; z<=zmax; z++) pset(x,y,z, getArray(2,x,y,z)); } } } // end masks //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// // adaptive contrast ////////// regions ////////// ////////// set up the histograms ////////// for (j=0; j 1)) // top edge { x00 = x_start+(i-1)*rW; x01 = x_start+(i+1)*rW; y00 = y_start; y01 = y_start+rH; } else // top right corner { x00 = x_start+(regionsW-1)*rW; x01 = x_end; y00 = y_start; y01 = y_start+rH; } } else if (h==1) { if (i==0) // left edge { x00 = x_start; x01 = x_start+rW; y00 = y_start; y01 = y_start+2*rH; if (regionsH==1) { y01 = y_start+rH; } } else if ((i < regionsW) && (regionsW > 1)) // row { x00 = x_start+(i-1)*rW; x01 = x_start+(i+1)*rW; y00 = y_start; y01 = y_start+2*rH; if (regionsH==1) { y01 = y_start+rH; } } else // right edge { x00 = x_start+(regionsW-1)*rW; x01 = x_end; y00 = y_start; y01 = y_start+2*rH; if (regionsH==1) { y01 = y_start+rH; } } } } // first row else if ((j 2)) // middle rows { if (h==0) { x00 = -1; } else { if (i==0) // left edge { x00 = x_start; x01 = x_start+rW; y00 = y_start+j*rH; y01 = y_start+(j+2)*rH; } else if ((i < regionsW) && (regionsW > 1)) // row { x00 = x_start+(i-1)*rW; x01 = x_start+(i+1)*rW; y00 = y_start+j*rH; y01 = y_start+(j+2)*rH; } else // right edge { x00 = x_start+(regionsW-1)*rW; x01 = x_end; y00 = y_start+j*rH; y01 = y_start+(j+2)*rH; } } } // middle rows else if (regionsH > 1) // bottom row { if (h==0) { x00 = -1; } else { if (i==0) // bottom left corner { x00 = x_start; x01 = x_start+rW; y00 = y_start+j*rH; y01 = y_end; } else if ((i < regionsW) && (regionsW > 1)) // bottom edge { x00 = x_start+(i-1)*rW; x01 = x_start+(i+1)*rW; y00 = y_start+j*rH; y01 = y_end; } else // bottom right corner { x00 = x_start+(regionsW-1)*rW; x01 = x_end; y00 = y_start+j*rH; y01 = y_end; } } } // bottom row ////////// get the histograms ////////// if (x00 > -1) { ffillArray(20, 0.0); ffillArray(21, 0.0); ffillArray(22, 0.0); Rmv = 0; Gmv = 0; Bmv = 0; pixels = 0.0; //(x01-x00) * (y01-y00); // count unselected pixels less // <== //plevel = (pixels * (1+level)) / 2; for (x=x00; x 0) Rmv = Rmv + (dC-Rmv)*level; } else // median { Rmv = 0; for (k=0; k<256; k++) { Rmv += fgetArray(20,k,0,0); if ((Rmv >= plevel) || (k == 255)) { Rmv = k; break; } } Rmv = Rmv / to8bit; // back to 16-bit } // median fputArray(10, i, j+h, 0, Rmv); if (mode > 1) { for (x=x00; x 0) { Gmv = Gmv + (dC-Gmv)*level; Bmv = Bmv + (dC-Bmv)*level; } } else // median { Gmv = 0; Bmv = 0; for (k=0; k<256; k++) { Gmv += fgetArray(21,k,0,0); if ((Gmv >= plevel) || (k == 255)) { Gmv = k; break; } } for (k=0; k<256; k++) { Bmv += fgetArray(22,k,0,0); if ((Bmv >= plevel) || (k == 255)) { Bmv = k; break; } } Gmv = Gmv / to8bit; Bmv = Bmv / to8bit; } // median fputArray(10, i, j+h, 1, Gmv); fputArray(10, i, j+h, 2, Bmv); } // (mode > 1) } } // for histograms h } // for histograms i ////////// pixels ////////// for (i=0; i Rm) Rv = (1-ssH)*Rv + ssH*(1 - (1-Rmv)*pow((1-Rv)/(1-Rmv), amountH)); // ejmartin, http://www.luminous-landscape.com/forum/index.php?topic=52364.0 Ri = min(max((int)(Rv*dC), 0), C); pset(x,y,0, Ri); if (mode > 1) { Gi = getArray(2,x,y,1); Gv = (double)Gi / dC; Y0 = fgetArray(10,i,j,1); Y1 = fgetArray(10,i+1,j,1); Yx0 = (d01*Y0)/(d01+d00) + (d00*Y1)/(d01+d00); Y0 = fgetArray(10,i,j+1,1); Y1 = fgetArray(10,i+1,j+1,1); Yx1 = (d01*Y0)/(d01+d00) + (d00*Y1)/(d01+d00); Gmv = (d11*Yx0)/(d11+d10) + (d10*Yx1)/(d11+d10); Gm = (int)Gmv; Gmv = Gmv / dC; if (Gi < Gm) Gv = (1-ssL)*Gv + ssL*Gmv*pow(Gv/Gmv, amountL); else if (Gi > Gm) Gv = (1-ssH)*Gv + ssH*(1 - (1-Gmv)*pow((1-Gv)/(1-Gmv), amountH)); Bi = getArray(2,x,y,2); Bv = (double)Bi / dC; Y0 = fgetArray(10,i,j,2); Y1 = fgetArray(10,i+1,j,2); Yx0 = (d01*Y0)/(d01+d00) + (d00*Y1)/(d01+d00); Y0 = fgetArray(10,i,j+1,2); Y1 = fgetArray(10,i+1,j+1,2); Yx1 = (d01*Y0)/(d01+d00) + (d00*Y1)/(d01+d00); Bmv = (d11*Yx0)/(d11+d10) + (d10*Yx1)/(d11+d10); Bm = (int)Bmv; Bmv = Bmv / dC; if (Bi < Bm) Bv = (1-ssL)*Bv + ssL*Bmv*pow(Bv/Bmv, amountL); else if (Bi > Bm) Bv = (1-ssH)*Bv + ssH*(1 - (1-Bmv)*pow((1-Bv)/(1-Bmv), amountH)); Gi = min(max((int)(Gv*dC), 0), C); Bi = min(max((int)(Bv*dC), 0), C); pset(x,y,1, Gi); pset(x,y,2, Bi); } // (mode > 1) } // for x } // for y } // for pixels i } // for histograms j ////////// blend range ////////// if ( ctl(78) && ((ctl(72)>0) || (ctl(73)>0) || (ctl(74)<255) || (ctl(75)<255)) ) { for (y=y_start; y wc1)) alpha = 0.0; else if ((bg >= bc0) && (bg < bc1)) alpha = (bg - bc0)/(bc1 - bc0); else if ((bg > wc0) && (bg <= wc1)) alpha = (wc1 - bg)/(wc1 - wc0); for (z=0; z<=zmax; z++) { bg2 = (double)src(x,y,z); fg2 = (double)pget(x,y,z); fg2 = alpha*fg2 + (1-alpha)*bg2; // blend range pset(x,y,z, (int)fg2); } } } } //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// ////////// darken/lighten mixer ////////// if (ctl(4) != 0) { for (y=y_start; y 0) && (bg > fg))) { if (mode < 2) bg2 = (double)getArray(2,x,y,3)/dC; else bg2 = (double)src(x,y,z)/dC; // the real src fg2 = (double)pget(x,y,z)/dC; fg2 = alpha2*bg2 + (1-alpha2)*fg2; pset(x,y,z, (int)(fg2*dC)); } } } } } //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// ////////// show masks ////////// for (y=y_start; y 0) { if (gg < t3get(x,y,0)) { // blend the highlight and shadow masks rr = C; bb = C - abs(t3get(x,y,0) - gg); } else if (t3get(x,y,0) < gg) { rr = C - abs(t3get(x,y,0) - gg); bb = C; } else { rr = C; bb = C; } gg = min(t3get(x,y,0), gg); pset(x,y,0,rr); pset(x,y,1,gg); pset(x,y,2,bb); } else pset(x,y,0, min(t3get(x,y,0), gg)); } } } //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// ////////// histograms ////////// allocArray(10, 2, 256, 0, 4); fillArray(10, 0); cWhite = RGB(255,255,255); cLGray = RGB(200,200,200); cGray = RGB(180,180,180); cDGray = RGB(80,80,80); cBlack = RGB(0,0,0); for (y=y_start; y nMax) nMax = n; if (!ctl(39)) { // show mask if (mode < 2) Yv = (double)pget(x,y,0); else Yv = (double)pget(x,y,0)*0.299 + (double)pget(x,y,1)*0.587 + (double)pget(x,y,2)*0.114; Yv *= to8bit; xx = (int)Yv; n = getArray(10,1,xx,0) + 1; putArray(10,1,xx,0, n); if (n > nMax) nMax = n; } } } if (ctlEnabled(41)==0) { if (nMax > (X*Y*4)/256) nMax = (X*Y*4)/256; startSetPixel(40); setRectFrame(0, 0, 258, 102, cGray); setRectFill(1, 1, 257, 101, cLGray); if (nMax > 0) { for (i=0; i<256; i++) { xx0 = i+1; xx1 = i+1+1; hh0 = 100-min((int)((double)getArray(10,0,i,0)*(100.0/(double)nMax)),100)+1; hh1 = 100-min((int)((double)getArray(10,1,i,0)*(100.0/(double)nMax)),100)+1; hh2 = 100+1; if (hh0 < hh1) { setRectFill(xx0, hh0, xx1, hh1, cWhite); setRectFill(xx0, hh1, xx1, hh2, cDGray); } else { setRectFill(xx0, hh1, xx1, hh0, cBlack); setRectFill(xx0, hh0, xx1, hh2, cDGray); } } } endSetPixel(40); } ////////// color ////////// if ((mode > 0) && !ctl(39)) // isRGB and not show mask { for (y=y_start; y 1) sat = (1-sat)*(vib-1) + 1; else sat = (sat)*(vib-1) + 1; Cb = Cb * sat; Cr = Cr * sat; Rv = Yv + 1.402*Cr; Gv = Yv - 0.34414*Cb - 0.71414*Cr; Bv = Yv + 1.772*Cb; pset(x,y,0, (int)Rv); pset(x,y,1, (int)Gv); pset(x,y,2, (int)Bv); } } } return true; } OnFilterEnd: { updateProgress(0,1); return false; }