New online demos available.  

PsdWebService - The Dynamic Image

PsdWebService (we also sometimes call it Dynamic Image) is a Web API app which allows generating images dynamically from a PSD file where we can replace/modify some layers based on our request.

Why you may need it? For example, you build an ecommerce system and need to generate a lot of product images for different its variants (like Color, Size, etc). Or, you need to personalize designs by replacing texts, colors, images. Or, you need to insert a design on a product mockup.

How it works?

The overall idea is the following. You create a multilayered PSD file. For example, it may contain a photo as a Photo layer, text string as a Message layer and rectangle under this text as a Text Background layer. Now you want to replace a photo, text and colors of a text and its background.

You send a HTTP request to PsdWebService where you specify a name of a PSD file and a list of "commands" what to do with each of these layers, e.g. insert a URL http://example.com/image.jpg to a Photo layer, set Message layer to Hello World and change its text to yellow, while the underlaying rectangle should become blue. PsdWebService performs all these operations and returns a URL to the resulting image or a PDF file.

There are a lot of different commands - in addition to the image replacement, text and font settings modifications, and shape object color changes, you can also insert images to Smart Objects, toggle elements visibility, or even generate tables! See a full list of features below.

Features

You can use the following image personalization features:

  • Hiding design elements.
  • Replacing images (both local images and by direct URLs).
  • Replacing text and text style (font, size, and color).
  • Inserting images into a smart object.
  • Inserting a PSD file into a smart object, and defining custom parameters for this PSD file.
  • Selecting a layer from a group with predefined parameters.

The Dynamic Image is implemented as a web service providing basic methods for rendering product images:

  • POST api/preview renders a proof image of a PSD template to display it in a browser (like JPEG or PNG).
  • POST api/hires renders a print-ready high-resolution output (PDF files).

Also, this web service provides additional methods to work with an image library and fonts on your server.

Running the Dynamic Image Service

This distribution package contains the psdWebService.zip file.

To run the service:

  1. Unzip this archive to a new IIS folder.
  2. In IIS Manager, create an application pool with the NetworkService identity. If you prefer using other values, be ready to configure permissions for the PsdWebService data folders.
  3. Create an Application (if you want to put it to a folder of your main site) or Add a website to the Sites list associated with this folder (if you want to deploy a service on a separate domain). Set the AppPool you have created for this application/site.
  4. In AppSettings.config, specify your folders for the cache, assets, and resulting outputs or leave the default paths.
  5. Copy your license file (Aurigma.GraphicsMill.lic) to the \bin\ folder.

Note: A user account, under which the PsdWebService runs in IIS, must have Read and Write permissions to the App_Data and Logs folders.

The Rendering of PSD Templates

PSD templates you create for PsdWebService may use such features of Photoshop as:

  • Image, text, and shape layers.
  • Grouped layers.
  • Text and paragraph settings.
  • Stroke and shadow text effects.
  • Smart objects with applied transforms.
  • Embedded color profiles.
  • Blend modes.
  • Rendering PSD files as is or changing layers and fields.
  • Combining alternative layers into groups and making one of them visible.

To render templates, you should pass such parameters as a name of your PSD template and personalization data to the preview and hires controllers. Additionally, preview takes a configuration of the resulting files in the request payload:

{
    "template": "schedule.psd",
    "size": {
        "maxWidth": 600,
        "maxHeight": 800
    },
    "format": "jpg",
    "data": {
         ...
    }
}

Here, the data object is responsible for the personalization. As property names (keys), it uses layer names in the PSD file. Layers included in layer groups are also supported. In this case, specify property names as "GroupName\\LayerName". The values are objects defining the content and style of design elements to be replaced and rendered on this template. For example:

{
    "data": {
        "Background": {
            "type": "image",
            "image": "long\\rose.jpg"
         },
        "Header\\Line 1": {
            "type": "text",
            "text": "Washington Capitals"
        },
        "Header\\Line 2": {
            "type": "text",
            "text": "vs. Anaheim Ducks", 
            "color": "#ff0000",
            "size": 18,
            "postScriptName": "Pacifico-Regular"
        }
    }
}

This data tells to replace an image in the Background layer with rose.jpg from the long image subfolder. Also, in the Header layer group, it replaces text and style of the Line 1 and Line 2 text elements. Later we will describe all available parameters that you can customize.

As a result, you get a URL that links to high-resolution outputs. The first time you render a template, this service generates a hi-res image, puts this output to the cache, and gives you a link to the cached image. However, on the next requests, you just get the link to the cached image.

Using this Web Service with Customer's Canvas Templates

Sometimes you may want to use PsdWebService with the PSD files created for the Aurigma Customer's Canvas online image editor. The main peculiarity of Customer's Canvas PSD templates are so-called "markers" - special shortcodes in the layer names, which tell the editor what a user can do with a particular layer. For example, Layer 1<LC> locks this layer, etc.

Markers don't make any sense when you render a PSD file without the editor. Also, specifying all markers in the layer name would be quite annoying. That's why PsdWebService just ignores markers. In other words, if a layer named Layer 1<LC><VNP>, you should refer it as Layer 1.

Image library manipulation

When passing images to PsdWebService, you can either provide a URL to download an image or specify a path relatively a root image folder inside PsdWebService. For example, in the previous example, we referenced to the rose.jpg image placed in the long subfolder.

It is convenient to use it when you have some limited set of predefined images (e.g. standard backgrounds, etc) - instead of having to download files from some remote storage, you can just use the local copies.

By default, the root folder is located in the App_Data/assets/images folder, but you may overrride it in AppSettings.config file (the PsdPersonalizatorImagePath param).

PsdWebServer exposes a Web API to manage these images:

Fonts manipulations

When using text strings in a PSD file, you may run into problems with fonts. For example, a designer who creates a PSD template in Photoshop may have a particular font installed in his/her system, but it may be missing on the server.

Installing fonts

To add a font to PsdWebService, all you need is to put it to a special folder in the app. By default, it is located at App_Data/assets/fonts, but you may override it in AppSettings.config (PsdPersonalizatorFontPath param).

PsdWebService supports TrueType and OpenType fonts.

After you add a font, you need to restart AppPool in IIS for the PsdWebService to have it to recognize it. It may work on a dev machine or if you do it seldomly, however, if you are running PsdWebService in the production, you may prefer avoiding it.

In this case, to rescan the fonts folder, just use this API method:

Specifying a font name

Unlike other software, when you specify a font name in PsdWebService, you should use so-called PostScript Name instead of a Font Family. In other words, if you want to use, say, a Roboto font, you need to specify Roboto-Regular (not just Roboto). Or ArialMT instead of Arial.

You have to do this, because it allows you specifying not just a font name, but also a font style (including some non-standard ones, like UtlraThin, etc).

You may find it a bit challenging to determine a PostScript name of a font, especially, if you are on Windows. To do it, you have to download some font editing software, like FontForge and open the font file in it.

Alternatively, you may use this endpoint to read a list of fonts available in PsdWebService:

Among with other data, it contains PostScript Names. So you can use this endpoint just as a "cheat sheet" or create a dropdown list for fonts in your user interface.

AppSettings.config

PsdWebServer application has the following params which can be configured in the AppSettings.config file:

<add key="PsdPersonalizatorFontPath" value=".\App_Data\assets\fonts" /> - the folder with fonts
<add key="PsdPersonalizatorImagePath" value=".\App_Data\assets\images" /> - the folder with images
<add key="PsdPersonalizatorFontCachePath" value=".\App_Data\FontCache" /> - the font cache folder
<add key="PsdPersonalizatorPsdPath" value=".\App_Data\assets\templates" /> - the folder with PSD templates
<add key="PsdPersonalizatorCachePath" value=".\App_Data\Cache" /> - the product cahce folder
<add key="PdfFilePath" value=".\App_Data\Results\Pdf" /> - the folder with resulting hi-res outputs
<add key="ImageFilePath" value=".\App_Data\Results\Images" /> - the folder with previews
<add key="PreviewResizeInterpolationMode" value="Anisotropic9" /> - the interpolation mode for previews
<add key="AllowUploadImages" value="true"/> - allows for uploading images through the API

These are the default values.

For the complete list of available interpolation modes, you can refer to GraphicsMill documentation.

API Reference

This Rest API contains:

Preview

Renders a PSD template and returns a URL to display the preview in a browser.

URL:api/preview

Method:POST

URL Parameters:

disableCache=[boolean] enables rendering and loading assets every time you make requests. By default, this is false, which means that repeated requests return the link to the already cached image.

Request payload:

{
    "template": "games.psd",
    "data": {
        "Team": {
            "type": "text",
            "text": "Washington Capitals"
        }
    },
    "format": "jpg",
    "size": {
        "maxWidth": 600,
        "maxHeight": 800
    }
}

template, data, and format are mandatory parameters. format is either jpg, jpeg, or png.

Success Response:

Code: 200 Ok
Content: "http://localhost:84/api/download/1f78f1d8-cf23-45a0-ac47-ef57774cd435.jpg/"

Error Responses:

Code: 500 Server Error
Content: Template is required

Code: 500 Server Error
Content: Error! Font required for the table was not found.

Request Example:

var data = {
    template: "games.psd",
    format: "jpg" 
};

$.ajax({
    url: "http://localhost:84/api/preview",
    type: "POST",
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    data: JSON.stringify(data),
    success: function(d) { 
        console.log(d);
    },
    error: function(d) { 
        console.error(d.responseText);
    }
});

Hires

Renders a PSD template and returns a URL that links to the print-ready PDF file.

URL:api/hires

Method:POST

URL Parameters:

disableCache=[boolean] enables rendering and loading assets every time you make requests. By default, this is false, which means that repeated requests return the link to the already cached image.

Request payload:

{
    "template": "games.psd",
    "data": {
        "Team": {
            "type": "text",
            "text": "Washington Capitals"
        }
    }
}

template is a mandatory parameter.

Success Response:

Code: 200 Ok
Content: "http://localhost:84/api/download/d8040e7e-53ed-406e-aef6-15e41b39a5c2.pdf/"

Error Responses:

Code: 500 Server Error
Content: Template is required

Code: 500 Server Error
Content: Error! Unsupported color format.

Request Example:

var change = {
    Team: {
        type: "text",
        text: "Washington Capitals"
    }
};

var payload = {
    template: "games.psd",
    data: change
};

$.ajax({
    url: "http://localhost:84/api/hires",
    type: "POST",
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    data: JSON.stringify(payload),
    success: function(d) { 
        console.log(d);
    },
    error: function(d) { 
        console.error(d.responseText);
    }
});

Images

Gets a list of images placed in PsdPersonalizatorImagePath and available in this API. Every element in this list contains a title, a preview URL, and a name that you can use for the personalization by using the api/preview and api/hires methods.

URL:api/resources/images

Method:GET

URL Parameters:

  • subfolder=[alphanumeric] specifies a folder from where it obtains the image list. By default, this is an empty string, which means that this method looks for images in the PsdPersonalizatorImagePath folder.
  • showSubfolders=[boolean] allows you to list images in subfolders. By default, this is false, which means that this method looks for images in the current folder only.

Success Response:

{
    "total": 2,
    "items": [
        {
            "title": "SkyBlue",
            "name": "themes\\SkyBlue.jpg",
            "previewUrl": "http://localhost:84/api/resources/images/preview?imageName=themes%5cSkyBlue.jpg"
        },
        {
            "title": "Contrast",
            "name": "themes\\Contrast.jpg",
            "previewUrl": "http://localhost:84/api/resources/images/preview?imageName=themes%5cContrast.jpg"
        }
    ]
}

Error Responses:

Code: 500 Server Error
Content: Error! Folder does not exist.

Request Example:

http://localhost:84/api/resources/images?showSubfolders=true

Image Upload

Uploads an image to the PsdPersonalizatorImagePath folder.

URL:api/resources/images

Method:POST

URL Parameters:

  • destination=[alphanumeric] specifies a destination subfolder. If this is a new subfolder, it will be created. By default, this is an empty string, which means that images will be uploaded to the PsdPersonalizatorImagePath folder.
  • overwrite=[boolean] enables overwriting files if this file name already exists. By default, this is false, which means that the name of the uploaded file is changed by adding _1, _2, etc. to it.

Request Payload

You can pass a number of files as multipart/form-data in this POST request.

Success Response:

[
    {
        "title": "Logo_4",
        "name": "images\Logo_4.pdf",
        "previewUrl": "http://localhost:84/api/resources/images/preview?file=images%5cLogo_4.pdf"
    }
]

Error Responses:

Code: 500 Server Error
Content: Error! Uploaded file has empty content.

Request Example:

<input type="file" class="inputfile" name="logo" id="logo" placeholder="Company Logo" onchange="uploadLogo(event)">
...
function uploadLogo(e) {
    var formData = new FormData();
    var file = $('#logo')[0].files[0]
    formData.append('file', file);
    if (file) {
        $.ajax({
            url: 'https://localhost:84/api/resources/images?destination=uploaded',
            type: 'POST',
            data: formData,
            processData: false,
            contentType: false,
            success: function(d) { 
                console.log(d[0].previewUrl);
            },
            error: function(d) { 
                console.error(d.responseText);
            }
       });
   }

}

Image Preview

Returns an image preview. You can use this method to obtain the content of IMG elements as follows:

<img src="http://example.com/api/resources/images/preview?imageName=rose.jpg&height=400" />

URL:api/resources/images/preview

Method:GET

URL Parameters:

  • imageName=[string] the image file name. This is a mandatory parameter.
  • width=[integer] the image width. The default value is 400 pixels.
  • height=[integer] the image height. The default value is 400 pixels.
  • disableCache=[boolean] enables loading assets every time you make requests. By default, this is false, which means that repeated requests return the link to the already cached image.

Success Response:

Code: 200 Ok
Content-Type: image/jpeg

Error Responses:

Code: 500 Server Error
Content: Error! Incorrect params: width or height is less than zero.

Request Example:

http://localhost:84/api/resources/images/preview?imageName=rose.jpg

Fonts

Gets a list of fonts placed in PsdPersonalizatorFontPath and available in this API. Every element in this list contains a full name, a font style, a font family, and a postScript name that you can use for the personalization by using the api/preview and api/hires methods.

URL:api/resources/fonts

Method:GET

Success Response:

[
    {
        "fullName": "Arial",
        "style": "Regular",
        "family": "Arial",
        "postscriptName": "ArialMT"
    },
    {
        "fullName": "Arial Black",
        "style": "Black",
        "family": "Arial",
        "postscriptName": "Arial-Black"
    }
]

Request Example:

http://localhost:84/api/resources/fonts

Reload Fonts

Rescans the PsdPersonalizatorFontPath folder. After you have changed fonts in this folder, you should reload the font list to apply changes to the web service. Note, if you have changed the default font folder in AppSettings.config, then you need to recycle the application pool.

URL:api/resources/fonts/reload

Method:POST

Success Response:

Code: 200 Ok

Error Response:

Code: 500 Server Error

Request Example:

$.ajax({
    url: "http://localhost:84/api/resources/fonts/reload",
    type: "POST",
    success: function(d) { 
        console.log(d);
    },
    error: function(d) { 
        console.error(d.responseText);
    }
});

How to Personalize Design Elements in Your Template

As we discussed earlier, when sending a request to preview or hires, we pass a data object containing commands for personalized layers. Such a command represents an object that has a type and other settings specifying how to personalize that layer.

Earlier, we gave an example of commands corresponding to the image and text layer types. Now, let us list available commands and their settings. We use the following types:

  • text - to personalize text layers. This type is only applicable to text.
  • shape - to change colors of vector graphics. This type is only applicable to shapes.
  • image - to replace images in templates. You can apply this type to image layers and smart objects.
  • switch - to allow your users to select an element design from a number of options. In Photoshop, you can combine these options in a group, and then specify the name of the layer that you want to enable in the request. You can also personalize such a layer by passing the commands. This type is only applicable to layer groups.
  • psd - to insert another PSD into a smart object. This can be useful to generate mockup previews. You can only apply this type to smart objects.
  • table - to generate a table based on a prototype in a smart object. You can apply this type to smart objects that contain a table prototype.

When configuring an element, first specify the type property.

You can specify colors in the following formats:

  • HEX - (#ffffff)
  • RGB - rgb(255, 0, 0)
  • RGBA - rgba(255, 0, 0, 0.6)

Such ordinary elements as text, images, and shapes can specify its visibility as follows: visible ? (bool) = true

Here, we use the following notation to define the configuration parameters:

paramName ? (typeName)

  1. paramName - the parameter name.
  2. ? - marks the parameter as optional.
  3. (typeName) - the parameter type is in parentheses.
  4. =true - the default value if any.

Now, let us describe what properties you can change to personalize templates.

Text

  • visible ? (bool) = true - enables this text element.
  • text ? (string) - the content of this text element.
  • fauxItalic ? (bool) - enables the faux italic style for this text.
  • fauxBold ? (bool) - enables the faux bold style for this text.
  • color ? (string) - the text color.
  • postScriptName ? (string) - the PostScriptName of the text font.
  • size ? (float) - the font size.
{
    "data": {
        "Team": {
            "type": "text",
            "text": "Washington Capitals",
            "color": "#ff0000",
            "postScriptName": "ArialMT",
            "size": "20"
        }
    }
}

Shape

  • visible ? (bool) = true - enables this shape.
  • color ? (string) - the shape color.
{
    "data": {
        "Rectangle": {
            "type": "shape",
            "color": "rgb(200, 200, 0)"
        }
    }
}

Image

  • visible ? (bool) = true - enables this image.
  • image ? (string) - the link to the image source, either a local link relative to PsdPersonalizatorImagePath or a direct URL.
  • resizeMode (string) - the image resize mode, either fill or fit.
  • dpiX ? (int) = 300 - X-coordinate resolution, in dots per inch. This parameter applies only to PDF images.
  • dpiY ? (int) = 300 - Y-coordinate resolution, in dots per inch. This parameter applies only to PDF images.
  • transform ? (object) - an object defining transforms.
  1. rotate ? (number) = 0 - the image rotation angle, in degrees. You can only rotate PDF images at 90, 180, and 270 degrees.
  2. flip ? (string) = none - the flip mode, either none, horizontal, vertical, or both.
{
    "data": {
        "Logo": {
            "type": "image",
            "Image": "http://example.com/capitals.png",
            "resizeMode": "fit",
            "dpiX": 150,
            "dpiY": 150,
            "transform": {
                "flip": "horizontal"
            }
        }
    }
}

Switch

  • select (string) - the name of a visible layer in this group, the rest layers are hidden.
  • data ? (object) - the configuration of the visible layer.
{
    "data": {
        "text_group": {
            "type": "switch",
            "select": "city",
            "data": {
                "type": "text",
                "text": "Carlington",
                "color": "#000000"
            }
        }
    }
}

Psd

  • content (string) - the path to PSD file relative to PsdPersonalizatorPsdPath.
  • data ? (object) - the configuration of design elements.
{
    "data": {
        "Team 2\\Away Table": {
            "type": "psd",
            "content": "home-away-games.psd",
            "data": {
                "City": {
                    "type": "text",
                    "text": "Chicago"
                },
                "Week": {
                    "type": "text",
                    "text": "18"
                }
            }
        }
    }
}

Table

  • data (array<object>) - an array of rows. Rows contain key-value pairs representing table cells. The keys in the data array are layer names, whereas values are the cell's content - either text or links to images.
  • settings (object) - an object defining the table style.
  1. color (array<string>) - an array of text colors.
  2. backgroundColor (array<string>) - an array of background colors.
  3. fontSize (string) - the text font size, either a number in points or auto that means the Dynamic Image automatically fits the font size.
  4. horizontalMargin (int) - the margin between columns (gutter), in pixels.
{
    "data": {
        "Team1": {
            "type": "table",
            "data": [
                { "Col1": "Sep 10", "Col2": "Atlanta", "Col3": "12:00p" },
                { "Col1": "Sep 17", "Col2": "@ Tampa Bay", "Col3": "12:00p" },
                { "Col1": "Sep 24", "Col2": "Pittsburgh", "Col3": "12:00p" },
                { "Col1": "Sep 28", "Col2": "@ Green Bay", "Col3": "7:25p" }
            ],
            "settings": {
                "color": [
                    "#ffffff",
                    "rgb(200, 200, 200)"
                ],
                "backgroundColor": [
                    "rgba(242, 97, 34, 0.7)",
                    "#f26122"
                ],
                "fontSize": "auto",
                "horizontalMargin": "60"
            }
        }
    }
}

Table Prototypes

Prior to working with tables, you need to design a table prototype. In Photoshop, such a prototype represents a smart object containing another PSD file with the table layout.

You can add both text and image layers to a prototype. When the Dynamic Image renders a table, it takes font settings, text alignment, and the position of cells from your prototype. It fills in the table row by row and sets the row height automatically.

Note that you can arrange a number of layers in a table prototype under each other. In this case, you can personalize headers. For example:

Table Prototype

Add this prototype as a smart object to another PSD file:

Table Prototype

To personalize this table, you can run the following sample:

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>The Dynamic Image</title>
    <script type="text/javascript" src="https://code.jquery.com/jquery-2.2.0.js">
    </script>

<script language="javascript">
var render = function() {

var config = {
    "TableProto": {
        "type": "table",
        "data": [
            { "Header Col1": "Description", "Header Col2": "Price" },
            { "Col1": "15 inch wheel", "Col2": "$200" },
            { "Col1": "16 inch wheel", "Col2": "$275" },
            { "Col1": "16 inch wheel", "Col2": "$350"}
        ],
        "settings": {
            "color": ["#ff0000", "#0000ff" ],
            "backgroundColor": ["rgba(255,255,255, 100)", "rgba(200,200,200, 100)" ],
            "fontSize": "auto",
            "horizontalMargin": "10"
        }
    }
};

var data = { template: "template.psd", data: config };

$.ajax({
    url: "http://localhost:84/api/hires",
    type: "POST",
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    data: JSON.stringify(data),
    success: function(d) { 
        console.log(d);
    },
    error: function(d) { 
        console.error(d.responseText);
    }
});
}
</script>
</head>

<body>
    <h3>The Dynamic Image</h3>
    <input type="button" value="Personalize" onclick="render()" />
</body>
</html>