Converting B&W Clipart With A Script

Anyone, especially newbies, asking for help with Photoshop Scripting and Photoshop Automation - as opposed to those contributing to discussion about an aspect of Photoshop Scripting

Moderators: Tom, Kukurykus

jmarkt

Converting B&W Clipart With A Script

Post by jmarkt »

Attached is an example file:https://jumpshare.com/b/PNpGmixLYcwaK0P9NNPkgx, and here's the issue:

The origin image on the left is one of many PNG format clipart images; thus, there is no white - only black lines are visible when this image is placed on another background. If the background is a lighter color, this works fine; however, when placed on a dark background, the image is hard to decipher.

Therefore, I need to "fill in" the transparent body of the origin image with white, and "knock out", or make transparent, the black portion of the origin image, creating the image on the right, and retaining the PNG format. Is it possible for a script to accomplish this? I can get the job done, one at a time, but my task is to accomplish this with approximately 10,000 images!

Hope someone can find the time to help - much appreciated!!!
pfaffenbichler

Converting B&W Clipart With A Script

Post by pfaffenbichler »

This may provide a starting point.
Whether the current expansion of the Selection for white meets with your needs you’ll have to figure out yourself and the Script is based on the assumption that the upper left corner of all the illustrations is white.
Should the latter not be the case other approaches to finding a white pixel (possibly with a Working Path) seem possible but would hardly be worth the trouble if the assumption should be correct anyway … 
Code: Select all// 2015, use it at your own risk;
#target "photoshop-70.032"
if (app.documents.length > 0) {
//////////////////////////////////////////
var myDocument = app.activeDocument;
// check there is but one layer;
if (myDocument.layers.length == 1) {
var originalUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var theLayer = myDocument.activeLayer;
// load red channel;
myDocument.selection.load(myDocument.channels[0], SelectionType.REPLACE, true);
// create layer;
var blackLayer = solidColorLayer (0,0,0);
// check upper left pixel is white;
myDocument.activeLayer = theLayer;
var theX = 1;
var theY = 1;
var theColor = getColor (theX, theY);
if (theColor[0] != 255 ||  theColor[1] != 255 ||  theColor[2] != 255) {
alert ("upper left corner is not white")
} else {
magicWand(theX, theY);
// expand and invert selection;
myDocument.selection.expand(3);
myDocument.selection.invert();
// create layer;
var whiteLayer = solidColorLayer (255,255,255);
};
// remove original layer and merge;
theLayer.remove();
if (myDocument.layers.length > 1) {myDocument.mergeVisibleLayers()};
// reset;
app.preferences.rulerUnits = originalUnits;
}
};
//////////////////////////////////////////
////// function to create a solid color layer //////
function solidColorLayer (theRed, theGreen, theBlue) {
// =======================================================
var idMk = charIDToTypeID( "Mk  " );
    var desc3 = new ActionDescriptor();
    var idnull = charIDToTypeID( "null" );
        var ref1 = new ActionReference();
        var idcontentLayer = stringIDToTypeID( "contentLayer" );
        ref1.putClass( idcontentLayer );
    desc3.putReference( idnull, ref1 );
    var idUsng = charIDToTypeID( "Usng" );
        var desc4 = new ActionDescriptor();
        var idType = charIDToTypeID( "Type" );
            var desc5 = new ActionDescriptor();
            var idClr = charIDToTypeID( "Clr " );
                var desc6 = new ActionDescriptor();
                var idRd = charIDToTypeID( "Rd  " );
                desc6.putDouble( idRd, theRed );
                var idGrn = charIDToTypeID( "Grn " );
                desc6.putDouble( idGrn,theGreen );
                var idBl = charIDToTypeID( "Bl  " );
                desc6.putDouble( idBl, theBlue );
            var idRGBC = charIDToTypeID( "RGBC" );
            desc5.putObject( idClr, idRGBC, desc6 );
        var idsolidColorLayer = stringIDToTypeID( "solidColorLayer" );
        desc4.putObject( idType, idsolidColorLayer, desc5 );
    var idcontentLayer = stringIDToTypeID( "contentLayer" );
    desc3.putObject( idUsng, idcontentLayer, desc4 );
executeAction( idMk, desc3, DialogModes.NO );
return app.activeDocument.activeLayer
};
////// magic wand //////
function magicWand (theX, theY) {
//use magic wand
    var idsetd = charIDToTypeID( "setd" );
        var desc263 = new ActionDescriptor();
        var idnull = charIDToTypeID( "null" );
            var ref123 = new ActionReference();
            var idChnl = charIDToTypeID( "Chnl" );
            var idfsel = charIDToTypeID( "fsel" );
            ref123.putProperty( idChnl, idfsel );
        desc263.putReference( idnull, ref123 );
        var idT = charIDToTypeID( "T   " );
            var desc264 = new ActionDescriptor();
            var idHrzn = charIDToTypeID( "Hrzn" );
            var idRlt = charIDToTypeID( "#Rlt" );
            desc264.putUnitDouble( idHrzn, idRlt, theX);
            var idVrtc = charIDToTypeID( "Vrtc" );
            var idRlt = charIDToTypeID( "#Rlt" );
            desc264.putUnitDouble( idVrtc, idRlt, theY);
        var idPnt = charIDToTypeID( "Pnt " );
        desc263.putObject( idT, idPnt, desc264 );
        var idTlrn = charIDToTypeID( "Tlrn" );
        desc263.putInteger( idTlrn, 1 );
    executeAction( idsetd, desc263, DialogModes.NO );
};
////// get color //////
function getColor (theX, theY) {
// select color sampler tool;
// =======================================================
var idslct = charIDToTypeID( "slct" );
    var desc3 = new ActionDescriptor();
    var idnull = charIDToTypeID( "null" );
        var ref2 = new ActionReference();
        var idcolorSamplerTool = stringIDToTypeID( "colorSamplerTool" );
        ref2.putClass( idcolorSamplerTool );
    desc3.putReference( idnull, ref2 );
    var iddontRecord = stringIDToTypeID( "dontRecord" );
    desc3.putBoolean( iddontRecord, true );
    var idforceNotify = stringIDToTypeID( "forceNotify" );
    desc3.putBoolean( idforceNotify, true );
executeAction( idslct, desc3, DialogModes.NO );
// set sampler;
// =======================================================
var idMk = charIDToTypeID( "Mk  " );
    var desc4 = new ActionDescriptor();
    var idnull = charIDToTypeID( "null" );
        var ref3 = new ActionReference();
        var idClSm = charIDToTypeID( "ClSm" );
        ref3.putClass( idClSm );
    desc4.putReference( idnull, ref3 );
    var idPstn = charIDToTypeID( "Pstn" );
        var desc5 = new ActionDescriptor();
        var idHrzn = charIDToTypeID( "Hrzn" );
        var idPxl = charIDToTypeID( "#Pxl" );
        desc5.putUnitDouble( idHrzn, idPxl, theX );
        var idVrtc = charIDToTypeID( "Vrtc" );
        var idPxl = charIDToTypeID( "#Pxl" );
        desc5.putUnitDouble( idVrtc, idPxl, theY );
    var idPnt = charIDToTypeID( "Pnt " );
    desc4.putObject( idPstn, idPnt, desc5 );
executeAction( idMk, desc4, DialogModes.NO );
// forground color;
var theSampler = activeDocument.colorSamplers[activeDocument.colorSamplers.length - 1];
var theColor = theSampler.color;
theSampler.remove();
app.preferences.rulerUnits = originalUnits;
return [theColor.rgb.red, theColor.rgb.green, theColor.rgb.blue];
};
jmarkt

Converting B&W Clipart With A Script

Post by jmarkt »

Thanks so much, pfaffenbichler, for the quick reply and help! Much appreciated.

I copied the script into ExtendScript and saved it. I then opened one of the clipart images and selected the script in PS, and it returned the following:

Error 8800: General Photoshop error occurred. This functionality may not be available in this version of Photoshop.

- <no additional information available>
Line: 130
-> var theColor = theSampler.color;"

I failed to mention that I'm using CS5, if that makes a difference? Probably something I'm doing wrong?? The Forum will not allow a PNG or JPG extension as an upload, so I've placed a couple of the files I was working with at this location: https://jumpshare.com/b/3ROsCQEcJM5YYUpbUt6g

Thanks again for your willingness to help!
pfaffenbichler

Converting B&W Clipart With A Script

Post by pfaffenbichler »

I only tested »monsterInJeep.png« and here the problems are that the Layer already has transparency and the illustration touches the edges – please try this:
Code: Select all// 2015, use it at your own risk;
#target "photoshop-70.032"
if (app.documents.length > 0) {
//////////////////////////////////////////
var myDocument = app.activeDocument;
// check there is but one layer;
if (isBlackAndWhite () == true) {
var originalUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
myDocument.flatten();
var theLayer = myDocument.activeLayer;
// change canvas to ascertain white background edge;
resetForeAndBackgroud ();
var theW = myDocument.width;
var theH = myDocument.height;
myDocument.resizeCanvas(theW + 4, theH + 4, AnchorPosition.MIDDLECENTER);
// load red channel;
myDocument.selection.load(myDocument.channels[0], SelectionType.REPLACE, true);
// create layer;
var blackLayer = solidColorLayer (0,0,0);
// check upper left pixel is white;
myDocument.activeLayer = theLayer;
var theX = 1;
var theY = 1;
magicWand(theX, theY);
// expand and invert selection;
myDocument.selection.expand(1);
myDocument.selection.invert();
// create layer;
var whiteLayer = solidColorLayer (255,255,255);
// remove original layer and merge;
theLayer.remove();
if (myDocument.layers.length > 1) {myDocument.mergeVisibleLayers()};
// reset;
myDocument.resizeCanvas(theW, theH, AnchorPosition.MIDDLECENTER);
app.preferences.rulerUnits = originalUnits;
} else {alert ("image seems to contain color")}
};
//////////////////////////////////////////
////// function to create a solid color layer //////
function solidColorLayer (theRed, theGreen, theBlue) {
// =======================================================
var idMk = charIDToTypeID( "Mk  " );
    var desc3 = new ActionDescriptor();
    var idnull = charIDToTypeID( "null" );
        var ref1 = new ActionReference();
        var idcontentLayer = stringIDToTypeID( "contentLayer" );
        ref1.putClass( idcontentLayer );
    desc3.putReference( idnull, ref1 );
    var idUsng = charIDToTypeID( "Usng" );
        var desc4 = new ActionDescriptor();
        var idType = charIDToTypeID( "Type" );
            var desc5 = new ActionDescriptor();
            var idClr = charIDToTypeID( "Clr " );
                var desc6 = new ActionDescriptor();
                var idRd = charIDToTypeID( "Rd  " );
                desc6.putDouble( idRd, theRed );
                var idGrn = charIDToTypeID( "Grn " );
                desc6.putDouble( idGrn,theGreen );
                var idBl = charIDToTypeID( "Bl  " );
                desc6.putDouble( idBl, theBlue );
            var idRGBC = charIDToTypeID( "RGBC" );
            desc5.putObject( idClr, idRGBC, desc6 );
        var idsolidColorLayer = stringIDToTypeID( "solidColorLayer" );
        desc4.putObject( idType, idsolidColorLayer, desc5 );
    var idcontentLayer = stringIDToTypeID( "contentLayer" );
    desc3.putObject( idUsng, idcontentLayer, desc4 );
executeAction( idMk, desc3, DialogModes.NO );
return app.activeDocument.activeLayer
};
////// magic wand //////
function magicWand (theX, theY) {
//use magic wand
    var idsetd = charIDToTypeID( "setd" );
        var desc263 = new ActionDescriptor();
        var idnull = charIDToTypeID( "null" );
            var ref123 = new ActionReference();
            var idChnl = charIDToTypeID( "Chnl" );
            var idfsel = charIDToTypeID( "fsel" );
            ref123.putProperty( idChnl, idfsel );
        desc263.putReference( idnull, ref123 );
        var idT = charIDToTypeID( "T   " );
            var desc264 = new ActionDescriptor();
            var idHrzn = charIDToTypeID( "Hrzn" );
            var idRlt = charIDToTypeID( "#Rlt" );
            desc264.putUnitDouble( idHrzn, idRlt, theX);
            var idVrtc = charIDToTypeID( "Vrtc" );
            var idRlt = charIDToTypeID( "#Rlt" );
            desc264.putUnitDouble( idVrtc, idRlt, theY);
        var idPnt = charIDToTypeID( "Pnt " );
        desc263.putObject( idT, idPnt, desc264 );
        var idTlrn = charIDToTypeID( "Tlrn" );
        desc263.putInteger( idTlrn, 1 );
    executeAction( idsetd, desc263, DialogModes.NO );
};
////// get color //////
function getColor (theX, theY) {
// select color sampler tool;
// =======================================================
var idslct = charIDToTypeID( "slct" );
    var desc3 = new ActionDescriptor();
    var idnull = charIDToTypeID( "null" );
        var ref2 = new ActionReference();
        var idcolorSamplerTool = stringIDToTypeID( "colorSamplerTool" );
        ref2.putClass( idcolorSamplerTool );
    desc3.putReference( idnull, ref2 );
    var iddontRecord = stringIDToTypeID( "dontRecord" );
    desc3.putBoolean( iddontRecord, true );
    var idforceNotify = stringIDToTypeID( "forceNotify" );
    desc3.putBoolean( idforceNotify, true );
executeAction( idslct, desc3, DialogModes.NO );
// set sampler;
// =======================================================
var idMk = charIDToTypeID( "Mk  " );
    var desc4 = new ActionDescriptor();
    var idnull = charIDToTypeID( "null" );
        var ref3 = new ActionReference();
        var idClSm = charIDToTypeID( "ClSm" );
        ref3.putClass( idClSm );
    desc4.putReference( idnull, ref3 );
    var idPstn = charIDToTypeID( "Pstn" );
        var desc5 = new ActionDescriptor();
        var idHrzn = charIDToTypeID( "Hrzn" );
        var idPxl = charIDToTypeID( "#Pxl" );
        desc5.putUnitDouble( idHrzn, idPxl, theX );
        var idVrtc = charIDToTypeID( "Vrtc" );
        var idPxl = charIDToTypeID( "#Pxl" );
        desc5.putUnitDouble( idVrtc, idPxl, theY );
    var idPnt = charIDToTypeID( "Pnt " );
    desc4.putObject( idPstn, idPnt, desc5 );
executeAction( idMk, desc4, DialogModes.NO );
// forground color;
var theSampler = activeDocument.colorSamplers[activeDocument.colorSamplers.length - 1];
var theColor = theSampler.color;
theSampler.remove();
app.preferences.rulerUnits = originalUnits;
return [theColor.rgb.red, theColor.rgb.green, theColor.rgb.blue];
};
////// reset fore- and background color //////
function resetForeAndBackgroud () {
// =======================================================
var idRset = charIDToTypeID( "Rset" );
    var desc2 = new ActionDescriptor();
    var idnull = charIDToTypeID( "null" );
        var ref1 = new ActionReference();
        var idClr = charIDToTypeID( "Clr " );
        var idClrs = charIDToTypeID( "Clrs" );
        ref1.putProperty( idClr, idClrs );
    desc2.putReference( idnull, ref1 );
executeAction( idRset, desc2, DialogModes.NO );
};
////// is black and white //////
function isBlackAndWhite () {
// =======================================================
var idDplc = charIDToTypeID( "Dplc" );
    var desc5 = new ActionDescriptor();
    var idnull = charIDToTypeID( "null" );
        var ref4 = new ActionReference();
        var idDcmn = charIDToTypeID( "Dcmn" );
        var idOrdn = charIDToTypeID( "Ordn" );
        var idFrst = charIDToTypeID( "Frst" );
        ref4.putEnumerated( idDcmn, idOrdn, idFrst );
    desc5.putReference( idnull, ref4 );
    var idMrgd = charIDToTypeID( "Mrgd" );
    desc5.putBoolean( idMrgd, true );
executeAction( idDplc, desc5, DialogModes.NO );
// =======================================================
var idCnvM = charIDToTypeID( "CnvM" );
    var desc6 = new ActionDescriptor();
    var idT = charIDToTypeID( "T   " );
    var idLbCM = charIDToTypeID( "LbCM" );
    desc6.putClass( idT, idLbCM );
executeAction( idCnvM, desc6, DialogModes.NO );
// the temp file;
var theFile = app.activeDocument;
// the histograms of a and b channels;
var histo1 = theFile.channels[1].histogram;
var histo2 = theFile.channels[1].histogram;
// the total pixels;
var theNumber = theFile.width * theFile.height;
// close temp file;
theFile.close(SaveOptions.DONOTSAVECHANGES);
// check;
if (histo1[127]+histo1[128]+histo1[129] == theNumber && histo2[127]+histo2[128]+histo2[129] == theNumber) {return true}
else {return false}
};

Edit: The work-around of flattening the file and recreating the lines from the red channel is not elegant and may take more time than other possible approaches but you are free to change the Script anyway.
Edit: I have amended the Script to check whether the image is indeed black and white.
jmarkt

Converting B&W Clipart With A Script

Post by jmarkt »

Curiously enough, the script was returning "Image seems to contain color". When I clicked OK, nothing happened. I removed a couple of lines referring to the color, and it worked flawlessly on both images! I will work on my learning curve to learn how to add something to the beginning of the script that will allow me to use/apply it with some 400 sub-folders that contain the clipart.

I REALLY appreciate your doing this, pfaffenbichler.
pfaffenbichler

Converting B&W Clipart With A Script

Post by pfaffenbichler »

WIth the image I tested (the jeep) it seems to work here.

I included the check to make sure simply using one of the inverted Composite Channels for the lines is OK.
You probably saw that the function only checks the middle three values of the a- and b-channels of an Lab copy of the image – if they don’t encompass the whole of the image there must be some color (at least some very faint one).

You could insert the Script in an Action and use File > Automate > Batch or File > Scripts > Image Processor.