Photoshop: Rasterize all smart objects in a PSD file to shrink down it's size

  • 2
  • Idea
  • Updated 2 years ago
  • (Edited)
When doing my designs and layouts in photoshop I often work with smart objects, so I can resize them later. But smart objects blow up the files size of the PSD files. Often I can shrink down a PSD file from 100MB to about 20MB by rasterizing the smart objects in it. But rasterizing every smart object manually is time consuming, so I would like a function / Script which does all this for me with a click.
Photo of Kenny

Kenny

  • 27 Posts
  • 0 Reply Likes

Posted 6 years ago

  • 2
Photo of Kenny

Kenny

  • 27 Posts
  • 0 Reply Likes
Or maybe a dialog, where I can see all smart objects with peview and possible file size to shrink down. So I can select only the layers I want and are needed to rasterize because of their size.
Photo of Kenny

Kenny

  • 27 Posts
  • 0 Reply Likes
And maybe also the possiblity to rasterize layer masks. I think this would also save some space.
Photo of christoph pfaffenbichler

christoph pfaffenbichler, Champion

  • 1225 Posts
  • 172 Reply Likes
You could give this Script a try:
// convert all smart objects to pixel content;
// 2010, use it at your own risk;
#target photoshop;
var myDocument = app.activeDocument;
myDocument.suspendHistory("rasterizeAllSmartObjects", "rasterizeSOLayers(myDocument)");
////// function to rasterize all smart objects //////
function rasterizeSOLayers (theParent) {
for (var m = theParent.layers.length - 1; m >= 0;m--) {
var theLayer = theParent.layers[m];
// apply the funtion to layersets;
if (theLayer.typename == "ArtLayer") {
if (theLayer.kind == LayerKind.SMARTOBJECT) {
var theVisibility = theLayer.visible;
myDocument.activeLayer = theLayer;
// rasterize;
var id631 = charIDToTypeID( "slct" );
var desc125 = new ActionDescriptor();
var id632 = charIDToTypeID( "null" );
var ref83 = new ActionReference();
var id633 = charIDToTypeID( "Mn " );
var id634 = charIDToTypeID( "MnIt" );
var id635 = stringIDToTypeID( "rasterizePlaced" );
ref83.putEnumerated( id633, id634, id635 );
desc125.putReference( id632, ref83 );
executeAction( id631, desc125, DialogModes.NO );
// reset visibility;
theLayer.visible = theVisibility;
};
}
else {
rasterizeSOLayers(theLayer)
}
}
return
};
Photo of Kenny

Kenny

  • 27 Posts
  • 0 Reply Likes
I tried the script, but got an error. I did this on a simple new file with 2 smart objects and 2 pixel layers and put them in a folder - to see if it would have problems with folder. If this script would work I, that would be nice. But an official version and with the mentioned dialog I think that would be useful.

Photo of christoph pfaffenbichler

christoph pfaffenbichler, Champion

  • 1221 Posts
  • 170 Reply Likes
If you are on CS6 I’m afraid I can’t trouble-shoot for that yet, with CS5 it seems to perform as expected.
Photo of Kenny

Kenny

  • 27 Posts
  • 0 Reply Likes
I am using Photoshop CS5.1 (12.1) x64 of the CS5.5 Suite.
Photo of Paul Riggott

Paul Riggott

  • 359 Posts
  • 143 Reply Likes
It looks as if the forum has truncated part of the script.
"Mn " should be "Mn space space so there is a space missing.

Here is my version, it should be quicker as it uses AM to check for layers with SOs

 

//#target photoshop
app.bringToFront();
activeDocument.suspendHistory('Raster SOs', 'main()');
function main(){
if(!documents.length) return;
selectAllLayers();
var selectedLayers = getSelectedLayersIdx();
for(var a in selectedLayers){
if(hasSmartObject(Number(selectedLayers[a]))){
makeActiveByIndex(Number(selectedLayers[a]),false);
executeAction( stringIDToTypeID( "rasterizePlaced" ), undefined, DialogModes.NO );
}
}
}
function hasSmartObject(idx){
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , stringIDToTypeID( "smartObject" ));
ref.putIndex( charIDToTypeID( "Lyr " ), idx);
var desc = executeActionGet(ref);
if(desc.hasKey(stringIDToTypeID('smartObject'))) return true; else return false;
}
function makeActiveByIndex( idx, visible ){
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIndex(charIDToTypeID( "Lyr " ), idx)
desc.putReference( charIDToTypeID( "null" ), ref );
desc.putBoolean( charIDToTypeID( "MkVs" ), visible );
executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO );
};

function getSelectedLayersIdx(){
var selectedLayers = new Array;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
if( desc.hasKey( stringIDToTypeID( 'targetLayers' ) ) ){
desc = desc.getList( stringIDToTypeID( 'targetLayers' ));
var c = desc.count
var selectedLayers = new Array();
for(var i=0;i<c;i++){
try{
activeDocument.backgroundLayer;
selectedLayers.push( desc.getReference( i ).getIndex() );
}catch(e){
selectedLayers.push( desc.getReference( i ).getIndex()+1 );
}
}
}else{
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "ItmI" ));
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
try{
activeDocument.backgroundLayer;
selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" ))-1);
}catch(e){
selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" )));
}
}
return selectedLayers;
};
function selectAllLayers() {
var desc29 = new ActionDescriptor();
var ref23 = new ActionReference();
ref23.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc29.putReference( charIDToTypeID('null'), ref23 );
executeAction( stringIDToTypeID('selectAllLayers'), desc29, DialogModes.NO );
}
</pre>
Photo of Kenny

Kenny

  • 27 Posts
  • 0 Reply Likes
This works really well, thank you. The "pre" at the end of the code is not meant to be part of the script, right? Can you you change this script so it does not change the open/close state of the folders?
Photo of Paul Riggott

Paul Riggott

  • 359 Posts
  • 143 Reply Likes
No the pre should not be part of the code. Sorry but this is not possible to keep the state of the folders, if a layer is made the active layer the folder is opened and there is no method of finding what state a folder is or closing it.
Maybe in CS7 we might get futher functions?
Photo of Vu Dang

Vu Dang

  • 2 Posts
  • 0 Reply Likes
Thanks for the code...how do you implement it in Photoshop?
Photo of Jeffrey Tranberry

Jeffrey Tranberry, Sr. Product Manager, Digital Imaging

  • 14149 Posts
  • 1765 Reply Likes
One work around:

Select a smart object layer
Choose Select>Similar Layers
Then you can choose Layer>Rasterize Layers
Photo of Jaroslav Bereza

Jaroslav Bereza

  • 781 Posts
  • 166 Reply Likes
I just wonder where is this menu item. Because i can't filter layers with script. So I thought this could script listener record. Anyway, I do not need a rasterize all smart objects. I want it because it could be useful in another scripts.
Photo of Jeffrey Tranberry

Jeffrey Tranberry, Sr. Product Manager, Digital Imaging

  • 14149 Posts
  • 1765 Reply Likes
There was a command in CS2-CS5 called Select Similar Layers. Might be able to snag the listener code to see if it still works. You could create a smart object layer, select similar layers, then rasterize. Just an idea. Don't have an old version handy on the machine I'm on.
Photo of Cristen Gillespie

Cristen Gillespie

  • 1269 Posts
  • 325 Reply Likes
I thought we only had the Layers panel to select by filtering now. I'm glad I wasn't missing something that important in the interface. Why can't a script get at that particular feature? It would make a lot of sense to be able to filter your layers panel before performing a routine action through a script. In fact, it would be nice if it were actionable, not that I'll hold my breath for it.
Photo of Paul Riggott

Paul Riggott

  • 359 Posts
  • 143 Reply Likes
It doesn't work with anthing newer than CS5 Jeffrey.

selectSimilarLayers();
function selectSimilarLayers() {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc.putReference( charIDToTypeID('null'), ref );
executeAction( stringIDToTypeID('selectSimilarLayers'), desc, DialogModes.NO );
};
Photo of Jaroslav Bereza

Jaroslav Bereza

  • 781 Posts
  • 166 Reply Likes
Photo of Paul Riggott

Paul Riggott

  • 359 Posts
  • 143 Reply Likes
Close but no cigar Jeffrey, doing it that way will rasterize all text layers as well.
Photo of Kenny

Kenny

  • 27 Posts
  • 0 Reply Likes
My text layer did not get rasterized. You can ratser "Layer" or "All Layers" - you have to raster only "Layer" for rasterizing the selected.
Photo of Paul Riggott

Paul Riggott

  • 359 Posts
  • 143 Reply Likes
Thanks Kenny, I should do a bit more testing!
Photo of Jeffrey Tranberry

Jeffrey Tranberry, Sr. Product Manager, Digital Imaging

  • 14090 Posts
  • 1748 Reply Likes
Ahh. Sorry. I see I suggested that earlier. Smart Objects and Text layers get selected as similar? That's odd. Was worth a shot.
Photo of NICOLE ANDRES

NICOLE ANDRES

  • 10 Posts
  • 2 Reply Likes
And also the other way round:

It would be great to have the option to convert a smart object back to its original file.

There are sometimes changes/situations, where smart objects slow down your compositing process (because every small change takes a lot time until it becomes visible in the main document), but then there is no way to dissolve the smart object back into its contained layers.

If the smart object could be dissolved into all its actual layers, it would mean that all transformations of the smart object need to be transferred to all its layers.

To do it manually (by dragging and dropping of all layers from the smart document) is a lot work and sometimes impossible.
(Edited)
Photo of christoph pfaffenbichler

christoph pfaffenbichler, Champion

  • 1208 Posts
  • 166 Reply Likes
This issue has been brought up before and I think it usually would not make a lot of sense. 

In any case you could automate the process with a Script that basically has to create a new Smart Object Via Copy for each contained Layer, open that SO, remove all Layers but one, save, close, rasterise that SO etc. – of course taking all possible combinations of Layers/Groups, Clipping Masks, Layer Masks, Vector Masks, ... into account would likely make this a pretty complicated process. 
Also applied transformations and Smart Filters could make the result impossible to recreate with the individual Layers in the containing document. 
Photo of Chris Cox

Chris Cox

  • 20280 Posts
  • 813 Reply Likes
Converting smart objects back to layers is also usually impossible without serious issues - because smart objects can be transformed, color mode and depth changed, aspect ratio corrected, filtered, etc.  There are requests for this, but it can only work well in very, very limited circumstances.
Photo of christoph pfaffenbichler

christoph pfaffenbichler, Champion

  • 1208 Posts
  • 166 Reply Likes
This thread my not be the ideal place but I want to say that I am continually impressed by your and a couple of your Photoshop team colleagues’ willingness to communicate with actual users on the Fora. 
Adobe’s and some product teams’ performance may not be above reproach and Photoshop certainly can (and will) be improved in the future but for me at least it does make a difference to get qualified feedback. 
Photo of Chris Cox

Chris Cox

  • 20280 Posts
  • 813 Reply Likes
Thanks.
Photo of Jon Kerr

Jon Kerr

  • 1 Post
  • 0 Reply Likes
In your Layers tab at the very top you have a search icon which is drop down menu for search type.  Choose 'Kind' from the drop down and then choose the smart object icon to the right of the drop down list.  Your layers tab now only shows smart objects.  Select all the Layers and choose Layer > Rasterize > Smart Object.  Done.