//
#target photoshop
//
// Gallery Wrap Script
//
// Martin Renters
// 3 Elsley Court
// Dundas, Ontario
// Canada L9H 6Z2
//
// email: [email protected]
// web: www.teckelworks.com
//
// Copyright (c) 2016 Martin Renters, All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY MARTIN RENTERS ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL MARTIN RENTERS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Edit the following for the default amount of gallery wrap in inches
var GWconfig={
defaultUnits: "inch", // Can be "inch" or "cm"
wrapSize: 0.125, // Size of wrap area in default Units
trimSize: 0, // Trim area around wrap in default Units
lineWidth: 0, // Line width for trim lines
innerBox: true, // Draw inner box (limits of wrap)
outerBox: true, // Draw outer box (limits of trim area)
foldLines: true, // Draw fold lines
mirroredEdges: true, // Mirror image in wrap area
addLogo: false, // Add a logo to the trim area
logoName: null, // Logo name (fill in by dialog)
position: 'Bottom (Upside Down)' // Logo position
};
// No further changes should be required to any of the code below
var gallery_wrap_version = "2.0.3";
/*
<javascriptresource>
<name>Mirror Edges</name>
<type>automate</type>
<about>This script automates the process of creating a gallery wrap</about>
<enableinfo>true</enableinfo>
</javascriptresource>
*/
//////////////////////////////////////////////////////////////////////////
//
// Draw Line
//
//////////////////////////////////////////////////////////////////////////
function drawLine(start, stop, width) {
if (width <= 0) return;
var desc = new ActionDescriptor();
var lineDesc = new ActionDescriptor();
var startDesc = new ActionDescriptor();
var endDesc = new ActionDescriptor();
startDesc.putUnitDouble(charIDToTypeID('Hrzn'), charIDToTypeID('#Pxl'),
start[0]);
startDesc.putUnitDouble(charIDToTypeID('Vrtc'), charIDToTypeID('#Pxl'),
start[1]);
endDesc.putUnitDouble(charIDToTypeID('Hrzn'), charIDToTypeID('#Pxl'),
stop[0]);
endDesc.putUnitDouble(charIDToTypeID('Vrtc'), charIDToTypeID('#Pxl'),
stop[1]);
lineDesc.putObject(charIDToTypeID('Strt'), charIDToTypeID('Pnt '),
startDesc);
lineDesc.putObject(charIDToTypeID('End '), charIDToTypeID('Pnt '), endDesc);
lineDesc.putUnitDouble(charIDToTypeID('Wdth'), charIDToTypeID('#Pxl'),
width);
desc.putObject(charIDToTypeID('Shp '), charIDToTypeID('Ln '), lineDesc);
desc.putBoolean(charIDToTypeID('AntA'), true);
executeAction(charIDToTypeID('Draw'), desc, DialogModes.NO);
}
//////////////////////////////////////////////////////////////////////////
//
// Check for valid value for Wrap/Trim Size and Line Weight
//
//////////////////////////////////////////////////////////////////////////
function check_value(name, obj)
{
var v = parseFloat(obj.text);
if (isNaN(v) || (v < 0)) {
alert(name + " is not a valid value");
return 1;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
//
// Preferences dialog
//
//////////////////////////////////////////////////////////////////////////
function PreferencesDialog()
{
// Create the dialog box
var d = new Window('dialog', 'Enter Parameters');
d.alignChildren = ['fill', 'top'];
var header = d.add('group', undefined, '', { orientation: 'row'});
var msg = header.add('statictext{justify: "center", \
properties: {multiline: true}}');
msg.text = 'Gallery Wrap Script\nVersion ' + gallery_wrap_version + '\n' +
'Martin Renters, Copyright \u00A92016\n' + 'www.teckelworks.com';
msg.preferredSize.width = 300;
///////////////////////////////////////////////////////
// Wrap Size
///////////////////////////////////////////////////////
wrap = d.add('panel', undefined, 'Wrap Parameters', {
orientation: 'column'
});
wrap.alignChildren = 'left';
wrap.margins = 20;
wrap.indent = 20;
var wrap_size = wrap.add('group', undefined, '', {
orientation: 'row'
});
wrap_size.s = wrap_size.add('statictext', undefined,
'Wrap Size:');
wrap_size.s.preferredSize.width = 80;
wrap_size.e = wrap_size.add('edittext', undefined,
GWconfig.wrapSize);
wrap_size.e.characters = 5;
wrap_size.e.justify = 'right';
wrap_size.u = wrap_size.add('dropdownlist');
var mirrored = wrap.add('group', undefined, '', {
orientation: 'row'
});
mirrored.e = mirrored.add('checkbox', undefined,
'Mirrored Edges');
mirrored.e.value = GWconfig.mirroredEdges;
///////////////////////////////////////////////////////
// Trim Size
///////////////////////////////////////////////////////
var trim = d.add('panel', undefined, 'Trim Parameters', {
orientation: 'column'
});
trim.alignChildren = 'left';
trim.margins = 20;
trim.indent = 20;
// Trim Size
var trim_size = trim.add('group', undefined, '', {
orientation: 'row'
});
trim_size.s = trim_size.add('statictext', undefined,
'Trim Size:');
trim_size.s.preferredSize.width = 80;
trim_size.e = trim_size.add('edittext', undefined,
GWconfig.trimSize);
trim_size.e.characters = 5;
trim_size.e.justify = 'right';
trim_size.u = trim_size.add('dropdownlist');
// Line Width
var line_width = trim.add('group', undefined, '', {
orientation: 'row'
});
line_width.s = line_width.add('statictext', undefined,
'Line Weight:');
line_width.s.preferredSize.width = 80;
line_width.e = line_width.add('edittext', undefined,
GWconfig.lineWidth);
line_width.e.characters = 5;
line_width.e.justify = 'right';
var innerBox = trim.add('checkbox', undefined, 'Draw Inner Bounding Box');
innerBox.value = GWconfig.innerBox;
var outerBox = trim.add('checkbox', undefined, 'Draw Outer Bounding Box');
outerBox.value = GWconfig.outerBox;
var foldLines = trim.add('checkbox', undefined, 'Draw Folding Lines');
foldLines.value = GWconfig.foldLines;
// Logo
var addlogo = trim.add('checkbox', undefined, 'Add Logo');
addlogo.onClick = function() {
logo.enabled = this.value;
pos.enabled = this.value;
};
var logo = trim.add('group', undefined, '', {
orientation: 'row',
enabled: false
});
logo.s = logo.add('statictext', undefined,
'Document:');
logo.s.preferredSize.width = 100;
logo.s.justify = 'right';
logo.d = logo.add('dropdownlist');
// Position
var pos = trim.add('group', undefined, '', {
orientation: 'row',
enabled: false
});
pos.s = pos.add('statictext', undefined,
'Position:');
pos.s.preferredSize.width = 100;
pos.s.justify = 'right';
pos.d = pos.add('dropdownlist');
// Buttons
var buttons = d.add('group', undefined, '', {
orientation: 'row'
});
buttons.alignment='center';
buttons.okBtn = buttons.add('button', undefined, 'OK');
buttons.okBtn.onClick = function() {
if (check_value("Wrap Size", wrap_size.e)) return;
if (check_value("Trim Size", trim_size.e)) return;
if (check_value("Line Weight", line_width.e)) return;
buttons.okBtn.close(1);
};
buttons.cancelBtn = buttons.add('button', undefined, 'Cancel');
var documents = app.documents;
var i;
var listitem;
addlogo.enabled = false;
logo.enabled = this.value;
pos.enabled = this.value;
// Populate logos if other documents open
for (i=0; i<app.documents.length; i++) {
if (app.documents[i] == docRef) continue;
listitem = logo.d.add("item", app.documents[i].name);
if (listitem.index == 0) {
logo.d.selection = listitem;
addlogo.enabled = true;
addlogo.value = GWconfig.addLogo;
if (addlogo.value) {
logo.enabled = true;
pos.enabled = true;
}
}
}
if (!logo.enabled) {
logo.d.selection = logo.d.add("item", "No other open documents");
}
// Populate logo positioning
var positions = ['Bottom', 'Bottom (Upside Down)', 'All Sides'];
for (i=0; i<positions.length; i++) {
listitem = pos.d.add("item", positions[i]);
if (GWconfig.position == positions[i])
pos.d.selection = listitem;
}
// Populate wrap/trim units
var units = ['inch', 'cm'];
for (i=0; i<units.length; i++) {
listitem = wrap_size.u.add("item", units[i]);
if (GWconfig.defaultUnits == units[i])
wrap_size.u.selection = listitem;
listitem = trim_size.u.add("item", units[i]);
if (GWconfig.defaultUnits == units[i])
trim_size.u.selection = listitem;
}
// Center dialog and show it to user
d.center();
var code = d.show();
// Fetch the user's preferences
GWconfig.wrapSize = parseFloat(wrap_size.e.text);
GWconfig.mirroredEdges = mirrored.e.value;
GWconfig.trimSize = parseFloat(trim_size.e.text);
GWconfig.addLogo = addlogo.value;
GWconfig.lineWidth = line_width.e.text;
GWconfig.innerBox = innerBox.value;
GWconfig.outerBox = outerBox.value;
GWconfig.foldLines = foldLines.value;
// Logo name
listitem = logo.d.selection;
if (listitem) GWconfig.logoName = listitem.text;
// Logo position
listitem = pos.d.selection;
if (listitem) GWconfig.position = listitem.text;
// Convert to cm if necessary
listitem = wrap_size.u.selection;
if (listitem && listitem.text == "cm")
GWconfig.wrapSize = GWconfig.wrapSize / 2.54;
listitem = trim_size.u.selection;
if (listitem && listitem.text == "cm")
GWconfig.trimSize = GWconfig.trimSize / 2.54;
// Convert wrap from inches to pixels
GWconfig.wrapSize = Math.round(GWconfig.wrapSize * docRef.resolution);
GWconfig.trimSize = Math.round(GWconfig.trimSize * docRef.resolution);
return code;
}
//////////////////////////////////////////////////////////////////////////
//
// drawLogos
//
//////////////////////////////////////////////////////////////////////////
function drawLogos(config)
{
var layer;
var trimSize = config.trimSize;
// Can't draw logo if there is no trim size
if (trimSize <= 0) return;
if (config.addLogo == false) return;
if (config.logoName == null) return;
var logo = app.documents.getByName(config.logoName);
app.activeDocument = logo;
// Duplicate logo and get reference to new one
logo = logo.duplicate("Logo-Gallery-Wrap");
logo.flatten();
var logo_h = logo.height.value;
var logo_w = logo.width.value;
// Figure out how much to resize the image
var scale = trimSize*0.8/logo_h;
logo.resizeImage(scale*logo_w, scale*logo_h, docRef.Resolution);
logo_h = logo.height.value;
logo_w = logo.width.value;
// Copy to LAB so that we can paste without color space mismatches
logo.convertProfile("Lab Color", Intent.RELATIVECOLORIMETRIC);
logo.selection.selectAll();
logo.selection.copy();
app.activeDocument = docRef;
// Logo on bottom
docRef.selection.selectAll();
layer = docRef.paste();
if (config.position != "Bottom")
layer.rotate(180, AnchorPosition.MIDDLECENTER);
layer.translate(0, (docRef.height.value - trimSize)/2);
layer.merge();
if (config.position == "All Sides") {
// Logo on top
docRef.selection.selectAll();
layer = docRef.paste();
layer.rotate(0, AnchorPosition.MIDDLECENTER);
layer.translate(0, -(docRef.height.value - trimSize)/2);
layer.merge();
// Logo on Left
docRef.selection.selectAll();
layer = docRef.paste();
layer.rotate(-90, AnchorPosition.MIDDLECENTER);
layer.translate(-(docRef.width - trimSize)/2, 0);
layer.merge();
// Logo on right
docRef.selection.selectAll();
layer = docRef.paste();
layer.rotate(90, AnchorPosition.MIDDLECENTER);
layer.translate((docRef.width - trimSize)/2, 0);
layer.merge();
}
logo.close(SaveOptions.DONOTSAVECHANGES);
// Delete Reference
logo = null;
}
//////////////////////////////////////////////////////////////////////////
//
// drawTrimLines
//
//////////////////////////////////////////////////////////////////////////
function drawTrimLines(config)
{
var wrapSize = config.wrapSize;
var trimSize = config.trimSize;
var lineWidth = config.lineWidth;
// If no trimSize, then nothing to do
if (trimSize <= 0) return;
var black = new SolidColor();
black.rgb.hexValue = "000000";
app.foregroundColor = black;
size = wrapSize + trimSize;
height = docRef.height;
width = docRef.width;
// Fold Lines
if (config.foldLines) {
// Top Left
drawLine([0,size], [trimSize,size], lineWidth);
drawLine([size,0], [size,trimSize], lineWidth);
// Top Right
drawLine([width.value,size], [width.value-trimSize,size], lineWidth);
drawLine([width.value-size,0], [width.value-size,trimSize], lineWidth);
// Bottom Left
drawLine([0,height.value-size],
[trimSize,height.value-size], lineWidth);
drawLine([size,height.value],
[size,height.value-trimSize], lineWidth);
// Bottom Right
drawLine([width.value,height.value-size],
[width.value-trimSize,height.value-size], lineWidth);
drawLine([width.value-size,height.value],
[width.value-size,height.value-trimSize], lineWidth);
}
// Inner box
if (config.innerBox) {
drawLine([trimSize, trimSize],
[width.value-trimSize, trimSize], lineWidth);
drawLine([width.value-trimSize, trimSize],
[width.value-trimSize, height.value-trimSize], lineWidth);
drawLine([width.value-trimSize, height.value-trimSize],
[trimSize, height.value-trimSize], lineWidth);
drawLine([trimSize, height.value-trimSize],
[trimSize, trimSize], lineWidth);
}
// Outer Box
if (config.outerBox) {
drawLine([0, 0], [width.value, 0], lineWidth);
drawLine([width.value, 0], [width.value, height.value], lineWidth);
drawLine([width.value, height.value], [0, height.value], lineWidth);
drawLine([0, height.value], [0, 0], lineWidth);
}
}
//////////////////////////////////////////////////////////////////////////
//
// selectWrapArea - Selects the gallery wrap area
//
//////////////////////////////////////////////////////////////////////////
function selectWrapArea(config)
{
var wrapSize = config.wrapSize;
var trimSize = config.trimSize;
if (wrapSize <= 0) return;
var height = docRef.height;
var width = docRef.width;
var selRegion;
var size;
app.activeDocument = docRef;
// Select image canvas image area
size = trimSize;
selRegion = [ [size, size],
[width-size, size],
[width-size, height-size],
[size, height-size]
];
docRef.selection.select(selRegion, SelectionType.REPLACE, 0);
size = wrapSize + trimSize;
selRegion = [ [size, size],
[width-size, size],
[width-size, height-size],
[size, height-size]
];
docRef.selection.select(selRegion, SelectionType.DIMINISH, 0);
}
//////////////////////////////////////////////////////////////////////////
//
// getMode
//
//////////////////////////////////////////////////////////////////////////
function getMode(doc)
{
switch(doc.mode) {
case DocumentMode.BITMAP: mode = NewDocumentMode.BITMAP; break;
case DocumentMode.CMYK: mode = NewDocumentMode.CMYK; break;
case DocumentMode.GRAYSCALE: mode = NewDocumentMode.GRAYSCALE; break;
case DocumentMode.LAB: mode = NewDocumentMode.LAB; break;
case DocumentMode.RGB: mode = NewDocumentMode.RGB; break;
default:
alert("This document mode isn't supported by this script. Converting document to RGB mode");
doc.changeMode(ChangeMode.RGB);
mode = NewDocumentMode.RGB;
break;
}
return mode;
}
//////////////////////////////////////////////////////////////////////////
//
// Gallery Wrap Procedure
//
//////////////////////////////////////////////////////////////////////////
function GalleryWrap(config)
{
var wrapSize = config.wrapSize;
var trimSize = config.trimSize;
var height = docRef.height+((trimSize+wrapSize)*2);
var width = docRef.width+((trimSize+wrapSize)*2);
var layer;
var mode = getMode(docRef);;
docRef.flatten();
var white = new SolidColor();
white.rgb.hexValue = "FFFFFF";
app.backgroundColor = white;
docRef.resizeCanvas(width, height, AnchorPosition.MIDDLECENTER);
// If we don't want to mirror, we're done
if (!config.mirroredEdges) return;
// If we don't have a wrap size, we're done
if (wrapSize <= 0) return;
var i;
var selRegion;
var copyRef;
var areas = [
{ // Left
src_selection: [
[trimSize+wrapSize, trimSize],
[trimSize+wrapSize*2, trimSize],
[trimSize+wrapSize*2, height-trimSize],
[trimSize+wrapSize, height-trimSize]
],
dst_selection: [
[trimSize, trimSize],
[trimSize+wrapSize, trimSize],
[trimSize+wrapSize, height-trimSize],
[trimSize, height-trimSize]
],
w: wrapSize,
h: height-trimSize*2
},
{ // Right
src_selection: [
[width-(trimSize+wrapSize), trimSize],
[width-(trimSize+wrapSize*2), trimSize],
[width-(trimSize+wrapSize*2), height-trimSize],
[width-(trimSize+wrapSize), height-trimSize]
],
dst_selection: [
[width-trimSize, trimSize],
[width-(trimSize+wrapSize), trimSize],
[width-(trimSize+wrapSize), height-trimSize],
[width-trimSize, height-trimSize]
],
w: wrapSize,
h: height-trimSize*2
},
{ // Top
src_selection: [
[trimSize, trimSize+wrapSize],
[trimSize, trimSize+wrapSize*2],
[width-trimSize, trimSize+wrapSize*2],
[width-trimSize, trimSize+wrapSize]
],
dst_selection: [
[trimSize, trimSize],
[trimSize, trimSize+wrapSize],
[width-trimSize, trimSize+wrapSize],
[width-trimSize, trimSize]
],
w: width-trimSize*2,
h: wrapSize
},
{ // Bottom
src_selection: [
[trimSize, height-(trimSize+wrapSize)],
[trimSize, height-(trimSize+wrapSize*2)],
[width-trimSize, height-(trimSize+wrapSize*2)],
[width-trimSize, height-(trimSize+wrapSize)]
],
dst_selection: [
[trimSize, height-trimSize],
[trimSize, height-(trimSize+wrapSize)],
[width-trimSize, height-(trimSize+wrapSize)],
[width-trimSize, height-trimSize]
],
w: width-trimSize*2,
h: wrapSize
}
];
for (i=0; i<4; i++) {
docRef.selection.select(areas[i].src_selection,
SelectionType.REPLACE, 0);
docRef.selection.copy();
if (docRef.colorProfileType.toString() != ColorProfile.NONE) {
copyRef = app.documents.add(areas[i].w, areas[i].h,
docRef.resolution, "Mirror",
mode, DocumentFill.WHITE, docRef.pixelAspectRatio,
docRef.bitsPerChannel, docRef.colorProfileName);
} else {
copyRef = app.documents.add(areas[i].w, areas[i].h,
docRef.resolution, "Mirror",
mode, DocumentFill.WHITE, docRef.pixelAspectRatio,
docRef.bitsPerChannel);
}
copyRef.paste();
if (i < 2)
copyRef.flipCanvas(Direction.HORIZONTAL);
else
copyRef.flipCanvas(Direction.VERTICAL);
copyRef.selection.selectAll();
copyRef.selection.copy();
copyRef.close(SaveOptions.DONOTSAVECHANGES);
app.activeDocument = docRef;
docRef.selection.select(areas[i].dst_selection,
SelectionType.REPLACE, 0);
layer = docRef.paste(true);
layer.merge();
}
copyRef = null;
}
//////////////////////////////////////////////////////////////////////////
//
// Main Procedure
//
//////////////////////////////////////////////////////////////////////////
var docRef;
var originalRulerUnits = app.preferences.rulerUnits;
preferences.rulerUnits = Units.PIXELS;
if (app.documents.length == 0) {
alert("No documents open. Terminating.");
} else {
docRef = app.activeDocument;
app.bringToFront();
if (docRef && PreferencesDialog() == 1) {
docRef.suspendHistory("Gallery Wrap",
" GalleryWrap(GWconfig); \
if (GWconfig.trimSize) { \
drawTrimLines(GWconfig); \
drawLogos(GWconfig); \
} \
selectWrapArea(GWconfig);");
}
}
// Release references
docRef = null;
// Restore original ruler unit setting
app.preferences.rulerUnits = originalRulerUnits;