Skip to content

Instantly share code, notes, and snippets.

@yorb
Last active December 14, 2018 16:31
Show Gist options
  • Save yorb/5042960 to your computer and use it in GitHub Desktop.
Save yorb/5042960 to your computer and use it in GitHub Desktop.
Photoshop script for adding measurements to your mockups, based on Pixel Measure v0.04 by Nikolaj Selvik (https://code.google.com/p/pixelmeasure/)
/*
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.
Tips:
- Set your pencil to 1x1 and 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.
*/
var originalUnit = preferences.rulerUnits;
preferences.rulerUnits = Units.POINTS;
var ratio;
app.displayDialogs = DialogModes.NO;
if(validateState())
{
app.activeDocument.suspendHistory("Create 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;
}
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;
ratio = docRef.measurementScale.pixelLength;
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 linesLayerRef = layerSetRef.artLayers.add();
// =======================================================
// Draw Lines
// =======================================================
// 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();
// figure out what color to use
var baseColorValue = (bgColor.rgb.red + bgColor.rgb.green + bgColor.rgb.blue) / 3;
var tmpFgColor = app.foregroundColor;
if(baseColorValue < 192)
{
app.foregroundColor.rgb.hexValue = "ffffff";
}
var horizontal = width > height;
if(horizontal)
{
drawLine(x1,y1,x1,y1+10/ratio);
drawLine(x2-1/ratio,y1,x2-1/ratio,y1+10/ratio);
drawLine(x1,y1+5/ratio,x2-1/ratio,y1+5/ratio);
}
else
{
drawLine(x1,y1,x1+10/ratio,y1);
drawLine(x1,y2-1/ratio,x1+10/ratio,y2-1/ratio);
drawLine(x1+5/ratio,y1,x1+5/ratio,y2-1/ratio);
}
// =======================================================
// Draw Text
// =======================================================
var textLayerRef = layerSetRef.artLayers.add();
textLayerRef.kind = LayerKind.TEXT;
var textItemRef = textLayerRef.textItem;
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;
var textWidth, textHeight, textX, textY;
if (horizontal) {
if (width > 16) {
textItemRef.contents = width + " " + measureUnits;
} else {
textItemRef.contents = width + "\r" + measureUnits;
}
textItemRef.justification = Justification.CENTER;
// test position of text and find good offsets
textWidth = textLayerRef.bounds[2].value - textLayerRef.bounds[0].value;
textHeight = textLayerRef.bounds[3].value - textLayerRef.bounds[1].value;
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;
}
textY = y1 + 21/ratio;
if (textY + 4 > docRef.height.value) {
textY = y1 - (width > 16 ? 6 : 16)/ratio;
}
textItemRef.position = Array(Math.floor(textX), Math.floor(textY));
} else {
textItemRef.contents = height + " " + measureUnits;
// test position of text and find good offsets
textWidth = textLayerRef.bounds[2].value - textLayerRef.bounds[0].value;
textHeight = textLayerRef.bounds[3].value - textLayerRef.bounds[1].value;
textX = x1 + 15/ratio;
if (textX + textWidth > docRef.width.value) {
textX = x1 - 4/ratio;
textItemRef.justification = Justification.RIGHT;
}
textY = y1 + 4/ratio + height/2;
textItemRef.position = Array(Math.floor(textX), Math.floor(textY));
}
layerSetRef.name = (horizontal ? width : height) + " " + measureUnits;
textItemRef.color = app.foregroundColor;
// =======================================================
// Reset
// =======================================================
app.preferences.rulerUnits = originalUnit;
app.foregroundColor = tmpFgColor;
}
function drawLine(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, y2);
pointB.leftDirection = pointB.anchor;
pointB.rightDirection = pointB.anchor;
pointArray.push(pointB);
var line = new SubPathInfo();
line.operation = ShapeOperation.SHAPEXOR;
line.closed = false;
line.entireSubPath = pointArray;
var lineSubPathArray = [];
lineSubPathArray.push(line);
var linePath = app.activeDocument.pathItems.add("TempPath", lineSubPathArray);
linePath.strokePath(ToolType.PENCIL, 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 );
}
@ahsanpervaiz
Copy link

Does it work with Photoshop CC2015 and 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment