Photoshop: Replace linked smart objet through data variables

  • 3
  • Idea
  • Updated 4 years ago
  • (Edited)
I would great to have a linked smart object and be able to replace it, according to the data in the data variables, instead of just replacing pixels with static images.
Photo of Ignacio Galdames

Ignacio Galdames

  • 2 Posts
  • 0 Reply Likes

Posted 4 years ago

  • 3
Photo of Patrik Bloebaum

Patrik Bloebaum

  • 4 Posts
  • 0 Reply Likes
This reply was created from a merged topic originally titled Photoshop: Ability to replace smart objects via the pixel variables function to o....

I have been using Pixel variables often to make many composites shots that are all tailored however this mainly works with flats not with smart objects. It would be good if one can replace smart objects or 3D objects as well using pixel variables.

Also when exporting all pixel variables using the export function it would be great to not have the process stop when a variable is missing and give an error dialog but rather to have a error report at the end of the full export. Otherwise you might have to sit there and push enter every few minutes. An html report or similar would be much more efficient and then allow you to redo the ones after you added the missing assets where they are meant to be and re-run the data set pixel variable export on the ones that error'ed. If you could temporarily store the data sets that errored and just re-run that as a set later that would be even better.

How this would help. Well in terms of foreign packaging it would allow me to replace the dust jacket of a book or prototype with other language versions much faster. so I could export a simulated photoshoot of a book in front of a backdrop in 30 languages in 15 minutes for example.
Photo of Patrik Bloebaum

Patrik Bloebaum

  • 4 Posts
  • 0 Reply Likes
Hi,

Well I made an applescript that does this function sort of [the code can be used perhaps to take this further. I is just a first rough draft of the code and I did not spend too much time on debugging it or cleaning it up.]

Quick explanation first:

Anyway the script assumes that you use a 3 letter code followed by a hyphen in order to identify layers that will be replaced. I call them language smarts as they are smart objects that replaced out depending on which language you are dealing with.

In my test example I used the demo psd file that Adobe supplies for linked smarts. (playfest_poster_wild_leaves.psd) and manually replaced the smarts with external smarts that had a language prefix such as "ENG-band_names_wild_leaves.psd"

The folder structure for the replacement smarts is kind of fixed as it is based on the layer names but the script then lets you just select your template psd that was prepped as mentioned above and then select the "Language Smarts" folder and then it will generate the modified PSDS to the location of your choice. It works on linked and embedded smart objects.

Example:

Language Smarts
band_names_wild_leaves
ENG-band_names_wild_leaves.psd
FRE-band_names_wild_leaves.psd
GER-band_names_wild_leaves.psd
common_bottom_bar
ENG-common_bottom_bar.psd
FRE-common_bottom_bar.psd
GER-common_bottom_bar.psd
Play_fest_logo
ENG-Play_fest_logo.psd
FRE-Play_fest_logo.psd
GER-Play_fest_logo.psd
WildLeaves_blurmask
ENG-WildLeaves_blurmask.psd
FRE-WildLeaves_blurmask.psd
GER-WildLeaves_blurmask.psd
WildLeaves_logo
ENG-WildLeaves_logo.psd
FRE-WildLeaves_logo.psd
GER-WildLeaves_logo.psd

Here is the applescript code compiled on MAC OS 10.7.5
for Adobe Photoshop CC 2014
------------------------------------------------
-- written 8 November 2014 and updated 1 Dec. 2014 - Patrik B.

set MyKind to {"smart object layer"} -- this is the layers it will filter by
set myerror to {}

global mylayerlist, MyKind, myprefix, myfolder, myerror, mydecision2save, myprefixfaillist, my2nderrorlog, my1sterrorlog, myflatoption, mysuccesslog

set mylayerlist to {}
set myprefixfaillist to {}
set my1sterrorlog to {}
set my2nderrorlog to {}
set mysuccesslog to {}

tell application "Adobe Photoshop CC 2014"
set myrepeat to false
try
set myfile to current document
on error
--display dialog "You have no documents open" buttons {"OK"} default button 1
copy (choose file with prompt "Select the template file(s) to open" with multiple selections allowed) to myfile
if class of myfile is list then
set myrepeat to true
else
set myrepeat to false
end if

end try
set mylist to {"CHI", "ENG", "DAN", "DUT", "FRE", "GER", "GRE", "HEB", "HUN", "ITA", "JAP", "LAT", "NOR", "POR", "RUS", "SWE"} -- list of language prefixes - smart objects have text in them in different languages
--language codes are based on the first 3 letters of the language as spelled in English -i.e. "ENG-" English.
copy (choose from list mylist with multiple selections allowed) to myprefixes
log myprefixes

display dialog "Select whether you want the exported psds to be flat or layered." buttons {"Cancel", "Layered", "Flat"} default button 2
copy button returned of result to myflatoption
if myflatoption = "Cancel" then return

copy (choose folder with prompt "Select the folder where the replacement shots (smarts) are:") to myfolder
copy (choose folder with prompt "Select the folder where the exported images (flats/layered psds) should go:") to myflatfolder
--copy my removenameparts(myfile) to mymodfolders
-- my myfoldercreator(mymodfolders, myflatfolder)

set starttime to my gettime()
set mydecision2save to false
if myrepeat as string = "true" then
repeat with myonefile in myfile

if class of myprefixes is list then
set myCount to count of myprefixes
repeat with k from 1 to myCount
set myprefix to item k of myprefixes
copy my decidewhether2modify(myonefile, myfolder, myprefixes, myprefix) to mydecision
if mydecision = "Success" then
open file (myonefile as string) showing dialogs never

my saveas(myfolder, myflatfolder)
end if
if mydecision = "Fail" then
copy my getfilename(myonefile) to mynewname
copy my removenameparts(mynewname) to mymodpsdname
set mymodpsdname to (myprefix & "-" & mymodpsdname & ".psd" as string)
if mymodpsdname is not in my2nderrorlog then
set end of my2nderrorlog to mymodpsdname & return
end if
end if
end repeat
else
copy my decidewhether2modify(myonefile, myfolder, myprefixes, myprefix) to mydecision
if mydecision = "Success" then
set myprefix to myprefixes
my saveas(myfolder, myflatfolder)
end if
if mydecision = "Fail" then
copy my getfilename(myfile) to mynewname
copy my removenameparts(mynewname) to mymodpsdname
set mymodpsdname to (myprefix & "-" & mymodpsdname & ".psd" as string)
if mymodpsdname is not in my2nderrorlog then
set end of my2nderrorlog to mymodpsdname & return
end if
end if
end if
close current document saving no
end repeat
else
if class of myprefixes is list then
set myCount to count of myprefixes
repeat with k from 1 to myCount
set myprefix to item k of myprefixes
copy my decidewhether2modify(myfile, myfolder, myprefixes, myprefix) to mydecision
open file (myfile as string) showing dialogs never

if mydecision = "Success" then
my saveas(myfolder, myflatfolder)
end if
if mydecision = "Fail" then
copy my getfilename(myfile) to mynewname
copy my removenameparts(mynewname) to mymodpsdname
set mymodpsdname to (myprefix & "-" & mymodpsdname & ".psd" as string)
if mymodpsdname is not in my2nderrorlog then
set end of my2nderrorlog to mymodpsdname & return
end if
end if

end repeat
else
copy my decidewhether2modify(myfile, myfolder, myprefixes, myprefix) to mydecision
if mydecision = "Success" then
open file (myfile as string) showing dialogs never

set myprefix to myprefixes
my saveas(myfolder, myflatfolder)
end if
if mydecision = "Fail" then
copy my getfilename(myfile) to mynewname
copy my removenameparts(mynewname) to mymodpsdname
set mymodpsdname to (myprefix & "-" & mymodpsdname & ".psd" as string)
if mymodpsdname is not in my2nderrorlog then
set end of my2nderrorlog to mymodpsdname & return
end if
end if

end if
close current document saving no
end if

set endtime to my gettime()
set timeinbetween to endtime - starttime
my makehtmlreport(myerror, timeinbetween)

end tell

on decidewhether2modify(filepathofpsd, myfolder, myprefixes, myprefix)
set filepathofpsd to POSIX path of (filepathofpsd as string)
copy my psdlayercheck(filepathofpsd) to mylayerlist
copy my checkifsmartexists(mylayerlist, myfolder, myprefixes) to {mysmartimagefaillist, myprefixfaillist1}
repeat with myi in myprefixfaillist1
if myi is not in myprefixfaillist then
set end of myprefixfaillist to (myi as string)
end if
end repeat
if myprefix is in myprefixfaillist then
set mydecision to "Fail"
else
set mydecision to "Success"
end if
return mydecision
end decidewhether2modify

on saveas(myfolder, myflatfolder)
tell application "Adobe Photoshop CC 2014"
tell current document
set MyName to name
my doGetLayers(layers)
set mynumber to count mylayerlist
copy my rename(MyName) to {mynewimagename, mytruncname}
set my2ndtruncname to characters 1 through -5 of mytruncname
-- set myflatpath to myflatfolder & my2ndtruncname & ":" & mynewimagename
if mydecision2save is true then
if myprefix is not in myprefixfaillist then
if myflatoption as string = "Flat" then
set myflatoption to "false"
else
set myflatoption to "true"
end if
copy my removenameparts(mytruncname) to mymodname --removes the word psd or template from the name
my myfoldercreator1(mymodname, myflatfolder) -- checks if the subfolder exists if not creates it
log mymodname
copy my removenameparts(mynewimagename) to mymodpsdname
set mymodpsdname to (mymodpsdname & ".psd" as string)
set myflatpath to myflatfolder & (mymodname as string) & ":" & mymodpsdname

set myoptions to {class:Photoshop save options, embed color profile:true, save alpha channels:true, save annotations:false, save layers:myflatoption, save spot colors:true}
save as Photoshop format in (myflatpath as string) with options myoptions copying yes
set end of mysuccesslog to mymodpsdname
-- save as Photoshop format in (myflatpath as string) copying yes
end if

else
--if myprefix is in myprefixfaillist then
copy my removenameparts(mynewimagename) to mymodpsdname
set mymodpsdname to (mymodpsdname & ".psd" as string)
if mymodpsdname is not in my2nderrorlog then
set end of my2nderrorlog to mymodpsdname & return
end if
-- end if
end if
end tell
end tell
end saveas

on doGetLayers(myCurrentLayers) -- this gets all the layers from a psd document that are smart objects
tell application "Adobe Photoshop CC 2014"
repeat with i from 1 to count myCurrentLayers
set myLayer to item i of myCurrentLayers
if class of myLayer is art layer then
log kind of myLayer & "-------- kind"
if (kind of myLayer as string) is in MyKind then
-- if myprefix is not in myprefixfaillist then
set end of mylayerlist to myLayer
set MyName to name of myLayer
log MyName & "----myname"
my myselect(MyName)
copy my rename(MyName) to {mynewname, mytruncname}
copy my replacelink(mynewname, mytruncname, myfolder) & return to mytemperror
copy mytemperror to end of myerror

if mytemperror begins with "Failed" then
set mydecision2save to false
set end of myprefixfaillist to myprefix
if my1sterrorlog does not contain mytemperror then
set end of my1sterrorlog to mytemperror
end if
else
set mydecision2save to true
end if
-- end if
end if
else if class of myLayer is layer set then
my doGetLayers(layers of myLayer)
end if
end repeat
end tell
end doGetLayers

on replacelink(mynewname, mytruncname, myfolder) -- this replaces a smart object with another smart object
if mytruncname begins with "-" then set mytruncname to characters 2 through -1 of mytruncname
set myfile to myfolder & mytruncname & ":" & mynewname & ".psd"

--set myfile to myfolder & mynewname & ".psd"
tell application "Adobe Photoshop CC 2014"
log myfile & " -----filepath"
copy my mydoesfileexistcheck(myfile) to mydecision
if mydecision as string is "Success" then
set myfileposix to POSIX path of (myfile as string)
try
do javascript " var idplacedLayerReplaceContents = stringIDToTypeID( \"placedLayerReplaceContents\" );
var desc33 = new ActionDescriptor();
var idnull = charIDToTypeID( \"null\" );
desc33.putPath( idnull, new File( \"/" & myfileposix & "\" ) );
executeAction( idplacedLayerReplaceContents, desc33, DialogModes.NO );"
return "Success relinking " & mynewname & ".psd"
on error
return "Failed relinking " & mynewname & ".psd"

end try
else
return "Failed relinking " & mynewname & ".psd"
end if
end tell
end replacelink

on mydoesfileexistcheck(mypath)
try
set mydata to info for file (mypath as string)
return "Success"
on error
return "Error"
end try
end mydoesfileexistcheck

on gettime()
set mytime to time of (current date)
return mytime
end gettime

on myselect(MYLAYERNAME) -- this selects the next smart layer in photoshop so you can then replace out the smart later
tell application "Adobe Photoshop CC 2014"
do javascript "
var idslct = charIDToTypeID( \"slct\" );
var desc43 = new ActionDescriptor();
var idnull = charIDToTypeID( \"null\" );
var ref26 = new ActionReference();
var idLyr = charIDToTypeID( \"Lyr \" );
ref26.putName( idLyr, \"" & MYLAYERNAME & "\" );
desc43.putReference( idnull, ref26 );
var idMkVs = charIDToTypeID( \"MkVs\" );
desc43.putBoolean( idMkVs, false );
executeAction( idslct, desc43, DialogModes.NO );"
end tell
end myselect

on rename2(MyName) -- this renames a filename
if character 4 of MyName = "-" then
set mytruncname to characters 4 through -1 of MyName
else
set mytruncname to MyName
set mytruncnamewith to "-" & MyName
end if
set mynewname to myprefix & mytruncname
return {mynewname as string, mytruncname as string}
end rename2

on rename(MyName) -- this renames a filename

if character 4 of MyName = "-" then
set mytruncname to characters 4 through -1 of MyName
else
set mytruncname to MyName
end if
if mytruncname does not start with "-" then
set mynewname to myprefix & "-" & mytruncname
else
set mynewname to myprefix & mytruncname
end if
return {mynewname as string, mytruncname as string}
end rename

on removenameparts(MyName) -- this removes parts of a filename such as psd, template, master etc.

if MyName ends with "_template.psd" then
set MyName to (characters 1 through -14 of MyName) as string
end if

if MyName ends with "-template.psd" then
set MyName to (characters 1 through -14 of MyName) as string
end if
if MyName ends with "_master.psd" then
set MyName to (characters 1 through -14 of MyName) as string
end if

if MyName ends with "-master.psd" then
set MyName to (characters 1 through -14 of MyName) as string
end if

if MyName ends with ".psd" then
set MyName to (characters 1 through -5 of MyName) as string
end if
set mynewfoldername to MyName as string

return (mynewfoldername)

end removenameparts

on makehtmlreport(mypaths, timeinbetween) -- this generates the html report at the end
set savetime to my gettime()

set HTMLfile to (path to temporary items as string) & "Temp-Smart-Object-Replacement_report_" & savetime & ".html"
set f to open for access file HTMLfile with write permission
set eof of f to 0 --- truncates the file if already there

write "

Smart Objects report:

" & timeinbetween & " seconds taken:" & "
Script finished running." to f

if 1 is 0 then
write "Report below"
else

write "
    " to f
    write "The following images were exported.
    " to f

    if mysuccesslog is not {} then
    repeat with d_File in mysuccesslog

    write "
  • " & (d_File as string) & "
  • " to f
    end repeat
    write "
" & return & return to f

end if
write "
    " to f
    write "The following flats/layered psds were not generated.
    " to f

    if my2nderrorlog is not {} then
    repeat with a_File in my2nderrorlog

    write "
  • " & (a_File as string) & "
  • " to f
    end repeat
    write "
" & return & return to f

end if
write "
    " to f
    write "The following smarts were missing so were not relinked.
    " to f
    if my1sterrorlog is not {} then

    repeat with b_File in my1sterrorlog

    write "
  • " & (b_File as string) & "
  • " to f
    end repeat
    write "
" & return & return to f

end if

(* repeat with aFile in mypaths
if (aFile as text) contains "old-" or (aFile as text) contains "outdated" or (aFile as text) contains "Failed" or (aFile as text) contains "- old" or (aFile as text) contains "- original" then --- or "outdated" or "Correction" then

write "" & (aFile as string) & "" to f
else
write "" & (aFile as string) & "" to f
end if
end repeat
write "" to f
*)

end if

write "" to f
close access f
tell application "Safari" to open file HTMLfile
tell application "Safari" to activate
end makehtmlreport
on getitem(myitem, mylist)
repeat with myid from 1 to count of mylist

set myiteration to (item myid of mylist) as list
if myiteration = myitem then
return myid
end if
end repeat
end getitem

on myfoldercreator1(theFile, myfolder) -- this creates the folders into which the images go in case these are missing
copy my mydoesfileexistcheck((myfolder as string) & theFile) to doesExist
if doesExist = "Error" then
set pdfunquotedPath to POSIX path of ((myfolder as string) & theFile)
set myfoldertomake to (pdfunquotedPath) as string
log myfoldertomake
set makefolder to do shell script ("mkdir -p '" & myfoldertomake & "'")
end if
end myfoldercreator1

on psdlayercheck(This_PSD)

set The_Layers to paragraphs 2 through -2 of (do shell script "/usr/bin/mdls -name kMDItemLayerNames " & quoted form of (This_PSD))

set mylayerlist to {}
set mylayercount to count of The_Layers
repeat with i in The_Layers

if i begins with " \"" then
set m to (characters 6 through -1 of i) as string
if m ends with "\"," then
set m to (characters 1 through -3 of m) as string
log m
end if
if m ends with "\"" then
set m to (characters 1 through -2 of m) as string
log m
end if
set end of mylayerlist to m
else
if i begins with " " then
set m to (characters 4 through -1 of i) as string
log m
if m ends with ",\"," then
set m to (characters 1 through -3 of m) as string
log m
end if
if m ends with "\"" then
set m to (characters 1 through -2 of m) as string
log m
end if
set end of mylayerlist to m
log m
else
if i begins with " " then
set m to (characters 5 through -1 of i) as string

if m ends with "," then
set m to (characters 1 through -2 of m) as string
--log m & "--1"
end if
set end of mylayerlist to m
--log m & "--2"
else
set end of mylayerlist to (i as string)
--log m
end if
end if
end if
end repeat
set mylayercountnew to count mylayerlist
if mylayercountnew is not equal to mylayercount then display dialog "Layer count mismatch"
return mylayerlist
end psdlayercheck

on checkifsmartexists(mylayerlist, myfolder, myprefixes) -- handler to find smarts that don't exist so they can't be dropped in
set mylanglayers to {}
set myprefixfaillist1 to {}
repeat with o in mylayerlist

if character 4 of o = "-" then
set end of mylanglayers to (o as string)
end if
end repeat
set mysmartimagefaillist to {}
repeat with myspecificlayer in mylanglayers
repeat with myprefix in myprefixes

set n to (characters 5 through -1 of myspecificlayer) as string
set myimagename to myprefix & "-" & n & ".psd"
set myfile2check to (myfolder as string) & n & ":" & myimagename
log myfile2check
copy my mydoesfileexistcheck(myfile2check) to myfileexists
if myfileexists = "Error" then
if myimagename is not in my1sterrorlog then
set end of my1sterrorlog to myimagename
end if
if myimagename is not in mysmartimagefaillist then
set end of mysmartimagefaillist to myimagename
end if
if myprefix is not in myprefixfaillist1 then
set end of myprefixfaillist1 to (myprefix as string)
end if
end if
log myfileexists
end repeat
end repeat

return {mysmartimagefaillist, myprefixfaillist1}
end checkifsmartexists

on getfilename(MyName)
set MyName to MyName as string
set AppleScript's text item delimiters to ":"
set mynewname to last text item of MyName
set AppleScript's text item delimiters to ""
return mynewname
end getfilename