TrophyCustomer's Canvas is honored with a 2020 InterTech Technology Award! Learn more 

Imposition Tutorial

The Customer's Canvas SDK allows you to implement template-based imposition.

Here, you will need at least two input templates:

  • A product design
  • An imposition template

Since Customer's Canvas renders preview images of only 72 DPI, you may want to provide two different imposition templates for low-res previews (72 DPI) and hi-res print files (for example, 300 DPI). You can also prepare more imposition templates for different paper sizes or imposition patterns.

As a result, you get a print-ready PDF file with the imposed sheet.

This solution uses the following packages of the SDK:

  • The Design Editor - to personalize product designs.
  • The Dynamic Image - to render preview images and high-resolution outputs.
  • The UI Framework - to make these tools work together and implement the workflow.

In this tutorial, you will learn how to prepare input templates and configure the solution.

Preparing Templates

To obtain an imposed sheet, we will use a Dynamic Image feature to replace the content of PSD layers when rendering PSD files.

Product Designs

You can use both PSD and IDML files as product designs. To create a design file, you can refer to the guide to creating product templates.

Imposition Templates

You can only use PSD files as imposition templates. Let's look at how you can create these templates for printing business cards.

First, you must ask your print service provider about the required bleed zone. Depending on this, you will define the size of the product design and arrange placeholders on the imposition template.

In our case, the product size is 3.5 x 2 inches. Including the bleed zone, we will create a product design of 3.75 x 2.25 inches. The size of the print file will be A6 (4.1 x 5.8 inches) and will allow you to print two business cards.

To create a template for previews: click New, click Web, select Inches, set 4.1 for the Width, set 5.8 for Height, and click Create.

To create a template for print files: click New, click Print, select the A6 document preset, and click Create.

Then, you can create these templates in the same way:

  1. By using the Rectangle tool, draw two rectangles of 3.75" x 2.25", one above the other.
  2. Define the same names for these rectangles, for example, bc.
  3. Group the layers with these rectangles and name it sheet.
  4. Use the Line tool to draw crop marks at 3.5" x 2" and then merge these shapes into a layer.
  5. Save this file.

The result may look as follows:

Imposition templates in Adobe Photoshop

These rectangles represent placeholders for the product. Later, you will learn how to configure the Dynamic Image to replace them with the rendered image.

Setting up the Application

Copying the Templates

Let's assume that you have deployed the Customer's Canvas SDK as follows:

SDK Folders

By default, the Design Editor and the Dynamic Image use different folders for their templates. You may want to change the default location. In this case, change the following parameters:

  • For the Design Editor:
    1. Open cc-<version>\Configuration\AppSettings.config.
    2. Change the value of DesignFolder.
  • For the Dynamic Image:
    1. Open DI-<version>\AppSettings.config.
    2. Change the value of TemplatePath.

If you leave the default paths unchanged, then place your templates into the following folders:

  • In \assets\designs create the imposition subfolder and place your business card design there.
  • In \assets\templates create the imposition subfolder and place your imposition templates there.

Configuring the UI Framework

You don't need to install the UI Framework locally; you can use its scripts hosted on Azure or jsDelivr CDN, for example:

https://www.jsdelivr.com/package/npm/@aurigma/ui-framework

However, you must configure steps and widgets that implement the user interface of your application. For more details, refer to the widget reference. Now, let's configure widgets for the imposition. This configuration represent a JSON file with the following objects.

1. Variables

Usually, configs contain a block of used variables.

"vars": {
	"templateName": "bc",
	"rootFolder": "imposition/",
	"diApiUrl": "https://localhost:44084/"
}

Here, we defined:

  • templateName - the name of our template (without the extension).
  • rootFolder - the subfolder where we placed the templates.
  • diApiUrl - the URL where you run the Dynamic Image service.

2. Steps

You also need to define steps - the screens of your application.

"steps": [
	{
		"name": "Design",
		"mainPanel": {
			"name": "cc"
		}
	},
	{
		"name": "Preview",
		"mainPanel": {
			"name": "approve-panel"
		},
		"onActivate": [
			"{{#function $['cc'].getHiResImages(800,800) }}"
		]
	}
]

In the first step, we display the Design Editor, which will be configured in the cc widget. The result may look as follows:

The Design tab.

In the second step, we display preview images and allow the user to approve them. The result may look as follows:

The Preview tab.

When the second step is activated, the application calls the getHiResImages method to render the product design.

3. The Design Editor Widget

In the first step, we display the Design Editor. To initialize the editor, you can only define a product definition. Here, the designFile will refer to the assets\designs\imposition\bc.psd when using the default path settings.

"widgets": [
	{
		"name": "cc",
		"type": "design-editor",
		"params": {
			"initial": {
				"productDefinition": {
					"surfaces": [{
						"printAreas": [{
							"designFile": "{{ vars.rootFolder + vars.templateName }}"
						}]
					}]
				},
				"editorConfig": {
					"initialMode": "SimpleOnly"
				}
			}
		}
	}
	...

The SimpleOnly edit mode only allows you to change the values of available design elements. In editorConfig, you can use all the parameters that you define in clientConfig.json. For more details about this widget, you can refer to the widget reference.

4. The Preview Request

To render preview images, we use the POST api/rendering/preview endpoint. In the request payload, we pass a low-resolution imposition template. Here, the template will refer to assets\templates\imposition\preview-bc-2up.psd when using the default path settings.

The data object defines how to personalize the template when rendering. To specify what layers should be personalized, we pass sheet\\bc, where sheet is the group name and bc is the name of the layer in this group. Since we gave the same names to all placeholders, this object will be enough to change all of them at once. In the following example, we paste preview images into these placeholders by using links from the proofImageUrls array. Note that links in this array were generated by the getHiResImages method when the user activated the preview step.

{
	"name": "image-request",
	"type": "ajax",
	"params": {
		"url": "{{ vars.diApiUrl + 'api/rendering/preview' }}",
		"method": "POST",
		"autoCompile": true,
		"responseType": "json",
		"lock": "preview",
		"request": {
			"template": "{{ vars.rootFolder + 'preview-bc-2up' }}",
			"format": "jpg",
			"size": {
				"height": 800
			},
			"data": {
				"sheet\\bc": {
					"type": "image",
					"image": "{{ $['cc'].proofImageUrls[0][0] }}"
				}
			}
		}
	}
}

If you have prepared several imposition templates, then you can configure the option widget and allow your users to select one of the imposition types. For an example, you can refer to the imposition demo.

5. The Request to Render Print Files

To render print files, we use the POST api/rendering/hires endpoint. In the request payload, we pass a high-resolution imposition template. Here, the template will refer to the assets\templates\imposition\bc-2up.psd when using the default path settings.

The data object defines how to personalize the template when rendering. In the sheet\\bc object name, sheet is the group name and bc is the name of the layer in this group. Since we gave the same names to all placeholders in the imposition template, this object will be enough to change all of them at once. In this example, we paste the hi-res images obtained by getHiResImages into these placeholders.

{
	"name": "pdf-request",
	"type": "ajax",
	"params": {
		"url": "{{ vars.diApiUrl + 'api/rendering/hires' }}",
		"method": "POST",
		"autoCompile": true,
		"responseType": "json",
		"request": {
			"template": "{{ vars.rootFolder + 'bc-2up' }}",
			"format": "jpg",
			"size": {
				"height": 800
			},
			"data": {
				"sheet\\bc": {
					"type": "image",
					"image": "{{ $['cc'].hiResUrls[0] }}",
					"dpix": 300,
					"dpiY": 300
				}
			}
		}
	}
}

6. Approval of Preview Images

In the second step, we display two images: the design preview and the imposition preview. On the approval panel, we also need to display controls to get the user's confirmation. We can configure this panel as a group of three widgets:

  • A preview slider with images.
  • A checkbox to approve the design.
  • A button to submit an order.
{
	"name": "approve-panel",
	"type": "group",
	"params": {
	"tabs": [
		{
		"widgets": [
			{
			"name": "preview",
			"type": "slider",
			"params": {
				"style": {
				"--au-widget-height": "400px"
				},
				"direction": "tile",
				"rows": 1,
				"columns": 2,
				"images": [
				{
					"title": "Design",
					"url": "{{ $['cc'].proofImageUrls[0][0] }}"
				},
				{
					"title": "Imposition",
					"url": "{{ $['image-request'].response }}"
				}
				]
			}
			}
		]
		},
		{
		"widgets": [
			{
			"name": "finish-panel",
			"type": "group",
			"params": {
				"type": "noncollapsible",
				"tabs": [
				{
					"widgets": [
					{
						"name": "agree-checkbox",
						"type": "checkbox",
						"params": {
						"prompt": "I have reviewed and approve my design.",
						"value": false
						}
					}
					]
				},
				{
					"widgets": [
					{
						"type": "button",
						"name": "real-finish-button",
						"params": {
						"enabled": "{{$['agree-checkbox']._}}",
						"text": "Finish",
						"classStyle": "primary",
						"onClick": [
							"{{ #function cart.submit() }}"
						]
						}
					}
					]
				}
				]
			}
			}
		]
		}
	]
	}
}

In the slider widget, we display two preview images:

  • In the design mode, rendered by the Design Editor {{ $['cc'].proofImageUrls[0][0] }}.
  • In the imposed mode, rendered by the Dynamic Image API {{ $['image-request'].response }}.

7. Order Submission

When the user clicks the Finish button, the order widget passes links to preview images and print files to the e-commerce system and outputs them in the console.

{
	"name": "order",
	"type": "order",
	"params": {
		"images": "{{ [$['cc'].proofImageUrls] }}",
		"downloadUrls": "{{ $['cc'].hiResUrls.concat([$['pdf-request'].response]) }}",
		"data": {
			"stateId": "{{ $['cc'].stateId }}"
		}
	}
}

For more details about the Order widget, you can refer to the widget reference.

Running the Application

After you have created the config, you can apply the UI Framework in your application.

First, you must specify a DIV element, which will be a container for the editor.

<div id="editor-container" class="editor-container">
</div>

Now, let's look at how you can define input parameters for the UI Framework editor, load the editor, and obtain the resulting links to print files.

<script type="module">
	// Import moduleLoader from jsDelivr CDN.
	// This script allows you to dynamically import ES6 modules and loads the editor to the page.
	const uiFrameworkBaseUrl = "https://cdn.jsdelivr.net/npm/@aurigma/ui-framework@4.9.8";
	import moduleLoader from "https://cdn.jsdelivr.net/npm/@aurigma/ui-framework@4.9.8/dist/moduleLoader.js";
	document.addEventListener('DOMContentLoaded', async () => {

		// Define an e-commerce product.
		// See https://customerscanvas.com/support/ui-framework/using-default-driver.md
		// for more details.
		const product = {
			id: 0,
			sku: "PRODUCT-001",
			title: "My Product",
			description: "This is a test product.",
			options: [],
			price: 1,
			attributes: []
		};

		// Load the config you just created.
		const config = await moduleLoader.loadJson("./imposition.json");


		// Initialize an e-commerce driver.
		let driver = (await moduleLoader.dynamicImport("ecommerceDriver", `${uiFrameworkBaseUrl}/dist/drivers/default-driver.js`)).ecommerceDriver;
		let editor = (await moduleLoader.dynamicImportDefault("editor", `${uiFrameworkBaseUrl}/dist/editor.js`)).editor;

		let ecommerce = await driver.init(product, editor, config, /* settings */ {customersCanvasBaseUrl: ""}, /* restore data */ null, /*quantity*/ 1, /* user info*/ {id: 'test-user'});

		// Load the editor into its container.
		ecommerce.products.current.renderEditor(document.getElementById("editor-container"));

		// Receive data from the editor after the user finishes editing it.
		ecommerce.cart.onSubmitted.subscribe(function (data) {
			console.log("submitted");
			data.lineItems.forEach(function (order) {
				// Output the array with links to the print files.
				console.log(order.downloadUrls);
			})
		});
	
	});
	
</script>

In the driver's settings, you must specify customersCanvasBaseUrl - a link to your Design Editor instance. For example, "https://cc.mysite.com/". If you load the editor to a page on the same host, you can leave an empty string.