Link in Zwischenablage kopieren
Kopiert
Hi all!
I'm currently working on a C++ and PHP library for obtaining information about PSD files; meaning that the library extracts information about every layer in the PSD. The library is not designed for decoding and/or displaying the image data in a PSD file, it is merely for extracting information about layers, their visibility and groups.
Now I realise that this might not be the place to ask this question, however I'm looking for people who can help me explain a bit about the file format. I'm using the documentation by Adobe as reference, which can be found here: Adobe Photoshop File Formats Specification
I'm trying to determine where a layer group starts and ends. I've noticed upon processing the file with my library at some point I come across a layer named '</Layer group>', which probably denotes the end of a layer group, however I can't figure out where the group begins.
I'm also wondering how I can detect a smart object, considering it's another way of grouping layers; however, in the file format each component of the smart object (including the smart object itself) are listed as layers. They are all (including the group entities) layer records, which are described here: Adobe Photoshop File Formats Specification (refers to the section of the document about layer records).
Can anyone point me in the right direction?
Cheers,
Bas Groothedde
With layersets you have to keep a count of layerset starts incrementing the count for each found and decrement the count on a layerset end. This will then show nested layersets.
An example script can be found here...
https://raw.githubusercontent.com/Paul-Riggott/PS-Scripts/master/getLayersetLayerIDs.jsx
Yes Indexs are in order from the background layer to the top, these indexs might/will change if a layer is deleted or moved, that is why the layers ID is used most of the time as its unique. Olso
...Link in Zwischenablage kopieren
Kopiert
There could be bit of confusion with the terminolgy here, grouped layers are not layersets or smart objects.
here is a function that will return if the layer index is a Layerset start/finish or is just a normal layer.
// returns one of:
// 'layerSectionStart' Start of a layer set
// 'layerSectionEnd' End of a layer set
// 'layerSectionConent' A content layer
function getLayerLayerSectionByIndex( index ) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID('Prpr') , stringIDToTypeID('layerSection'));
ref.putIndex(charIDToTypeID('Lyr '), index);
try{
return typeIDToStringID(executeActionGet(ref).getEnumerationValue(stringIDToTypeID('layerSection')));
}catch(e){$.writeln("error in index " + index); return;}
};
Here is another script you can run against a psd from ExtendScript Toolkit.
This will walk the PSD giving basic info including if Smart Object.
#target photoshop
if(documents.length) LayerInfo();
function LayerInfo(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
var count = executeActionGet(ref).getInteger(charIDToTypeID('NmbL')) +1;
var Layerinfo=[];
try{
activeDocument.backgroundLayer;
var i = 0; }catch(e){ var i = 1; };
for(i;i<count;i++){
ref = new ActionReference();
ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
var desc = executeActionGet(ref);
var layerName = desc.getString(charIDToTypeID( 'Nm ' ));
var Id = desc.getInteger(stringIDToTypeID( 'layerID' ));
var group = desc.getBoolean(stringIDToTypeID('group'));
var kind = getLayerKindByIndex( i);
if(layerName.match(/^<\/Layer group/) ) layerName = "End_Layerset";
var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));
var isLayerSet =( layerType == 'layerSectionContent') ? false:true;
if(isLayerSet) layerName = ">--->" + layerName;
Layerinfo.push([[layerName],[isLayerSet],[kind],,[Id],[group]]);
};
Layerinfo.reverse();
for(var z in Layerinfo){
$.writeln(Layerinfo
.toString()); }
};
function getLayerKindByIndex( index ) {
var ref, desc, adjustmentDesc, layerSectionType;
ref = new ActionReference();
ref.putIndex(charIDToTypeID( "Lyr " ), index );
desc = executeActionGet(ref);
if( desc.hasKey( stringIDToTypeID( 'textKey' ) ) ) return LayerKind.TEXT;
if( desc.hasKey( stringIDToTypeID( 'smartObject' ) ) ) return LayerKind.SMARTOBJECT;// includes LayerKind.VIDEO
if( desc.hasKey( stringIDToTypeID( 'layer3D' ) ) ) return LayerKind.LAYER3D;
var vMask = desc.getBoolean(stringIDToTypeID('hasVectorMask' ));
if( desc.hasKey( stringIDToTypeID( 'adjustment' ) ) && vMask === true) return "LayerKind.SHAPE";
if( desc.hasKey( stringIDToTypeID( 'adjustment' ) ) ){
switch(typeIDToStringID(desc.getList (stringIDToTypeID('adjustment')).getClass (0))){
case 'photoFilter' : return LayerKind.PHOTOFILTER;
case 'solidColorLayer' : return LayerKind.SOLIDFILL;
case 'gradientMapClass' : return LayerKind.GRADIENTMAP;
case 'gradientMapLayer' : return LayerKind.GRADIENTFILL;
case 'hueSaturation' : return LayerKind.HUESATURATION;
case 'colorLookup' : return undefined; //this does not exist and errors with getting layer kind
case 'colorBalance' : return LayerKind.COLORBALANCE;
case 'patternLayer' : return LayerKind.PATTERNFILL;
case 'invert' : return LayerKind.INVERSION;
case 'posterization' : return LayerKind.POSTERIZE;
case 'thresholdClassEvent' : return LayerKind.THRESHOLD;
case 'blackAndWhite' : return LayerKind.BLACKANDWHITE;
case 'selectiveColor' : return LayerKind.SELECTIVECOLOR;
case 'vibrance' : return LayerKind.VIBRANCE;
case 'brightnessEvent' : return LayerKind.BRIGHTNESSCONTRAST;
case 'channelMixer' : return LayerKind.CHANNELMIXER;
case 'curves' : return LayerKind.CURVES;
case 'exposure' : return LayerKind.EXPOSURE;
// if not one of the above adjustments return - adjustment layer type
default : return typeIDToStringID(desc.getList (stringIDToTypeID('adjustment')).getClass (0));
}
}
var layerType = typeIDToStringID(desc.getEnumerationValue( stringIDToTypeID( 'layerSection' )));
return ( layerType == 'layerSectionContent') ? LayerKind.NORMAL:undefined;
}
Hope it gives a bit of insight.
P.S. I don't have CC so things may be slightly different now.
Link in Zwischenablage kopieren
Kopiert
Thanks for your reply SuperMerlin,
The code you provided gives me insight in the information that should be available in the format, but I must add that I can't rely on a functionset or SDK for this problem. Due to the fact the library has to operate on many systems and should be ported to multiple languages, the processing of the PSD file is done from the library itself.
This means that the helper function you provide can't be implemented in my library, and I must rely on the information Adobe has put in each layer record. I have discovered the 'lsct' (Section divider setting) field in the Additional Layer Information section in the PSD format that defines information about a ‘folder’. It states the type (0 = any other type of layer, 1 = open "folder", 2 = closed "folder", 3 = bounding section divider, hidden in the UI), a blend mode if available and a possible subtype (0 = normal, 1 = scene group, affects the animation timeline.)
I’ve noticed that the layer with the name </Layer group> has the type ‘bounding section divider, hidden in the UI’, meaning I can determine the end of a group like that; however I don’t know which group it is ending.
I also found that the layersets are listed as layers, with the ‘lsct’ section as well. This time, they list a type 1 or 2 (open or closed “folder” according the docs, forgive the terminology), a blend mode (pass) and a subtype of 0 (normal)
Do you think these layers are in order, so that I can process these as start and end layers for a group?
Once again, forgive the terminology, I’m using the terminology from the format specification.
Thank you,
Bas
Link in Zwischenablage kopieren
Kopiert
You are not only one who tried to solve this problem. Look for already made solution first 😉
Link in Zwischenablage kopieren
Kopiert
To assume I did not first look for an already made solution is rather unproductive, I did in fact research implementations of the spec. I couldn't find one where the flags for a layer and grouping was implemented, where also all the information belonging in a layer record was exported.
If you know that I'm not the only one who tried to solve this problem, you appear to know of existing solutions; can you point me to one?
Link in Zwischenablage kopieren
Kopiert
With layersets you have to keep a count of layerset starts incrementing the count for each found and decrement the count on a layerset end. This will then show nested layersets.
An example script can be found here...
https://raw.githubusercontent.com/Paul-Riggott/PS-Scripts/master/getLayersetLayerIDs.jsx
Yes Indexs are in order from the background layer to the top, these indexs might/will change if a layer is deleted or moved, that is why the layers ID is used most of the time as its unique. Olso it depends if the PSD has a background layer to where the Index starts.
Confusing? sure is!
Link in Zwischenablage kopieren
Kopiert
Actually, that's all I need to know. Thank you for your time and being so kind, have a great day!
Link in Zwischenablage kopieren
Kopiert
Neo Hexeditor has structure view for PSD files: https://www.hhdsoftware.com/images/screenshots/hex-full-pacific-coloring-scheme-floating-layout.png
You should be able to see layersets. Template PSD for structure view should be written in C++
Link in Zwischenablage kopieren
Kopiert
I'm Sorry Jarda, but that's far from helpful; I already processed the filestructure completely. The only thing I needed to know, as that wasn't mentioned in the PSD file spec, is how to interpret the layers as layersets. SuperMerlin was very helpful in this regard.
The issue is solved.
Weitere Inspirationen, Events und Ressourcen finden Sie in der neuen Adobe Community
Jetzt ansehen