Main Page
 The gatekeeper of reality is
 quantified imagination.

Stay notified when site changes by adding your email address:

Your Email:

Bookmark and Share
Email Notification
Project Adobe Photoshop JSX
    Purpose
The purpose of this project is to demonstrate how you can run Adobe Photoshop from a webpage in order to create images; this is accomplished by the use of Adobe's JSX format (which Photoshop reads in order to create an image). Prior to this free release of methods and source code, it was virtually IMPOSSIBLE to find reliable source code and step-by-step instructions on how to use Adobe Photoshop CS2+ on a web site through a regular web page and have it perform tasks such as creating an image on a web site.


How I Approach This Project
The research and working method that was reached in late 2006 was done using ASP (although this can easily be done in .Net 3.5 as well), and Microsoft Server 2003 box.

Let's Begin
The big question that you may have is...how can you do something like accept parameters used to create an image, pass those to your ASP page and in turn, pass that to Adobe Photoshop CS2+ so that it creates the image? Although tedious to initially setup, the solution is simple...and is largely possible due to JSX importing that you can do with Adobe Photoshop CS2+ (you configure a JSX file with parameters and commands similar to Javascript which Adobe Photoshop CS2+ completes). It is important to understand security of the web server that you may experiment with and take appropriate safe guards; more than likely you don't want public-at-large to be using this.

In addition to the information on this web page, you may wish to go through the presentation that I gave. Go to the presentation.

Overview
  1. [STEP 1] Set up the web server and then set up some very simple ASP pages with code in them (such as snippets below) so you can see everything working.
  2. [STEP 2] Create an ASP page with a form in it. The form prompts for text that you want to have appear in the image.
  3. [STEP 3] Create an ASP page that accepts the form data. This ASP page will also create the JSX file. This ASP page will also invoke Adobe Photoshop CS2+ and the JSX file will be read by Adobe Photoshop CS2+ and the image will be created.
STEP 1: Server Steps
  1. Grant Local Activation permission for the COM Server application with CLSID {A1F4E726-8CF1-11D1-BF92-0060081ED811} (also known as the WIA) to the user NT AUTHORITY\NETWORK SERVICE, by giving the Internet Guest User Account (IUSR_...) Launch and Local Activation permissions.
  2. The Windows Image Aquisition (WIA) Service must be started.
  3. The DCOM Server Process Launcher service must be started.
  4. User accounts (IUSR, System, etc) have permissions to the destination folder where the image is to be created at. Make sure the Internet Guest User Account (IUSR_...) has permissions to write to the folder; if writing is not allowed, the image will not get created. Here is the permissions that are typically used: Modify, Read & Execute, List Folder Contents, Read, Write. You may need to modify other accounts so they have Write permissions so that files can be created. NOTE: If you have an Active Directory account and use it to login to get to the script, your account may also need to be modified or have a policy created to handle it.
  5. Be sure to attach those accounts to the application folders as well (hopefully your install is not strung across multiple drives).
  6. Add the network service account access to c:\document and settings\default user (this is a hidden folder).
  7. Add the network service account access to c:\windows\debug\usermode.
  8. UNINSTALL Extendscript Toolkit from the web server (typically located here: \Program Files\Adobe\Adobe Utilities\ExtendScript Toolkit). This helps ensure that the toolkit will not be triggered when the ASP web page is calling a JSX file. For unknown reasons if the ASP/JSX file is moved on the web server and called from the new location the Extendscript Toolkit is spawned instead of Photoshop CS2+(even though MIME association for JSX is set to Photoshop CS2+...however, the MIME association is recognized if the JSX is double-clicked locally). The same applies if a JSX file is edited with the Extendscript Toolkit and saved locally on the web server (the edit action that is accessible by right-clicking on the file and choosing "Edit"). ALWAYS open JSX files with Notepad to be safe. NOTE: You may have to upgrade the ToolKit to get the uninstall option.
  9. Restart the web server. Depending on your web server you may have to go as far as physically powering it down and back on again.
  10. Explicitly associate JSX file extensions to open with Photoshop CS2+.
  11. Examine security policies to minimize granting too much power to anonymous web surfers accessing your web server. For example, while you may have to temporarily expand permissions to get everything working which you then taper back based on your requirements, the "Everyone Group" should never have "Full Control" anywhere.
  12. Disable the adobe updater service, for Photoshop CS2, by placing the following code into a text document and saving as "DisableAUM_Updates.reg". Double-click on the file to have it modify your registry (you can also modify it so you can allow automatic updates, if needed). The reason this is disabled is that when Photoshop opens, the updater can be automatically launched. If it is detected that updates are available a dialog box will appear which will prevent any activity from occurring with Photoshop - the JSX files will not get processed.
    Windows Registry Editor Version 5.00
    [HKEY_LOCAL_MACHINE\SOFTWARE\Adobe\Updater]
    "Enterprise"=dword:00000001
  13. Need to track permissions and other possible issues with your web server? Check out Filemon; very invaluable.
TEST CODE SNIPPET
This code snippet is helpful if you are in the testing phase of trying to create a file on the web server using a similar process as how an image file would be created on the web server with Photoshop CS2+. If this code snippet does not work, you have a permissions issue to deal with.
<%
dim appName, cmdLocation, locale appName = "name_of_asp_page.asp" cmdLocation = "c:\windows\system32\" locale = Server.MapPath(appName) : locale = replace(locale, appName, "") set sbatch = server.CreateObject("WScript.Shell") set labor = sbatch.Exec(cmdLocation & "cmd.exe /C echo test >> " & locale & "temp.txt") sbatch.close set sbatch = nothing : set labor = nothing set appName = nothing : set cmdLocation = nothing : set locale = nothing %>


PHOTOSHOP CODE SNIPPET
This code snippet is helpful when you've reached the point of actually having Photoshop CS2+ run on the web server as a network service to create an image and having the process spawned through an ASP web page on the web server. Make sure your JSX is correct and has no errors (accomplished by double-clicking on the JSX file while you are locally at the web server; double-clicking should spawn Photoshop CS2+ to execute the JSX; the JSX then creates the image and saves it on the web server).

The Photoshop CS2+ application will stay active on the web server as a Network Service after it is completed with creating the image. Typically this is not an issue considering it takes between 30 seconds to 1 minute for Photoshop CS2+ to load...so most likely you will not want to repeatedly open and close the application and degrade server performance each time an image is created. Since Photoshop CS2+ loads as a Network Service you will not see the application open on the Task Bar. You can only see the Photoshop CS2+ process by viewing the Process tab of Task Manager on the web server.
<%
dim appName, dbJsx, locale
appName = "name_of_asp_page.asp"
dbJsx = "my_jsx.jsx"
locale = Server.MapPath(appName) : locale = replace(locale, appName, "")
set sbatch = server.CreateObject("WScript.Shell")
sbatch.Run locale & dbJsx, 0, FALSE
sbatch.close
set sbatch = nothing : set appName = nothing : set dbJsx = nothing : set locale = nothing
%>


CLOSING DOWN PHOTOSHOP VIA A WEBPAGE
You can close down the Photoshop CS2+ Network Service process through a webpage if you want and can be accomplished using the ASP code snippet below (since there is no way I am aware of, as of this writing, to signal Photoshop CS2+ to close itself down through JSX code):
<%
dim cmdLocation
cmdLocation = "c:\windows\system32\"
set sbatch = Server.CreateObject("WScript.Shell")
set labor = sbatch.Exec(cmdLocation & "cmd.exe /C taskkill /F /IM Photoshop.exe")
sbatch.close
set sbatch = nothing : set labor = nothing
%>


STEP 2
Now that it has been established that Adobe Photoshop CS2+ can be invoked from an ASP web page and that it can read and complete the actions in a simple JSX file you have written (a JSX file is just a text file with the JSX extension), it's time to add on what can be done. In this case, we'll prompt for some text so that the image that will be created will have some custom text inside of it.
<html>
<body>
<form method="post" action="make_image.asp">
<input type="text" name="text" size="50" maxlength="50" /> Enter some text to put into the image<br />
<input type="submit" value="Create Custom Image" />
</form>
</body>
</html>


STEP 3
Now it's time for the meat and potatoes. This ASP page (which should be the name of the ASP file you point to in the form (above)) will take the form data, create or modify the .JSX file and spawn Adobe Photoshop CS2+ so that it can read the .JSX file and create the image on the web server. Ready for the code? Here it is...
<%
dim appName, dbJsx, errInfo, height, width, title, tcolor, bcolor, name, txt_font, txt_size, txt_horizontalScale, txt_verticalScale, txt_translateX, txt_translateY, gif_colors

appName = "make_image.asp" ' Name of this application
dbJsx = "adobe_jsx.jsx" ' Adobe JSX File Containing Commands for Photoshop CS2+
errInfo = "" ' Catch Error Output From Execution
height = 65 ' Default height of image
width = 490 ' Default width of image
title = "This is a test" ' Default title of image
tcolor = "FFFFFF" ' Default text color of image
bcolor = "000000" ' Default background color of image
name = "test" ' Default filename of image
txt_font = "Verdana" ' Default text font type to use in image
txt_size = 25 ' Default font size
txt_horizontalScale = 100 ' Default font horizontal scale
txt_verticalScale = 115 ' Default font vertical scale
txt_translateX = -35 ' Default font X translation
txt_translateY = 37 ' Default font Y translation
gif_colors = 16 ' Default GIF palette

' GET Form Data
title = request.form("text")

' ERROR Accumulation
Sub HandleError(ecode, emsg)
errInfo = errInfo & "Error Code: " & ecode & "<br />Error Description: " & emsg & "<br />"
End Sub
' ERROR Probe
Sub ProbeError
If Err.Number <> 0 Then
HandleError Err.Number, Err.Description
Error.Clear
End If
On Error GoTo 0
End Sub
' BEGIN Error Monitoring
Err.Clear
On Error Resume Next

locale = Server.MapPath(appName) : locale = replace(locale, appName, "")
local_photoshop = replace(locale, "\", "\\")

' FILTER
tcolor = replace(tcolor, "#", "") : tcolor = replace(tcolor, ";", "")
bcolor = replace(bcolor, "#", "") : bcolor = replace(bcolor, ";", "")
title = replace(title, """", "\""") : title = replace(title, "“", "\""")
title = replace(title, "”", "\""") : title = replace(title, "‘", "'")
title = replace(title, "’", "'")

' BUILD the JSX File
set paper = Server.CreateObject("Scripting.FileSystemObject")
if paper.fileExists(locale & dbJsx) = False Then
' Create New JSX Content
set pen = paper.OpenTextFile(locale & dbJsx, 2, True)
Else
' Overwrite Existing JSX Content
set pen = paper.OpenTextFile(locale & dbJsx, 2, False)
End if

' Actually Build The JSX Here
pen.WriteLine "#target photoshop"
pen.WriteLine "app.displayDialogs = DialogModes.NO;" ' Do not display any dialog boxes for the entire script's execution.  Will catch font substitution dialog boxes that may come up.
pen.WriteLine "var imageHeight = " & height & ";"
pen.WriteLine "var imageWidth = " & width & ";"
pen.WriteLine "var imageText = """ & title & """;"
pen.WriteLine "var textColor = """ & tcolor & """;"
pen.WriteLine "var fillColor = """ & bcolor & """;"
pen.WriteLine "var fileLocation = """ & local_photoshop & """;"
pen.WriteLine "var originalUnit = preferences.rulerUnits;"
pen.WriteLine "preferences.rulerUnits = Units.PIXELS;"
pen.WriteLine "backgroundColor.rgb.hexValue = fillColor;"
pen.WriteLine "foregroundColor.rgb.hexValue = textColor;"
pen.WriteLine "var headerDoc = documents.add(imageWidth, imageHeight, 72, imageText, NewDocumentMode.RGB, DocumentFill.BACKGROUNDCOLOR, 1);"
pen.WriteLine "headerDoc.DialogModes = DialogModes.NO;" ' Do not display dialog boxes relating to "headerDoc" specifically.  Will not catch any font substitution dialog boxes.
pen.WriteLine "var textLayer = headerDoc.artLayers.add();"
pen.WriteLine "textLayer.kind = LayerKind.TEXT;"
pen.WriteLine "textLayer.textItem.contents = imageText;"
pen.WriteLine "textLayer.textItem.font = """ & txt_font & """;"
pen.WriteLine "textLayer.textItem.color = foregroundColor;"
pen.WriteLine "textLayer.textItem.size = " & txt_size & ";"
pen.WriteLine "textLayer.textItem.horizontalScale = " & txt_horizontalScale & ";"
pen.WriteLine "textLayer.textItem.verticalScale = " & txt_verticalScale & ";"
pen.WriteLine "textLayer.textItem.antiAliasMethod = AntiAlias.SHARP;"
pen.WriteLine "textLayer.translate(" & txt_translateX & ", " & txt_translateY & ");"
pen.WriteLine "var headerSaveOptions = new GIFSaveOptions();"
pen.WriteLine "headerSaveOptions.colors = " & gif_colors & ";"
pen.WriteLine "var headerFile = new File(fileLocation + """ & name & ".gif"");"
pen.WriteLine "headerDoc.flatten();"
pen.WriteLine "headerDoc.saveAs(headerFile,headerSaveOptions,true,Extension.LOWERCASE);"
pen.WriteLine "headerDoc.close(SaveOptions.DONOTSAVECHANGES);"
pen.WriteLine "preferences.rulerUnits = originalUnit;"
pen.WriteLine "imageHeight = null;"
pen.WriteLine "imageWidth = null;"
pen.WriteLine "headerText = null;"
pen.WriteLine "textColor = null;"
pen.WriteLine "fillColor = null;"
pen.WriteLine "fileLocation = null;"
pen.WriteLine "originalUnit = null;"
pen.WriteLine "headerDoc = null;"
pen.WriteLine "textLayer = null;"
pen.WriteLine "headerSaveOptions = null;"
pen.WriteLine "headerFile = null;"
pen.close()
set pen = nothing
set paper = nothing

' ERROR Trap
ProbeError()

' SPAWN Adobe With JSX
set sbatch = Server.CreateObject("WScript.Shell")
sbatch.Run locale & dbJsx, 0, FALSE
set sbatch = nothing

' ERROR Trap
ProbeError()

' SHOW Output
response.write "<html>" & vbcrlf
response.write "<body>" & vbcrlf
response.write errInfo & vbcrlf
response.write "</body>" & vbcrlf
response.write "</html>" & vbcrlf

' FREE Resources
set appName = nothing : set dbJsx = nothing : set errInfo = nothing : set height = nothing : set width = nothing
set title = nothing : set tcolor = nothing : set bcolor = nothing : set name = nothing : set txt_font = nothing
set txt_size = nothing : set txt_horizontalScale = nothing : set txt_verticalScale = nothing
set txt_translateX = nothing : set txt_translateY = nothing : set gif_colors = nothing
%>
About Joe