%ffp Category :"RC Filters" Title :"Very High Radius Contrast Mask" Filename :"VHRContrastMask.8bf" Description:"A Contrast Mask filter for images of any size." 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 /* Acknowledgements: Recursive gaussian demo code implemented by Tom Fiddaman from the article: Title: Recursive implementation of the Gaussian filter Authors: I.T. Young, L.J. van Vliet in: Signal Processing, vol. 44, no. 2, 1995, 139-151. Interpolation by Harald Heim The Plugin Site, http://thepluginsite.com Copyright 2002 by Harald Heim */ Dialog: Size=(590,406), MaxBox, MinBox, Theme=on, Initevent SupportedModes: RGBMode, RGB48Mode, GrayScaleMode, Gray16Mode Embed: Bitmap="logo.bmp" ctl(0): Standard, "Radius", Range=(0,100), Divisor=10, pos=(400,40), Val=6, Gamma=200 ctl(1): StaticText, "0px", pos=(525,40), size=(60,10) ctl(2): Standard, "Amount", Range=(-100,100), pos=(400,52), Val=100 ctl(3): Standard, "Curve", Range=(-100,100), pos=(414,80), size=(115,*), Val=0 ctl(4): Standard, "Dark/Light Mixer", Range=(-100,100), pos=(414,92), size=(115,*), Val=0 ctl(70): StaticText, "Blend Ranges:", pos=(365,124), size=(160,10) ctl(71): GroupBox, pos=(363,131), size=(204,28) ctl(72): Trackbar(Noticks,Bottom,Toptip), Pos=(365,136), Size=(200,11), Range=(0,255), Val=0, Color=Black ctl(73): Trackbar(Noticks,Top,Toptip), Pos=(365,146), Size=(200,11), Range=(0,255), Val=0, Color=Black ctl(74): Trackbar(Noticks,Bottom,Toptip), Pos=(365,161), Size=(200,11), Range=(0,255), Val=255, Color=White ctl(75): Trackbar(Noticks,Top,Toptip), Pos=(365,171), Size=(200,11), Range=(0,255), Val=255, Color=White ctl(76): GroupBox, pos=(363,156), size=(204,28) ctl(77): checkbox(Pushlike, 3State), text="All", Pos=(484,122), Size=(40,12), val=0 ctl(78): checkbox(Pushlike), text="Enabled", Pos=(526,122), Size=(40,12), val=1 ctl(40): OwnerDraw(drawitem), pos=(378,196), 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) ctl(50): Pushbutton, "100%", Pos=(160,391), Anchor=ANCHOR_LEFT|ANCHOR_BOTTOM, Size=(30,14), Action=Preview ctl(51): Pushbutton, "Fit", Pos=(195,391), Anchor=ANCHOR_LEFT|ANCHOR_BOTTOM, Size=(30,14), Action=Preview // VHRContrastMaskHelp.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); 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 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 if (ctl(77)==1) { setCtlVal(bctl0,0); setCtlVal(bctl1,0); setCtlVal(wctl0,0); setCtlVal(wctl1,127); setCtlText(77, "Shadows"); } else { setCtlVal(bctl0,128); setCtlVal(bctl1,255); setCtlVal(wctl0,255); setCtlVal(wctl1,255); setCtlText(77, "Highlights"); } } if (n==78) setCtlText(78, ctl(78) ? "Enabled" : "Off"); 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) || (n==54 && (e==FME_CUSTOMEVENT))) // Reset { setCtlVal(0,6); setCtlVal(2,100); setCtlVal(3,0); setCtlVal(4,0); setCtlVal(72,0); setCtlVal(73,0); setCtlVal(74,255); setCtlVal(75,255); setCtlVal(77,0); setCtlVal(78,1); setCtlVal(53,0); setCtlVal(54,0); triggerEvent(54, FME_CLICKED, 0); // ***AFTER*** 54 triggerEvent(53, FME_CLICKED, 0); triggerEvent(77, FME_CLICKED, 0); triggerEvent(78, FME_CLICKED, 0); } } if (e==FME_INIT) setZoom(-888); if (n==50) setZoom(1); else if (n==51) setZoom(-888); return false; } ForEveryTile: { int C=imageMode (double)minD) radius = (double)minD; //rcS = (int)ceil(radiusS); if (doingProxy) { // save the preview dimensions k0 = X; k1 = Y; x0 = radius; } snprintf(str2, 4, "%f", ((radius*(double)scaleFactor)/diag) * 100); // show the percent strcat(str2, " %"); setCtlText(1, str2); strset(str2, '\0'); sprintf(str1, "Blend Ranges: %d-%d %d-%d", ctl(72), ctl(73), ctl(74), ctl(75)); setCtlText(70, str1); // mode: 0 = grayscale, 2 = RGB. // Array(2,x,y,0) is an unmodified Y channel when mode = 2 used by the dark/light mixer and histogram. // Array(2,x,y,1) is the inverted copy. if ((imageMode==GrayScaleMode) || (imageMode==Gray16Mode)) mode = 0; else mode = 2; zmax = mode; allocArray(2, X, Y, 2, 2); for (y=y_start; y 0) { // can blur ////////// reduce ////////// if (!doingProxy) { Xnew = k0; // scale to the preview dimensions Ynew = k1; for (y=y_start; yx_start; x--) { wn = BB*((double)getArray(2,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*rc; x--) // chill down forward { wn = BB*((double)getArray(2,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*rc; x=x_start; x--) // backward pass { wn = BB*(double)(tget(x,y,0)) + (b1_b0*wn1 + b2_b0*wn2 + b3_b0*wn3); putArray(2,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(2,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*rc; y--) // chill down forward { wn = BB*((double)getArray(2,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*rc; 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, (int)wn); // enlargement else putArray(2,x,y,z, (int)wn); // no enlargement wn3=wn2; wn2=wn1; wn1=wn; } // for y } // for x ////////// enlarge ////////// if (!doingProxy) { Xold = Xnew; Yold = Ynew; z = 1; Xnew = (X*X)/(Xnew); // enlarge to original size Ynew = (Y*Y)/(Ynew); for (y=y_start; y 0) curve = 1.0 / (1.0 + curve/(100/3)); else curve = 1.0 + -curve/(100/3); for (y=y_start; y0) || (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))) { bg2 = (double)src(x,y,z)/dC; fg2 = (double)pget(x,y,z)/dC; fg2 = alpha2*bg2 + (1-alpha2)*fg2; pset(x,y,z, (int)(fg2*dC)); } } } } } ////////// 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 (mode == 0) 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); } return true; } OnFilterEnd: { updateProgress(0,1); return false; }