Beenden
  • Globale Community
    • Sprache:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티

The PSD format and layer groups

Community-Einsteiger ,
Oct 17, 2017 Oct 17, 2017

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

THEMEN
Aktionen und Skripte
2.1K
Übersetzen
Melden
Community-Richtlinien
Seien Sie freundlich und respektvoll, geben Sie die ursprüngliche Quelle der Inhalte an und suchen Sie vor dem Absenden Ihres Beitrags nach Duplikaten. Weitere Informationen
community guidelines

correct answers 1 richtige Antwort

Ratgeber , Oct 17, 2017 Oct 17, 2017

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

...
Übersetzen
Adobe
Ratgeber ,
Oct 17, 2017 Oct 17, 2017

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.

Übersetzen
Melden
Community-Richtlinien
Seien Sie freundlich und respektvoll, geben Sie die ursprüngliche Quelle der Inhalte an und suchen Sie vor dem Absenden Ihres Beitrags nach Duplikaten. Weitere Informationen
community guidelines
Community-Einsteiger ,
Oct 17, 2017 Oct 17, 2017

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

Übersetzen
Melden
Community-Richtlinien
Seien Sie freundlich und respektvoll, geben Sie die ursprüngliche Quelle der Inhalte an und suchen Sie vor dem Absenden Ihres Beitrags nach Duplikaten. Weitere Informationen
community guidelines
Enthusiast ,
Oct 17, 2017 Oct 17, 2017

You are not only one who tried to solve this problem. Look for already made solution first 😉

Übersetzen
Melden
Community-Richtlinien
Seien Sie freundlich und respektvoll, geben Sie die ursprüngliche Quelle der Inhalte an und suchen Sie vor dem Absenden Ihres Beitrags nach Duplikaten. Weitere Informationen
community guidelines
Community-Einsteiger ,
Oct 17, 2017 Oct 17, 2017

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?

Übersetzen
Melden
Community-Richtlinien
Seien Sie freundlich und respektvoll, geben Sie die ursprüngliche Quelle der Inhalte an und suchen Sie vor dem Absenden Ihres Beitrags nach Duplikaten. Weitere Informationen
community guidelines
Ratgeber ,
Oct 17, 2017 Oct 17, 2017

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!

Übersetzen
Melden
Community-Richtlinien
Seien Sie freundlich und respektvoll, geben Sie die ursprüngliche Quelle der Inhalte an und suchen Sie vor dem Absenden Ihres Beitrags nach Duplikaten. Weitere Informationen
community guidelines
Community-Einsteiger ,
Oct 17, 2017 Oct 17, 2017

Actually, that's all I need to know. Thank you for your time and being so kind, have a great day!

Übersetzen
Melden
Community-Richtlinien
Seien Sie freundlich und respektvoll, geben Sie die ursprüngliche Quelle der Inhalte an und suchen Sie vor dem Absenden Ihres Beitrags nach Duplikaten. Weitere Informationen
community guidelines
Enthusiast ,
Oct 17, 2017 Oct 17, 2017

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++

Übersetzen
Melden
Community-Richtlinien
Seien Sie freundlich und respektvoll, geben Sie die ursprüngliche Quelle der Inhalte an und suchen Sie vor dem Absenden Ihres Beitrags nach Duplikaten. Weitere Informationen
community guidelines
Community-Einsteiger ,
Oct 17, 2017 Oct 17, 2017
AKTUELL

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.

Übersetzen
Melden
Community-Richtlinien
Seien Sie freundlich und respektvoll, geben Sie die ursprüngliche Quelle der Inhalte an und suchen Sie vor dem Absenden Ihres Beitrags nach Duplikaten. Weitere Informationen
community guidelines