Last active
December 14, 2018 16:31
-
-
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/)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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 ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Does it work with Photoshop CC2015 and 2014