Skip to main content
Franck Payen
Inspiring
February 12, 2015
Open for Voting

Photoshop: Minimum AND Maximum sharing one dialog

  • February 12, 2015
  • 6 replies
  • 588 views
Hi there.

Can we have minimum AND maximum filter in the same window ?
I’m not using them enough to assign shortcuts or to memorize if black or white will grow.
Half of the time i pick one for the other and have to close and dig again inside the menus...
I would love it if they were joined.

6 replies

Stephen Marsh
Community Expert
Community Expert
September 30, 2024
quote
Or could the slider go to negative numbers for the opposite behaviour?
By @PECourtejoie 

 

That's an interesting idea!

 

/*
Combined Minimum-Maximum Filters v1-1 scriptUI GUI.jsx
v1.0 - 1st October 2024, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-ideas/photoshop-minimum-and-maximum-sharing-one-dialog/idi-p/12249090
*/

#target photoshop

main();

function main() {
    var dlg = new Window("dialog", "Combined Minimum/Maximum Filters (v1.1)");
    dlg.orientation = "column";
    dlg.alignChildren = ["left", "top"];
    dlg.spacing = 10;
    dlg.margins = 16;

    // Add explanatory text
    var explanationText = dlg.add("statictext", undefined, "Negative = Max  |  Positive = Min");
    explanationText.alignment = ["fill", "top"];

    var radiusGroup = dlg.add("group");
    radiusGroup.add("statictext", undefined, "Radius:");
    var radiusSlider = radiusGroup.add("slider", undefined, 0, -500, 500);
    var radiusValue = radiusGroup.add("edittext", undefined, "0");
    radiusValue.characters = 5;

    var shapeGroup = dlg.add("group");
    shapeGroup.add("statictext", undefined, "Preserve:");
    var shapeDropdown = shapeGroup.add("dropdownlist", undefined, ["Squareness", "Roundness"]);
    shapeDropdown.selection = 0;

    var previewCheckbox = dlg.add("checkbox", undefined, "Preview");
    previewCheckbox.value = true;  // Set preview checkbox to true by default

    var buttonGroup = dlg.add("group");
    buttonGroup.orientation = "row";
    buttonGroup.alignChildren = ["right", "center"];  // Align children to the right
    buttonGroup.alignment = ["fill", "top"];  // Make the group fill the width of the dialog
    var okButton = buttonGroup.add("button", undefined, "OK");
    var cancelButton = buttonGroup.add("button", undefined, "Cancel");

    var initialState;

    function saveInitialState() {
        initialState = app.activeDocument.activeHistoryState;
    }

    function resetToInitialState() {
        if (initialState) {
            app.activeDocument.activeHistoryState = initialState;
        }
    }

    function applyPreview() {
        if (previewCheckbox.value) {
            resetToInitialState();
            applyFilter();
        }
    }

    function handleControlChange() {
        updateShapeDropdown();
        applyPreview();
    }

    function updateShapeDropdown() {
        var radiusVal = parseInt(radiusValue.text);
        if (radiusVal < 0) {
            shapeDropdown.selection = 0;  // Set to "Squareness"
            shapeDropdown.enabled = false;
        } else {
            shapeDropdown.enabled = true;
        }
    }

    radiusSlider.onChanging = function() {
        radiusValue.text = Math.round(this.value);
        handleControlChange();
    };

    radiusValue.onChange = function() {
        var value = parseInt(this.text);
        if (isNaN(value)) value = 0;
        if (value < -500) value = -500;
        if (value > 500) value = 500;
        this.text = value;
        radiusSlider.value = value;
        handleControlChange();
    };

    shapeDropdown.onChange = handleControlChange;

    previewCheckbox.onClick = function() {
        if (this.value) {
            if (!initialState) {
                saveInitialState();
            }
            applyPreview();
        } else {
            resetToInitialState();
        }
    };

    okButton.onClick = function() {
        if (!previewCheckbox.value) {
            applyFilter();
        }
        dlg.close();
    };

    cancelButton.onClick = function() {
        resetToInitialState();
        dlg.close();
    };

    function applyFilter() {
        var radius = Math.abs(parseInt(radiusValue.text));
        var shape = shapeDropdown.selection.text.toLowerCase();
        if (parseInt(radiusValue.text) >= 0) {
            minimum(radius, shape);
        } else {
            maximum(radius, shape);
        }
    }

    updateShapeDropdown();  // Set initial state of dropdown
    saveInitialState();  // Save initial state when dialog is created
    applyPreview();  // Apply initial preview since checkbox is true by default

    dlg.show();
}

function minimum(radius, shape) {
    var s2t = function (s) { return app.stringIDToTypeID(s); };
    var descriptor = new ActionDescriptor();
    descriptor.putUnitDouble(s2t("radius"), s2t("pixelsUnit"), radius);
    descriptor.putEnumerated(s2t("preserveShape"), s2t("preserveShape"), s2t(shape));
    executeAction(s2t("minimum"), descriptor, DialogModes.NO);
}

function maximum(radius, shape) {
    var s2t = function (s) { return app.stringIDToTypeID(s); };
    var descriptor = new ActionDescriptor();
    descriptor.putUnitDouble(s2t("radius"), s2t("pixelsUnit"), radius);
    descriptor.putEnumerated(s2t("preserveShape"), s2t("preserveShape"), s2t(shape));
    executeAction(s2t("maximum"), descriptor, DialogModes.NO);
}
Stephen Marsh
Community Expert
Community Expert
September 30, 2024

More as an exercise than anything else, however, I hope that somebody finds it useful!

 

/*
Combined Minimum-Maximum Filters v1 scriptUI GUI.jsx
v1.0 - 1st October 2024, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-ideas/photoshop-minimum-and-maximum-sharing-one-dialog/idi-p/12249090
*/

#target photoshop

main();

function main() {
    var dlg = new Window("dialog", "Combined Minimum/Maximum Filters (v1.0)");
    dlg.orientation = "column";
    dlg.alignChildren = ["left", "top"];
    dlg.spacing = 10;
    dlg.margins = 16;

    var radioGroup = dlg.add("group");
    radioGroup.orientation = "row";
    var minRadio = radioGroup.add("radiobutton", undefined, "Minimum (Expand)");
    var maxRadio = radioGroup.add("radiobutton", undefined, "Maximum (Contract)");
    minRadio.value = true;

    var radiusGroup = dlg.add("group");
    radiusGroup.add("statictext", undefined, "Radius:");
    var radiusSlider = radiusGroup.add("slider", undefined, 1, 1, 500);
    var radiusValue = radiusGroup.add("editnumber", undefined, "1");
    radiusValue.characters = 4;

    var shapeGroup = dlg.add("group");
    shapeGroup.add("statictext", undefined, "Preserve:");
    var shapeDropdown = shapeGroup.add("dropdownlist", undefined, ["Squareness", "Roundness"]);
    shapeDropdown.selection = 0;

    var previewCheckbox = dlg.add("checkbox", undefined, "Preview");
    previewCheckbox.value = true;  // Set preview checkbox to true by default

    var buttonGroup = dlg.add("group");
    buttonGroup.orientation = "row";
    buttonGroup.alignChildren = ["right", "center"];  // Align children to the right
    buttonGroup.alignment = ["fill", "top"];  // Make the group fill the width of the dialog
    var okButton = buttonGroup.add("button", undefined, "OK");
    var cancelButton = buttonGroup.add("button", undefined, "Cancel");

    var initialState;

    function saveInitialState() {
        initialState = app.activeDocument.activeHistoryState;
    }

    function resetToInitialState() {
        if (initialState) {
            app.activeDocument.activeHistoryState = initialState;
        }
    }

    function applyPreview() {
        if (previewCheckbox.value) {
            resetToInitialState();
            applyFilter();
        }
    }

    function handleControlChange() {
        applyPreview();
    }

    function updateShapeDropdown() {
        if (maxRadio.value) {
            shapeDropdown.selection = 0;  // Set to "Squareness"
            shapeDropdown.enabled = false;
        } else {
            shapeDropdown.enabled = true;
        }
    }

    radiusSlider.onChanging = function() {
        radiusValue.text = Math.round(this.value);
        handleControlChange();
    };

    radiusValue.onChange = function() {
        var value = parseInt(this.text);
        if (isNaN(value) || value < 1) value = 1;
        if (value > 500) value = 500;
        this.text = value;
        radiusSlider.value = value;
        handleControlChange();
    };

    minRadio.onClick = function() {
        updateShapeDropdown();
        handleControlChange();
    };

    maxRadio.onClick = function() {
        updateShapeDropdown();
        handleControlChange();
    };
    
    shapeDropdown.onChange = handleControlChange;

    previewCheckbox.onClick = function() {
        if (this.value) {
            if (!initialState) {
                saveInitialState();
            }
            applyPreview();
        } else {
            resetToInitialState();
        }
    };

    okButton.onClick = function() {
        if (!previewCheckbox.value) {
            applyFilter();
        }
        dlg.close();
    };

    cancelButton.onClick = function() {
        resetToInitialState();
        dlg.close();
    };

    function applyFilter() {
        var radius = parseInt(radiusValue.text);
        var shape = shapeDropdown.selection.text.toLowerCase();
        if (minRadio.value) {
            minimum(radius, shape);
        } else {
            maximum(radius, shape);
        }
    }

    updateShapeDropdown();  // Set initial state of dropdown
    saveInitialState();  // Save initial state when dialog is created
    applyPreview();  // Apply initial preview since checkbox is true by default

    dlg.show();
}

function minimum(radius, shape) {
    var s2t = function (s) { return app.stringIDToTypeID(s); };
    var descriptor = new ActionDescriptor();
    descriptor.putUnitDouble(s2t("radius"), s2t("pixelsUnit"), radius);
    descriptor.putEnumerated(s2t("preserveShape"), s2t("preserveShape"), s2t(shape));
    executeAction(s2t("minimum"), descriptor, DialogModes.NO);
}

function maximum(radius, shape) {
    var s2t = function (s) { return app.stringIDToTypeID(s); };
    var descriptor = new ActionDescriptor();
    descriptor.putUnitDouble(s2t("radius"), s2t("pixelsUnit"), radius);
    descriptor.putEnumerated(s2t("preserveShape"), s2t("preserveShape"), s2t(shape));
    executeAction(s2t("maximum"), descriptor, DialogModes.NO);
}

 

https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html

skilled_thinking15A8
Adobe Employee
Adobe Employee
May 6, 2020
For the unified Min/Max filter, it will be great to add an option to extend/contrast only in the edge (with a threshold and feather sliders) to preserve colors and shades on a non-solid color layer content. 
PECourtejoie
Community Expert
Community Expert
May 6, 2020
The most frustrating moment is when you think you close the wrong filter, think you pick the other one, and pick the same one!
Franck Payen
Inspiring
May 6, 2020
It might be more explicit with an image :

PECourtejoie
Community Expert
Community Expert
May 5, 2020
If they need to stay for actions compatibility, could we have a switch that jumps to the other filter?
Or could the slider go to negative numbers for the opposite behaviour?