Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Photoshop script for adding rectangle measurements to your mockups
/*
Photoshop script for adding measurements to your mockups,
based on Pixel Measure v0.04 by Nikolaj Selvik (https://code.google.com/p/pixelmeasure/)
To install: Place in /Applications/Adobe Photoshop CC/Presets/Scripts/ and restart Photoshop.
To use: Draw a rectangle marquee and invoke from File > Scripts > Pixel Measure - Asset.
Tips:
- Set your foreground color to something visible (e.g., red).
- Set your Measurement Scale (Image > Analysis > Set Measurement Scale).
For iOS retina, you might use the unit "pt" and set the pixel length to 2 (2px = 1pt @2x).
- Set your DPI scale (Image > Image Size). In the retina example, if 72 is your normal dpi,
use 144 (72 x 2 = 144).
- Set your ruler to use points.
- Set a keyboard shortcut to invoke the script.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// temporarily change ruler units to points
var originalUnit = preferences.rulerUnits;
preferences.rulerUnits = Units.POINTS;
// set up vars
var assetName, docRef, ratio, docRes;
var isTextLabel = false;
app.displayDialogs = DialogModes.NO;
if(validateState())
{
app.activeDocument.suspendHistory("Create " + (isTextLabel ? "text spec" : "asset measurement"), "createMeasure();");
}
function validateState()
{
if (app.documents.length === 0)
{
alert("No document open");
return false;
} else {
docRef = app.activeDocument;
ratio = docRef.measurementScale.pixelLength;
docRes = docRef.resolution;
}
if(!hasSelection(app.activeDocument))
{
alert("Please make a selection to measure");
return false;
}
assetName = prompt("Asset Name\r(prefix with \"t \" for text styles; leave blank for dimensions only)", "");
if ((assetName) === null) {
return false;
}
if (assetName.indexOf("t ") === 0) {
isTextLabel = true;
assetName = assetName.substr(2);
}
if (docRes / ratio !== 72) {
if (!confirm("Measurement Scale does not match document resolution\rContinue anyway?")) {
return false;
}
}
try {
var colorTest = app.foregroundColor;
} catch(e) {
alert("Invalid foreground color\r" + e);
return false;
}
return true;
}
function createMeasure()
{
var selRef = docRef.selection;
var mainLayerSet;
// set density-independent units (dp, pt)
var measureUnits = docRef.measurementScale.logicalUnits;
if(measureUnits == "pixels")
{
measureUnits = "px";
}
else if(measureUnits == "points")
{
measureUnits = "pt";
}
// =======================================================
// Create "Pixel Measures" LayerSet if it doesn't already exist
// =======================================================
try
{
mainLayerSet = docRef.layerSets.getByName("Pixel Measures");
}
catch(error)
{
mainLayerSet = docRef.layerSets.add();
mainLayerSet.name = "Pixel Measures";
}
// =======================================================
// Create Measurement LayerSet
// =======================================================
var layerSetRef = mainLayerSet.layerSets.add();
var boxLayerRef = layerSetRef.artLayers.add();
// get average color
var x1 = selRef.bounds[0].value;
var y1 = selRef.bounds[1].value;
var x2 = selRef.bounds[2].value;
var y2 = selRef.bounds[3].value;
selRef.copy(true);
var chanRef = docRef.channels.add();
chanRef.name = "TMP";
chanRef.kind = ChannelType.SELECTEDAREA;
selRef.store(docRef.channels.getByName("TMP"), SelectionType.EXTEND);
docRef.paste();
var tmpLayer = docRef.activeLayer;
selRef.load(docRef.channels.getByName("TMP"));
tmpLayer.applyAverage();
chanRef.remove();
selRef.deselect();
var width = x2 - x1;
var height = y2 - y1;
var tmpSampler = docRef.colorSamplers.add(Array(x1 + width/2, y1 + height/2));
var bgColor = new SolidColor();
bgColor = tmpSampler.color;
tmpSampler.remove();
//~ app.foregroundColor = bgColor;
// =======================================================
// Draw Lines
// =======================================================
drawBox(x1,y1,x2,y2);
// =======================================================
// Draw Text
// =======================================================
var textLayerRef = layerSetRef.artLayers.add();
textLayerRef.kind = LayerKind.TEXT;
var textItemRef = textLayerRef.textItem;
var textColor = new SolidColor();
textItemRef.size = new UnitValue(5, "pt");
// temporary workaround for text size bug
if (textItemRef.size.as("pt") != 5) {
changeTextSize(5*ratio);
}
textItemRef.font = "Monaco";
textItemRef.antiAliasMethod = AntiAlias.NONE;
textItemRef.contents = assetName + (isTextLabel ? "" : (assetName ? "\r" : "") + width + "\u00D7" + height + " " + measureUnits);
textItemRef.justification = Justification.CENTER;
var textWidth = textLayerRef.bounds[2].value - textLayerRef.bounds[0].value;
var textHeight = textLayerRef.bounds[3].value - textLayerRef.bounds[1].value;
if(textWidth < width && textHeight < height)
{
textItemRef.position = Array(x1 + width/2, y1 + (height/2) + (assetName && !isTextLabel ? -2/ratio : 4/ratio));
var fgColorValue = (app.foregroundColor.rgb.red + app.foregroundColor.rgb.green + app.foregroundColor.rgb.blue) / 3;
if(isTextLabel || fgColorValue < 128)
{
textColor.rgb.hexValue = "ffffff";
}
else
{
textColor.rgb.hexValue = "000000";
}
}
else
{
// test position of text and find good offsets
var textX = x1 + width/2;
if (textX - textWidth/2 < 0) {
textX = 1;
textItemRef.justification = Justification.LEFT;
} else if (textX + textWidth/2 > docRef.width.value) {
textX = docRef.width.value - 1;
textItemRef.justification = Justification.RIGHT;
}
var textY = y2 + 15/ratio;
if (textY + 2 > docRef.height.value) {
textY = y1 - (assetName && !isTextLabel ? 16/ratio : 4/ratio);
}
textItemRef.position = Array(textX, textY);
if (isTextLabel) {
textColor.rgb.hexValue = "00aeef";
} else {
textColor = app.foregroundColor;
}
}
if (assetName) {
layerSetRef.name = assetName;
} else {
layerSetRef.name = textItemRef.contents;
}
textItemRef.color = textColor;
// =======================================================
// Reset
// =======================================================
app.preferences.rulerUnits = originalUnit;
}
function drawBox(x1,y1,x2,y2)
{
// Factor in ruler offset, from http://forums.adobe.com/message/2866222#2866222
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
var xOffSet = desc.getInteger(stringIDToTypeID('rulerOriginH')) / 65536;
var yOffSet = desc.getInteger(stringIDToTypeID('rulerOriginV')) / 65536;
x1 -= xOffSet/ratio;
x2 -= xOffSet/ratio;
y1 -= yOffSet/ratio;
y2 -= yOffSet/ratio;
var pointArray = [];
var pointA = new PathPointInfo();
pointA.kind = PointKind.CORNERPOINT;
pointA.anchor = Array(x1, y1);
pointA.leftDirection = pointA.anchor;
pointA.rightDirection = pointA.anchor;
pointArray.push(pointA);
var pointB = new PathPointInfo();
pointB.kind = PointKind.CORNERPOINT;
pointB.anchor = Array(x2, y1);
pointB.leftDirection = pointB.anchor;
pointB.rightDirection = pointB.anchor;
pointArray.push(pointB);
var pointC = new PathPointInfo();
pointC.kind = PointKind.CORNERPOINT;
pointC.anchor = Array(x2, y2);
pointC.leftDirection = pointC.anchor;
pointC.rightDirection = pointC.anchor;
pointArray.push(pointC);
var pointD = new PathPointInfo();
pointD.kind = PointKind.CORNERPOINT;
pointD.anchor = Array(x1, y2);
pointD.leftDirection = pointD.anchor;
pointD.rightDirection = pointD.anchor;
pointArray.push(pointD);
var box = new SubPathInfo();
box.operation = ShapeOperation.SHAPEXOR;
box.closed = true;
box.entireSubPath = pointArray;
var boxSubPathArray = [];
boxSubPathArray.push(box);
var fillColor;
if (isTextLabel) {
fillColor = new SolidColor();
fillColor.rgb.hexValue = "00aeef";
} else {
fillColor = app.foregroundColor;
}
var boxPath = app.activeDocument.pathItems.add("TempPath", boxSubPathArray);
boxPath.fillPath(fillColor, ColorBlendMode.NORMAL, 60, 0, false, false);
app.activeDocument.pathItems.removeAll();
}
function hasSelection(doc)
{
var res = false;
var as = doc.activeHistoryState;
doc.selection.deselect();
if (as != doc.activeHistoryState)
{
res = true;
doc.activeHistoryState = as;
}
return res;
}
// Temporary fix for the textItem.size bug: https://forums.adobe.com/message/6804450
// Adapted from https://forums.adobe.com/message/6814050#6814050
function changeTextSize(newSize) {
var idsetd = charIDToTypeID( "setd" );
var desc23 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref6 = new ActionReference();
var idPrpr = charIDToTypeID( "Prpr" );
var idTxtS = charIDToTypeID( "TxtS" );
ref6.putProperty( idPrpr, idTxtS );
var idTxLr = charIDToTypeID( "TxLr" );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref6.putEnumerated( idTxLr, idOrdn, idTrgt );
desc23.putReference( idnull, ref6 );
var idT = charIDToTypeID( "T " );
var desc24 = new ActionDescriptor();
var idtextOverrideFeatureName = stringIDToTypeID( "textOverrideFeatureName" );
desc24.putInteger( idtextOverrideFeatureName, 808465458 );
var idtypeStyleOperationType = stringIDToTypeID( "typeStyleOperationType" );
desc24.putInteger( idtypeStyleOperationType, 3 );
var idSz = charIDToTypeID( "Sz " );
var idPxl = charIDToTypeID( "#Pxl" );
desc24.putUnitDouble( idSz, idPxl, newSize );
var idTxtS = charIDToTypeID( "TxtS" );
desc23.putObject( idT, idTxtS, desc24 );
executeAction( idsetd, desc23, DialogModes.NO );
}
@mycort

This comment has been minimized.

Copy link

commented Sep 12, 2013

I have a even better and more robust version of this script. Supports multiple measurements at one time, creates arrow points, and creates the font info of a selected text. email me at mycort@yahoo.com if you want it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.