Posts in Category "photoshop extensions"

Formatting Text Ranges in Photoshop

In response to an earlier post, “Entering and Formatting Text” (here) a couple of folks asked if there was a way to apply formatting to ranges of text in a Photoshop text layer. It’s certainly not obvious from the Photoshop scripting object model how one would go about doing this—in fact, I don’t think it’s possible, and said so in my response to the comments.

This exchange got me thinking. So it’s impossible—how do you do it? I knew that Photoshop has another way of scripting (in addition to the object model), the Action Manager. I made a mental note to pursue this course, and promptly got distracted by other work.

In the comments section of the earlier post, Jeremy Knudsen kindly posted a pointer to an exchange from the (excellent) PS-Scripts forum, in which (excellent) Photoshop scripter xbytor described a way to work with text ranges in Photoshop. xbytor’s (excellent) xtools Photoshop scripting package for ExtendScript looked like it might solve the problem. I considered asking xbytor for permission to port the package to ActionScript, but decided to try solving the problem myself. There’s a lot of code in the xTools package, and I was looking for a lighter-weight solution.

This led me back to Photoshop, the Action Manager, and the Script Listener plug-in.

You can find the example project here.

Continue reading…

Watching the Detections

Most of the time, Creative Suite extension panels will need to know something about the state of their host application. If the extension, for example, displays a pop-up menu containing a list of the layers in the current document, the extension will need to know when the document closes, or when a new document opens. When the extension detects that the current document has changed, it can do whatever it needs to do to repopulate the menu.

While you could monitor the state of the application using polling—a function in a timing loop that checks the state of the application every so often—it’s much better to use event listeners. Event listeners are triggered whenever a particular event takes place, and run a function that responds to that event in some way. The only trick is that the application you’re interested in working with has to provide some sort of notification that something has happened that’s relevant to your extension. As you’ll see, that’s not always as straightforward as it sounds.

Because CS extensions are built on top of CSXS (Adobe’s Creative Suite Extensible Services framework), they can make use of CSXS “standardized” events.

Event Name Event Triggers:
documentAfterActivate When you activate the document.
documentAfterDeactivate When you deactivate the document
 (i.e., when you bring another document to the front).
applicationBeforeQuit When you quit the application.
applicationActivate When you activate the application.
documentAfterSave Immediately after you save the document.
 

 

Not all Creative Suite applications support the full range of CSXS “standardized” events, but the applications I want to work with—Illustrator, InDesign, and Photoshop—all support the events I’m most interested in. These applications also support other events—later in this post, I’ll show you how to create event listeners for those application-specific events.

We’ll also use two other CSXS events: StateChangeEvent.WINDOW_OPEN and StateChangeEvent.WINDOW_SHOW. These events are not part of the ”standardized” CSXS events—they apply to the state of the panel window itself. For more on general CSXS events, refer to the “com.adobe.csxs.events” section of the CSXS Library API Reference.

To test our event listeners, we’ll get and display the layers in the current document, and we’ll update the list of layers every time a document changes. I’m thinking that this is something that many CS extension developers will want to do.

You can find the project at:

DocumentWatcher
Continue reading…

Entering and Formatting Text

In my previous posts, I’ve shown how to draw objects in Illustrator, InDesign, and Photoshop. The idea was to create generic functions that “wrap” the application-specific code. Each function takes a set of coordinate locations, and uses those coordinates to draw a path. You don’t need to know the details of the application objects properties, and methods needed to draw the path—just send an array to the function, and the function will take care of drawing the path. The resulting paths will be as close to identical as we can make them, given the differences between the applications.

In this blog post, I’ll try to do the same thing for text. I’ll introduce a set of functions for entering text and doing some minor typesetting tasks in Illustrator, InDesign, and Photoshop. Send the function a string of text, a location (as a coordinate pair), a point size, and a font name, and the application-specific code in each “flavor” of the function will take care of creating and formatting the text. Again, I’ll try to have all three applications produce the same result.

While we’re at it, I’ll show how to get a list of fonts from the application and display the font names in a a ComboBox control in the example plug-in. Think of it as a bonus.

The example extension will create a sample document and position the text at the center of the document, but you can use the example makeText functions to draw text wherever you want.

You can find the example project for this post here:

text

Update: This project is now available via Import>Adobe Creative Suite Extension Builder>Remote Creative Suite SDK examples.

Continue reading…

Drawing: Assumptions, Mistakes, and Solutions

My most recent blog post on drawing paths in Illustrator, InDesign, and Photoshop (here) was an interesting exercise for me. In the process of writing the drawing routines, I made several mistakes, found that things I assumed to be true were, in fact, false.

I’ve solved the various problems and have created a workaround or two. I thought it might be useful for other CS Extension developers if I documented the problems and solutions. This way, you can learn from my mistakes. I make lots of mistakes, so it would be nice if we could get some use out of them.

In this article, I’ll show solutions for some of the problems I left unresolved in the previous post. For the most part, they weren’t critical to the point of the post, but it’s nice to tie up the loose ends. I’ve posted an updated version of the project here (this contains all of the code changes discussed in this post):

drawing

Update: This project is now available via Import>Adobe Creative Suite Extension Builder>Remote Creative Suite SDK examples.

My Point of View

First, let me admit to a bias: In my opinion, everything an application can do should be scriptable. Everything. I think InDesign has the best scripting support of the three applications, because its coverage is the most complete. This isn’t to say that it’s perfect, just that it’s a lot closer to my ideal. This means that I tend to approach the other applications with an InDesign bias.

Next, I’m coming to CS Extensions from the world of ExtendScript. My instinct is to develop and debug using the ExtendScript Toolkit (ESTK), then port to ActionScript. I think that this approach is probably shared by quite a few CS Extension developers.

Continue reading…

Drawing Paths: The Basics

In my previous blog post, I presented a fairly complete extension panel for InDesign. This time, I’d like to step back a bit and talk about the process of developing an extension for three Creative Suite applications: Illustrator, InDesign, and Photoshop. We’ll be doing something pretty basic–drawing the same shape in all three applications. While we’re at it, we’ll create a framework we can use to draw any valid shape­. This framework will simplify and standardize the process of drawing a shape, and will work for almost any extension that needs to draw shapes.

In this example, we’ll create a generic extension that can run in any of the above applications, and we’ll keep our application specific code isolated from the overall workings of the extension.

It’s All in the (Application-Specific) Details

The trickiest part of this extension, in fact, is the application-specific code. Illustrator, InDesign, and Photoshop can all draw paths, but each of the applications has a slightly different way of performing the task. In all three applications, you can draw paths using the Pen tool, and the resulting shapes, from a scripting point of view, are made up of paths, which are, in turn, made up of path points. The names and the details of the scripting objects differ a bit between products. In Illustrator and Photoshop, for example, the basic drawing object is a pathItem; in InDesign, it’s a pageItem.

Next, the applications have different ways of dealing with measurement. We’ll need to use measurement values to specify horizontal and vertical coordinates if we’re going to position new path points in a document. In InDesign and Photoshop, you can change measurement units at any time; Illustrator, by contrast, always uses points when it’s being driven by a script. In this example, we’ll be using points, but, for your own scripts, you’ll need to convert measurement values to points before sending them to Illustrator.

In InDesign and Photoshop, path point coordinates are specified relative to the ruler zero point; in Illustrator, they’re specified relative to the lower-left corner of the artboard. Since the default location of the ruler zero point is the upper-left corner of the document in all three applications, this means that the paths in Illustrator will be upside down relative to the paths in the other programs, but we don’t need to worry about that right now.

Finally, Illustrator and InDesign have a number of “shortcuts” for drawing paths with specifc arrangements of points–rectangles, ellipses, regular polygons, etc. We’ll ignore those features in favor of a “one size fits all” drawing routine.

In this tutorial, I’ll present support routines that provide a consistent approach to drawing paths in these applications. The idea is to create a generic drawing function that you can use to build new creative effects (ornamental borders for certificates, for example) or wire into your new data driven graphics feature.

You can download the project here (note that this isn’t really a “finished” extension, it’s just a container for the drawing routines):

drawing
Continue reading…

Drag and Drop in a Creative Suite Extension

One of the great benefits of working with the Flash/AIR environment, inside the Creative Suite, is how easy it makes tasks which would be significant challenges in C++. The geolocation sample is one example of this, but another is drag and drop.

This is something with a lot of potential benefit for developers, but (due to some limitations with the current environment) needs to be addressed in a specific way. To achieve this, we use the Flash NativeDragManager, triggered on a mouseDown listener added to our component like so:

<mx:FileSystemTree
id="fileSystemTree"
width="80%"
height="80%"
mouseDown="onFSTreeMouseDown(event)"
/>

We can then implement this listener to begin the drag:

public function handlePureFlashFileDragStart(event:Event):void
{
var clip:Clipboard = new Clipboard();
clip.setData(ClipboardFormats.FILE_LIST_FORMAT, event.currentTarget.selectedItems);

var allowedActions:NativeDragOptions = new NativeDragOptions();
allowedActions.allowLink = false;

NativeDragManager.doDrag(event.currentTarget as InteractiveObject, clip);
}

Here, we have the option of what kind of data we load onto the clipboard (in this case it is a collection of files), and also, if we so desire, we can add an Image object which would be used as the thumbnail for transfer.

If you’d like to see this in action, we’ve created a project which allows files to be dragged from a filesystem tree view into InDesign. It also allows text to be dragged from InDesign to a box in the extension, and back, using the same mechanisms. You can find that here.

For more information on Flash native drag and drop, you might like to look at the tutorial on the Adobe Developer Connection and the livedocs for the NativeDragManager.

Integrating Adobe Creative Suite CS5 With Other Systems via Adobe LiveCycle Data Services

As part of Adobe Creative Suite Developer Summit, May 3rd – 7th, 2010, there was a session entitled Integrating Creative Suite with Other Systems. The main intent of the session was to describe how the Flex/AIR platform can be used in conjunction with Adobe Creative Suite Extension Builder and Creative Suite ActionScript wrapper libraries, to make integrating Creative Suite CS5 with other systems- such as distributed, dynamic, enterprise data- relatively straightforward.

The session also aimed to show how quickly you could build support for collaboration within Creative Suite CS5, with Adobe LiveCycle Data Services (LCDS) on the backend; for instance, showing how to build a chat client as a CS5 extension, which could be used within multiple Creative Suite CS5 applications in a handful of lines of code, with LiveCycle Data Services on the backend. To find out more about the mechanics of doing this, read the “Integrating Adobe Creative Suite CS5 with backend distributed data via Adobe LiveCycle Data Services and Adobe Creative Suite Extension Builder” on Adobe Cookbooks.

We gave a quick demo as part of the developer summit keynote, showing a CS5 extension called BasicAmfConnector that was written in two or three days. This shows how easy it can be to keep multiple desktop clients in sync and also how easy it can be to produce Creative Suite CS5 publications based on remote, dynamic data with LiveCycle Data Services on the backend. A re-recording of the demo is shown below.

 

Localizing Adobe Creative Suite 5 Extensions

If you are developing extensions for Creative Suite CS5, you might want to adapt your software to your audience based on their language or specific region. The Creative Suite host applications have been localised to many languages and now you can also localise your extensions so your users will be able to interact with them in their native or preferred language.
Adding multiple locale support doesn’t have to increase your engineering effort. This cookbook recipe explains you how you can localise not only your extension user interface but also the extension configuration.
There is also a sample that puts in practice the steps explained in the cookbook recipe. This image below shows how the same extension can be localised to different languages and also how we can change it’s configuration based on specific locales. The same sample extension is running in an English version of Illustrator, a Japanese version of Flash Pro and a Spanish version of Photoshop.
localised_extension.jpg
If you are using Extension Builder, you can download the “Localised” sample by selecting:
File > Import > Other > Adobe Creative Suite Extension Builder > Remote Creative Suite SDK Samples > Localised

Geolocation inside the Creative Suite

As part of the Creative Suite Developer Summit we’ve been showing off some sample code that illustrates just how easy certain workflows become when you move into Flash. One of these, that was shown at the session on Connecting the Creative Suite to Web Services (go here to watch), illustrates how you can connect up the Creative Suite to Google Maps and Flickr.

This sample shows an extension built to run in Photoshop, InDesign and Bridge CS5 (and could easily be extended to any product in the Suite). It connects to Google Maps to show location information, and Flickr to show relevant images – with the data used to power those searches customised based on the application the extension runs in. So, in Photoshop this will check the geolocation of the current image (extracted via XMP) and show the images taken nearby. In InDesign it will instead take the location from the machine’s IP address and search based on keywords using the user’s last sentence. Bridge provides a combination of both, where location comes from the XMP and the keywords come from the image tags.

The best part of this is how cheap integration is with these external systems. Google Maps Flex SDK, for example, requires a single MXML entry to create a map, with an additional call into that object being enough to change the positioning of the map;

<maps:Map xmlns:maps=”com.google.maps.*”
    id=”map” width=”263″ height=”229″
    url=”http://code.google.com/apis/maps/”
    key=”SUPER_SECRET_API_KEY”
    x=”30″ y=”10″/>

this.map.setCenter(location,15, MapType.NORMAL_MAP_TYPE);

For Flickr there are plenty of SDK options available, including one for ActionScript, but for the purposes of this I’ve chosen to roll my own calls. This uses a network communications library provided with Extension Builder, which lets us use the minimal amount of code to make a quick call across the network to retrieve the relevant data;

var request:HttpRequest = new HttpRequest(HttpRequest.GET, “http://api.flickr.com”, “/services/rest/”);
request.setParam(“method”, “flickr.photos.search”);
request.setParam(“api_key”, FLICKR_KEY);
request.setParam(“lat”, latLon.lat());
request.setParam(“lon”, latLon.lng());
request.perform(function(response:HttpResponse):void
{
    if (response.succeeded() || response.get_Status() == 0)
    {
        if (response.isParseable())
        {
            // success: XML or JSON response
            var xml:XML = new XML(response.getBodyText());
            for each (var photo:XML in xml.photos.photo) {
            }
        }
    }
});

If you’d like to try this out, you can grab the Extension Builder project here. You’ll need to drop the Google Maps Flex SWC (available here) into the libs folder, and enter your own API key for both the Maps service and Flickr.

I’ve also made it available as a ZXP (here), and as a zip for Bridge (here) the contents of which should be unzipped into your Bridge CS5 user startup scripts folder.