Comparing layers for equality [2011]
Copy link to clipboard
Copied
Is it possible to compare two different layers to see if they are in fact the same image?
I'm actually working on a game at the moment. The game map was created by using game sprites created by other people. For example, I found 5 different pictures of trees, and copy pasted them into photoshop multiple times to create a forest. I have 100 trees in my photoshop document, but in reality, they are all made up of only 5 images. I want to save out each of these trees into a format usable by my game engine. I want to save each layer as an image, but avoid saving duplicates. Thus the need to compare layers for equality.
Is it possible to do this within a photoshop script? Thanks for any help you can provide.
Explore related tutorials & articles
Copy link to clipboard
Copied
@c.pfaffenbichler Kindly ignore the additional request, i was able to work on that part.
Thank you again for the help on entire feature request. Saved lot of scripting efforts for R&D.
Copy link to clipboard
Copied
@c.pfaffenbichler Is it possible to color the difference pixels instead of adding stroke ?
Copy link to clipboard
Copied
It is possible but I probably won’t have time to look into that this week.
Copy link to clipboard
Copied
// tries to create a file comparing all pages of two cmyk-pdfs;
// 2025, use it at your own risk;
/* dialog for pdf-selection */
if (ScriptUI.environment.keyboardState.shiftKey == true) {var theRes = 300}
else {var theRes = 150};
var theFile1 = File.openDialog("please select the first pdf", checkForPDF, false);
var theFile2 = File.openDialog("please select the second pdf", checkForPDF, false);
if (theFile1 && theFile2) {
/* the open options */
var pdfOpenOpts = new PDFOpenOptions;
pdfOpenOpts.antiAlias = true;
pdfOpenOpts.bitsPerChannel = BitsPerChannelType.EIGHT;
pdfOpenOpts.cropPage = CropToType.TRIMBOX;
pdfOpenOpts.mode = OpenDocumentMode.CMYK;
pdfOpenOpts.resolution = theRes;
pdfOpenOpts.suppressWarnings = true;
pdfOpenOpts.usePageNumber = true;
var thePdf = compareMultipagePDF(theFile1, theFile2, pdfOpenOpts);
revealAll ();
};
/* function to compare all pages of two pdfs */
function compareMultipagePDF(myPDFFile1, myPDFFile2) {
var secondShorter = false;
/* suppress dialogs */
var theDialogSettings = app.displayDialogs;
app.displayDialogs = DialogModes.NO;
var myCounter = 1;
var myBreak = false;
while(myBreak == false){
pdfOpenOpts.page = myCounter;
try {
var thePdf = app.open(myPDFFile1, pdfOpenOpts);
thePdf.flatten();
thePdf.layers[0].isBackgroundLayer = false;
thePdf.layers[0].name = myPDFFile1.name+"_"+myCounter;
if (myCounter == 1) {
var theFile = thePdf
}
else {
thePdf.layers[0].duplicate(theFile, ElementPlacement.PLACEATBEGINNING);
thePdf.close(SaveOptions.DONOTSAVECHANGES)
};
try {
var theSecondPdf = app.open(myPDFFile2, pdfOpenOpts);
theSecondPdf.flatten();
theSecondPdf.layers[0].isBackgroundLayer = false;
theSecondPdf.layers[0].name = myPDFFile2.name+"_"+myCounter;
theSecondPdf.layers[0].duplicate(theFile, ElementPlacement.PLACEATBEGINNING);
theSecondPdf.close(SaveOptions.DONOTSAVECHANGES);
var theSecond = activeDocument.activeLayer;
theSecond.blendMode = BlendMode.DIFFERENCE;
var id556 = charIDToTypeID( "GrpL" );
executeAction( id556, undefined, DialogModes.NO );
// mark differences;
mergVisibleToNewLayer();
var theBlendIfThisArray = [ [9,9,255,255], [0,0,255,255], [0,0,255,255], [0,0,255,255] ];
var theBlendIfUnderlyingArray = [ [0,0,255,255], [0,0,255,255], [0,0,255,255], [0,0,255,255] ];
blendIfThisAndUnderlying (theBlendIfThisArray, theBlendIfUnderlyingArray);
activeDocument.activeLayer.applyMaximum(10);
cmykChannelMixer();
groupSelectedLayers (myCounter);
activeDocument.activeLayer.merge();
var theGroup = activeDocument.activeLayer;
//applyLayerStyleStroke(5, 255, 0, 0);
applyColorOverlay (255, 0, 0);
theGroup.fillOpacity = 0;
theSecond.blendMode = BlendMode.NORMAL;
}
catch (e) {secondShorter = true}
}
catch (e) {
try {
var theSecondPdf = app.open(myPDFFile2, pdfOpenOpts);
theSecondPdf.close(SaveOptions.DONOTSAVECHANGES);
alert (theFile2.name+" seems to have more pages than "+theFile1.name)
}
catch (e) {}
myBreak = true
};
myCounter = myCounter + 1;
};
if (secondShorter == true) {alert (theFile1.name+" seems to have more pages than "+theFile2.name)};
/* reset dialogmodes */
app.displayDialogs = DialogModes.ERROR;
};
/* open pdf page */
function openPDFPage (myPDFFile, pdfOpenOpts, myCounter) {
var thePdf = app.open(myPDFFile, pdfOpenOpts);
thePdf.flatten();
thePdf.layers[0].isBackgroundLayer = false;
thePdf.layers[0].name = myPDFFile.name+"_"+myCounter;
return thePdf
};
/* filter-function for pdf-files */
function checkForPDF (theFile) {
if (theFile.name.slice(-4) == ".pdf" || theFile.constructor.name == "Folder") {return true}
else {return false}
};
////// reveal all //////
function revealAll () {
var idRvlA = charIDToTypeID( "RvlA" );
executeAction( idRvlA, undefined, DialogModes.NO );
};
////// layer via copy //////
function mergVisibleToNewLayer (){
var desc23 = new ActionDescriptor();
desc23.putBoolean( stringIDToTypeID( "duplicate" ), true );
executeAction( stringIDToTypeID( "mergeVisible" ), desc23, DialogModes.NO );
};
////// group //////
function groupSelectedLayers (theName) {
var desc159 = new ActionDescriptor();
var ref114 = new ActionReference();
var idlayer = stringIDToTypeID( "layer" );
var idordinal = stringIDToTypeID( "ordinal" );
var idtargetEnum = stringIDToTypeID( "targetEnum" );
var idnull = stringIDToTypeID( "null" );
var idname = stringIDToTypeID( "name" );
ref114.putEnumerated(idlayer, idordinal, idtargetEnum);
desc159.putReference(idnull, ref114 );
desc159.putString(idname, "aaa" );
executeAction( stringIDToTypeID( "groupLayersEvent" ), desc159, DialogModes.NO );
var desc63 = new ActionDescriptor();
var ref37 = new ActionReference();
ref37.putEnumerated( idlayer, idordinal, idtargetEnum );
desc63.putReference( idnull, ref37 );
var desc64 = new ActionDescriptor();
desc64.putString(idname, theName);
desc63.putObject(stringIDToTypeID( "to" ), idlayer, desc64);
executeAction(stringIDToTypeID( "set" ), desc63, DialogModes.NO)
};
////// make stroke //////
function applyLayerStyleStroke (theWitdh, theR, theG, theB) {
// =======================================================
var idsetd = charIDToTypeID( "setd" );
var desc12 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref7 = new ActionReference();
var idPrpr = charIDToTypeID( "Prpr" );
var idLefx = charIDToTypeID( "Lefx" );
ref7.putProperty( idPrpr, idLefx );
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref7.putEnumerated( idLyr, idOrdn, idTrgt );
desc12.putReference( idnull, ref7 );
var idT = charIDToTypeID( "T " );
var desc13 = new ActionDescriptor();
var idScl = charIDToTypeID( "Scl " );
var idPrc = charIDToTypeID( "#Prc" );
desc13.putUnitDouble( idScl, idPrc, 100.000000 );
var idFrFX = charIDToTypeID( "FrFX" );
var desc14 = new ActionDescriptor();
var idenab = charIDToTypeID( "enab" );
desc14.putBoolean( idenab, true );
var idStyl = charIDToTypeID( "Styl" );
var idFStl = charIDToTypeID( "FStl" );
desc14.putEnumerated( idStyl, idFStl, charIDToTypeID( "OutF" ) );
var idPntT = charIDToTypeID( "PntT" );
var idFrFl = charIDToTypeID( "FrFl" );
var idSClr = charIDToTypeID( "SClr" );
desc14.putEnumerated( idPntT, idFrFl, idSClr );
var idMd = charIDToTypeID( "Md " );
var idBlnM = charIDToTypeID( "BlnM" );
var idNrml = charIDToTypeID( "Nrml" );
desc14.putEnumerated( idMd, idBlnM, idNrml );
var idOpct = charIDToTypeID( "Opct" );
var idPrc = charIDToTypeID( "#Prc" );
desc14.putUnitDouble( idOpct, idPrc, 100.000000 );
var idSz = charIDToTypeID( "Sz " );
var idPxl = charIDToTypeID( "#Pxl" );
desc14.putUnitDouble( idSz, idPxl, theWitdh );
var idClr = charIDToTypeID( "Clr " );
var desc15 = new ActionDescriptor();
var idRd = charIDToTypeID( "Rd " );
desc15.putDouble( idRd, theR );
var idGrn = charIDToTypeID( "Grn " );
desc15.putDouble( idGrn, theG );
var idBl = charIDToTypeID( "Bl " );
desc15.putDouble( idBl, theB );
var idRGBC = charIDToTypeID( "RGBC" );
desc14.putObject( idClr, idRGBC, desc15 );
var idFrFX = charIDToTypeID( "FrFX" );
desc13.putObject( idFrFX, idFrFX, desc14 );
var idLefx = charIDToTypeID( "Lefx" );
desc12.putObject( idT, idLefx, desc13 );
executeAction( idsetd, desc12, DialogModes.NO );
};
////// set blend if settings for this and underlying //////
function blendIfThisAndUnderlying (thisNumbers, underlyingNumbers) {
// =======================================================
var idsetd = charIDToTypeID( "setd" );
var desc11 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref8 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref8.putEnumerated( idLyr, idOrdn, idTrgt );
desc11.putReference( idnull, ref8 );
var idT = charIDToTypeID( "T " );
var desc12 = new ActionDescriptor();
var idBlnd = charIDToTypeID( "Blnd" );
var list3 = new ActionList();
var desc13 = new ActionDescriptor();
var idChnl = charIDToTypeID( "Chnl" );
var ref9 = new ActionReference();
var idChnl = charIDToTypeID( "Chnl" );
var idChnl = charIDToTypeID( "Chnl" );
var idGry = charIDToTypeID( "Gry " );
ref9.putEnumerated( idChnl, idChnl, idGry );
desc13.putReference( idChnl, ref9 );
var idSrcB = charIDToTypeID( "SrcB" );
desc13.putInteger( idSrcB, thisNumbers[0][0] );
var idSrcl = charIDToTypeID( "Srcl" );
desc13.putInteger( idSrcl, thisNumbers[0][1] );
var idSrcW = charIDToTypeID( "SrcW" );
desc13.putInteger( idSrcW, thisNumbers[0][2] );
var idSrcm = charIDToTypeID( "Srcm" );
desc13.putInteger( idSrcm, thisNumbers[0][3] );
var idDstB = charIDToTypeID( "DstB" );
desc13.putInteger( idDstB, underlyingNumbers[0][0] );
var idDstl = charIDToTypeID( "Dstl" );
desc13.putInteger( idDstl, underlyingNumbers[0][1] );
var idDstW = charIDToTypeID( "DstW" );
desc13.putInteger( idDstW, underlyingNumbers[0][2] );
var idDstt = charIDToTypeID( "Dstt" );
desc13.putInteger( idDstt, underlyingNumbers[0][3] );
var idBlnd = charIDToTypeID( "Blnd" );
list3.putObject( idBlnd, desc13 );
/*var desc14 = new ActionDescriptor();
var idChnl = charIDToTypeID( "Chnl" );
var ref10 = new ActionReference();
var idChnl = charIDToTypeID( "Chnl" );
var idChnl = charIDToTypeID( "Chnl" );
var idRd = charIDToTypeID( "Rd " );
ref10.putEnumerated( idChnl, idChnl, idRd );
desc14.putReference( idChnl, ref10 );
var idSrcB = charIDToTypeID( "SrcB" );
desc14.putInteger( idSrcB, thisNumbers[1][0] );
var idSrcl = charIDToTypeID( "Srcl" );
desc14.putInteger( idSrcl, thisNumbers[1][1] );
var idSrcW = charIDToTypeID( "SrcW" );
desc14.putInteger( idSrcW, thisNumbers[1][2] );
var idSrcm = charIDToTypeID( "Srcm" );
desc14.putInteger( idSrcm, thisNumbers[1][3] );
var idDstB = charIDToTypeID( "DstB" );
desc14.putInteger( idDstB, underlyingNumbers[1][0] );
var idDstl = charIDToTypeID( "Dstl" );
desc14.putInteger( idDstl, underlyingNumbers[1][1] );
var idDstW = charIDToTypeID( "DstW" );
desc14.putInteger( idDstW, underlyingNumbers[1][2] );
var idDstt = charIDToTypeID( "Dstt" );
desc14.putInteger( idDstt, underlyingNumbers[1][3] );
var idBlnd = charIDToTypeID( "Blnd" );
list3.putObject( idBlnd, desc14 );
var desc15 = new ActionDescriptor();
var idChnl = charIDToTypeID( "Chnl" );
var ref11 = new ActionReference();
var idChnl = charIDToTypeID( "Chnl" );
var idChnl = charIDToTypeID( "Chnl" );
var idGrn = charIDToTypeID( "Grn " );
ref11.putEnumerated( idChnl, idChnl, idGrn );
desc15.putReference( idChnl, ref11 );
var idSrcB = charIDToTypeID( "SrcB" );
desc15.putInteger( idSrcB, thisNumbers[2][0] );
var idSrcl = charIDToTypeID( "Srcl" );
desc15.putInteger( idSrcl, thisNumbers[2][1] );
var idSrcW = charIDToTypeID( "SrcW" );
desc15.putInteger( idSrcW, thisNumbers[2][2] );
var idSrcm = charIDToTypeID( "Srcm" );
desc15.putInteger( idSrcm, thisNumbers[2][3] );
var idDstB = charIDToTypeID( "DstB" );
desc15.putInteger( idDstB, underlyingNumbers[2][0] );
var idDstl = charIDToTypeID( "Dstl" );
desc15.putInteger( idDstl, underlyingNumbers[2][1] );
var idDstW = charIDToTypeID( "DstW" );
desc15.putInteger( idDstW, underlyingNumbers[2][2] );
var idDstt = charIDToTypeID( "Dstt" );
desc15.putInteger( idDstt, underlyingNumbers[2][3] );
var idBlnd = charIDToTypeID( "Blnd" );
list3.putObject( idBlnd, desc15 );
var desc16 = new ActionDescriptor();
var idChnl = charIDToTypeID( "Chnl" );
var ref12 = new ActionReference();
var idChnl = charIDToTypeID( "Chnl" );
var idChnl = charIDToTypeID( "Chnl" );
var idBl = charIDToTypeID( "Bl " );
ref12.putEnumerated( idChnl, idChnl, idBl );
desc16.putReference( idChnl, ref12 );
var idSrcB = charIDToTypeID( "SrcB" );
desc16.putInteger( idSrcB, thisNumbers[3][0] );
var idSrcl = charIDToTypeID( "Srcl" );
desc16.putInteger( idSrcl, thisNumbers[3][1] );
var idSrcW = charIDToTypeID( "SrcW" );
desc16.putInteger( idSrcW, thisNumbers[3][2] );
var idSrcm = charIDToTypeID( "Srcm" );
desc16.putInteger( idSrcm, thisNumbers[3][3] );
var idDstB = charIDToTypeID( "DstB" );
desc16.putInteger( idDstB, underlyingNumbers[3][0] );
var idDstl = charIDToTypeID( "Dstl" );
desc16.putInteger( idDstl, underlyingNumbers[3][1] );
var idDstW = charIDToTypeID( "DstW" );
desc16.putInteger( idDstW, underlyingNumbers[3][2] );
var idDstt = charIDToTypeID( "Dstt" );
desc16.putInteger( idDstt, underlyingNumbers[3][3] );
var idBlnd = charIDToTypeID( "Blnd" );
list3.putObject( idBlnd, desc16 );*/
desc12.putList( idBlnd, list3 );
var idLefx = charIDToTypeID( "Lefx" );
var desc17 = new ActionDescriptor();
var idScl = charIDToTypeID( "Scl " );
var idPrc = charIDToTypeID( "#Prc" );
desc17.putUnitDouble( idScl, idPrc, 423.333316 );
var idLefx = charIDToTypeID( "Lefx" );
desc12.putObject( idLefx, idLefx, desc17 );
var idLyr = charIDToTypeID( "Lyr " );
desc11.putObject( idT, idLyr, desc12 );
executeAction( idsetd, desc11, DialogModes.NO );
};
////// channel mixer //////
function cmykChannelMixer () {
var idpercentUnit = stringIDToTypeID( "percentUnit" );
var idchannelMixer = stringIDToTypeID( "channelMixer" );
var desc5 = new ActionDescriptor();
var idpresetKind = stringIDToTypeID( "presetKind" );
var idpresetKindType = stringIDToTypeID( "presetKindType" );
var idpresetKindCustom = stringIDToTypeID( "presetKindCustom" );
desc5.putEnumerated( idpresetKind, idpresetKindType, idpresetKindCustom );
var idmonochromatic = stringIDToTypeID( "monochromatic" );
desc5.putBoolean( idmonochromatic, true );
var idgray = stringIDToTypeID( "gray" );
var desc6 = new ActionDescriptor();
var idcyan = stringIDToTypeID( "cyan" );
desc6.putUnitDouble( idcyan, idpercentUnit, 25.000000 );
var idmagenta = stringIDToTypeID( "magenta" );
desc6.putUnitDouble( idmagenta, idpercentUnit, 25.000000 );
var idyellowColor = stringIDToTypeID( "yellowColor" );
desc6.putUnitDouble( idyellowColor, idpercentUnit, 25.000000 );
var idblack = stringIDToTypeID( "black" );
desc6.putUnitDouble( idblack, idpercentUnit, 25.000000 );
var idchannelMatrix = stringIDToTypeID( "channelMatrix" );
desc5.putObject( idgray, idchannelMatrix, desc6 );
executeAction( idchannelMixer, desc5, DialogModes.NO );
};
////// color overlay //////
function applyColorOverlay (theR, theG, theB) {
//selectLayerByID(myLayer, false);
// =======================================================
var desc5 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putProperty( stringIDToTypeID( "property" ), stringIDToTypeID( "layerEffects" ) );
var idlayer = stringIDToTypeID( "layer" );
var idordinal = stringIDToTypeID( "ordinal" );
var idtargetEnum = stringIDToTypeID( "targetEnum" );
ref1.putEnumerated( idlayer, idordinal, idtargetEnum );
// ref1.putIdentifier( idlayer, myLayer );
desc5.putReference( stringIDToTypeID( "null" ), ref1 );
var desc6 = new ActionDescriptor();
var idscale = stringIDToTypeID( "scale" );
var idpercentUnit = stringIDToTypeID( "percentUnit" );
desc6.putUnitDouble( idscale, idpercentUnit, 416.666667 );
var desc7 = new ActionDescriptor();
var idenabled = stringIDToTypeID( "enabled" );
desc7.putBoolean( idenabled, true );
var idpresent = stringIDToTypeID( "present" );
desc7.putBoolean( idpresent, true );
var idshowInDialog = stringIDToTypeID( "showInDialog" );
desc7.putBoolean( idshowInDialog, true );
desc7.putEnumerated( stringIDToTypeID( "mode" ), stringIDToTypeID( "blendMode" ), stringIDToTypeID( "normal" ) );
var idcolor = stringIDToTypeID( "color" );
var desc8 = new ActionDescriptor();
var idred = stringIDToTypeID( "red" );
desc8.putDouble( idred, theR );
var idgrain = stringIDToTypeID( "grain" );
desc8.putDouble( idgrain, theG );
var idblue = stringIDToTypeID( "blue" );
desc8.putDouble( idblue, theB );
desc7.putObject( idcolor, stringIDToTypeID( "RGBColor" ), desc8 );
var idpercentUnit = stringIDToTypeID( "percentUnit" );
desc7.putUnitDouble( stringIDToTypeID( "opacity" ), idpercentUnit, 100.000000 );
desc6.putObject( stringIDToTypeID( "solidFill" ), stringIDToTypeID( "solidFill" ), desc7 );
desc5.putObject( stringIDToTypeID( "to" ), stringIDToTypeID( "layerEffects" ), desc6 );
executeAction( stringIDToTypeID( "set" ), desc5, DialogModes.NO );
};
Copy link to clipboard
Copied
Thanks, I am attaching a sample output . is it possible to get that output in Photoshop to identify difference ?


-
- 1
- 2