Skip to main content
Participating Frequently
May 18, 2016
Question

How do I script the Paint Bucket?

  • May 18, 2016
  • 1 reply
  • 836 views

Re: Photoshop CS6, ver 13.0.1 (x32) on Win 7 SP1 (64-bit) 16gB RAM

When scripting the Trim function in Photoshop, some of my photos apparently have non-white pixels on the canvas that don't match white color of the top left corner pixel. Thus some sides are not trimmed due to problem pixels while the other sides are neatly trimmed. An example where the top is not trimmed while the left, right and bottom are trimmed is at http://www.sylloge.net/Upload75/IFN-8480988_02.tif (apologies for defacing due museum's copyright).

This is easily repaired by using the Paint Bucket with white at opacity 100%, tolerance 10 near the top left of  background. How do I script the Paint Bucket at position 10 pixels from left, 10 pixels from top?

Is Paint Bucket the right approach to the problem?

This topic has been closed for replies.

1 reply

JJMack
Community Expert
Community Expert
May 18, 2016

If Trim using the top left or bottom right corner do not work adding a white pixel there may not work either.  I do not know how trim works or how much tolerance it may use.  I would suggest trying to simulate a trim with some high tolerance using the magic wand. If its a background layer image. Convert it to a normal layer and  add a white layer under that layer the use the magic wand tool to select contiguous pixels sampling areas on the boarder of the canvas  invert and clear pixels on that layer.  Do this several time sample different point about the canvas border,   Then get the layer's  bounds and crop the canvas to that layers bounds..

I wrote a script something like that to trim layer that have borders there was no cropping done.

try { if(app.documents.length>0){ app.activeDocument.suspendHistory ('Trim Layers', 'TrimLayers();') } }

catch(e) { alert( e + ': on line '  + e.line );}

function TrimLayers() {

  var orig_ruler_units = app.preferences.rulerUnits; // save user ruler units 

  var orig_display_dialogs = app.displayDialogs; // Save users Displat Doalogs

  app.preferences.rulerUnits = Units.PIXELS; // set the ruler units to PIXELS

  app.displayDialogs = DialogModes.NO; // Set Dialogs off

  var doc  = app.activeDocument; // get current document

  var saveactiveLayer = doc.activeLayer; // save activeLayer

  doc.selection.deselect(); // make sure ther is no active selection

  try {processArtLayers(doc);} // Process all Layers

  catch(e) { alert( e + ': on line '  + e.line );} // some unexpected error

  doc.selection.deselect(); // make sure ther is no active selection

  try { doc.activeLayer = saveactiveLayer;} // restore activeLayer

  catch(e) { } // may have been deleted

  app.displayDialogs = orig_display_dialogs; // Reset display dialogs

  app.preferences.rulerUnits = orig_ruler_units; // reset units to original settings

}

///////////////////////////////////////////////////////////////////////////////

// Function: processsArtLayers

// Input: document or layer set

///////////////////////////////////////////////////////////////////////////////

function processArtLayers(obj) {

    for(var i = obj.artLayers.length-1;0<= i; i--) { // for Layers

  try {TrimLayer(obj.artLayers); } // process Art Layer

  catch(e) {} // don't stop on errors

  }

    for(var i=obj.layerSets.length-1;0<=i;i--) { // for Layer sets

  try {processArtLayers(obj.layerSets);} // process Layer Set

  catch(e) {} // don't stop on errors

  }

}

function TrimLayer(layer) {

  // do nothing if layer is background or locked 

  if(layer.isBackgroundLayer || layer.allLocked || layer.pixelsLocked || layer.positionLocked || layer.transparentPixelsLocked ) return;

  //if(layer.protectArtboardAutonest ) return;

  if( layer.kind != LayerKind.NORMAL) return; // do nothing if not normal layer  

  app.activeDocument.activeLayer = layer; // target layer

  var bounds = layer.bounds; // layer bounds 

  var LWidth = bounds[2]-bounds[0]; // layer width 

  var LHeight = bounds[3]-bounds[1]; // layer height

  var Lleft =  bounds[0]; // layer left x

  var Lright =  bounds[2]; // layer right x

  var Ltop =  bounds[1]; // layer top y

  var Lbottom =  bounds[3]; // layer bottom y

  var tlrnc = 20; // tolerance

  i=0.6; // fudge factor

  try {

  MagicWand((Lleft+i), (Ltop+i), tlrnc); // top left

  app.activeDocument.selection.clear(); // clear

  }

  catch(e) {}; // do nothing

  try {

  MagicWand((Lleft+LWidth/2), (Ltop+i), tlrnc); // top middle

  app.activeDocument.selection.clear(); // clear

  }

  catch(e) {};   // do nothing

  try {

  MagicWand((Lright-i), (Ltop+i), tlrnc); // top right

  app.activeDocument.selection.clear(); // clear

  }

  catch(e) {}; // do nothing

  try {

  MagicWand((Lleft+i), (Ltop+LHeight/2), tlrnc); // middle left

  app.activeDocument.selection.clear(); // clear

  }

  catch(e) {}; // do nothing

  try {

  MagicWand((Lright-i), (Ltop+LHeight/2), tlrnc); // middle right

  app.activeDocument.selection.clear(); // clear

  }

  catch(e) {}; // do nothing

  try {

  MagicWand((Lleft+i), (Lbottom-i), tlrnc); // bottom left

  app.activeDocument.selection.clear(); // clear

  }

  catch(e) {};   // do nothing

  try {

  MagicWand((Lleft+LWidth/2), (Lbottom-i), tlrnc); // bottom middle

  app.activeDocument.selection.clear(); // clear

  }

  catch(e) {}; // do nothing

  try {

  MagicWand((Lright-i), (Lbottom-i), tlrnc); // bottom right

  app.activeDocument.selection.clear(); // clear

  }

  catch(e) {};   // do nothing

}

function MagicWand(x,y,tolerance) {

var idsetd = charIDToTypeID( "setd" );

    var desc106 = new ActionDescriptor();

    var idnull = charIDToTypeID( "null" );

        var ref60 = new ActionReference();

        var idChnl = charIDToTypeID( "Chnl" );

        var idfsel = charIDToTypeID( "fsel" );

        ref60.putProperty( idChnl, idfsel );

    desc106.putReference( idnull, ref60 );

    var idT = charIDToTypeID( "T   " );

        var desc107 = new ActionDescriptor();

        var idHrzn = charIDToTypeID( "Hrzn" );

        var idPxl = charIDToTypeID( "#Pxl" );

        desc107.putUnitDouble( idHrzn, idPxl, x );

        var idVrtc = charIDToTypeID( "Vrtc" );

        var idPxl = charIDToTypeID( "#Pxl" );

        desc107.putUnitDouble( idVrtc, idPxl, y );

    var idPnt = charIDToTypeID( "Pnt " );

    desc106.putObject( idT, idPnt, desc107 );

    var idTlrn = charIDToTypeID( "Tlrn" );

    desc106.putInteger( idTlrn, tolerance );

    var idAntA = charIDToTypeID( "AntA" );

    desc106.putBoolean( idAntA, true );

executeAction( idsetd, desc106, DialogModes.NO );

}

JJMack
Participating Frequently
June 16, 2016

I worked this part out on my own using the Script Listener which leaves you with some mysteries. Not sure what it all means, but it works!

You must provide value for the toler variable when calling this function. The bucket dump coordinates are hard-coded to 10x10.

Thanks to JJMack for his many instructive posts on the forums.

function UsePaintBucket(){

    var idFl = charIDToTypeID( "Fl  " ); // Fill

    var SetParams = new ActionDescriptor();

    var idFrom = charIDToTypeID( "From" ); // From

    var Coordinates = new ActionDescriptor(); //coordinates for Paint Bucket tool to use

    // set position for paint bucket to dump

    var idHrzn = charIDToTypeID( "Hrzn" ); // Horizontal position

    var idPxl = charIDToTypeID( "#Pxl" );  // in pixels

    Coordinates.putUnitDouble( idHrzn, idPxl, 10.000000 );

    var idVrtc = charIDToTypeID( "Vrtc" ); // Vertical position

    var idPxl = charIDToTypeID( "#Pxl" ); // in pixels

    Coordinates.putUnitDouble( idVrtc, idPxl, 10.000000 );

    var idPnt = charIDToTypeID( "Pnt " ); // Paint

    SetParams.putObject( idFrom, idPnt, Coordinates );

    // Set tolerance to user-specified value

    var idTlrn = charIDToTypeID( "Tlrn" ); // Tolerence

    SetParams.putInteger( idTlrn, toler );  // user's specified tolerance value

    // Set anti-alias True

    var idAntA = charIDToTypeID( "AntA" ); // Anti-alias

    SetParams.putBoolean( idAntA, true ); // set to True

    // What are these?

    var idUsng = charIDToTypeID( "Usng" );

    var idFlCn = charIDToTypeID( "FlCn" );

    var idFrgC = charIDToTypeID( "FrgC" );

    SetParams.putEnumerated( idUsng, idFlCn, idFrgC );

    // Set opacity to 100 per cent

    var idOpct = charIDToTypeID( "Opct" ); // Opacity

    var idPrc = charIDToTypeID( "#Prc" ); // Percentage

    SetParams.putUnitDouble( idOpct, idPrc, 100.000000 );   

    executeAction( idFl, SetParams, DialogModes.NO );

}