Except where otherwise noted, this work is licensed
under: http://creativecommons.org/licenses/by-nc-sa/
3.0/
Uso del API Javascript
para obtener fotos HDTR
Leganés, 11 y 12 de febrero
David Gómez G.
Dr Jeckyll & Mr Hide
Haciendo Fotos
desde los 16 años
Exposiciones
Colectivas e indivudales
Ing. técnico en
Informática de sistemas
Sw Engineer & Trainer
@dgomezg@d_v_g
The HDTR technique
Term coined by Martin Krzywinski
HDTR
High Dynamic
Time Range
@dgomezg @D_v_G
The HDTR Technique
Term coined by Martin KrzywinskiHDTR | High Dynamic
Time Range
http://mkweb.bcgsc.ca/fun/hdtr/
Steps
SHOT
Process
Plan
@dgomezg @D_v_G
The Planning
Spot the place
(Find out if its going to
be crowded at sunset)
Find out
when and where
the sun sets
Check the
weather forecast
(A rainy sunset looks
quite different)
@dgomezg @D_v_G
Do you require a Permit?
@dgomezg @D_v_G
Do you require a Permit?
(Even If they’re useless)
When and Where
the sun sets
PhotoPills
@dgomezg @D_v_G
Golden & Blue Hours
in Photography
@dgomezg @D_v_G
Photographic Shot
Keep the camera steady
for several hours
(a TRIPOD will help)
Set a
NEUTRAL White Balace
Keep a const Depth of
Field (Aperture Priority)
Better if you can shot
Tethered to a Computer
Pick some BEERS & FRIENDS
(but pay attention to the camera)
@dgomezg @D_v_G
TOOLS and Setup
Tethered Shooting
Set Aperture Priority
Set timered shooting
(TIMELAPSE SHOOTING)
@dgomezg @D_v_G
RESULTSRESULTS
@dgomezg @D_v_G
Construction of a
HDTR image
@dgomezg @D_v_G
The Photoshop Process
Described at
http://mkweb.bcgsc.ca/fun/hdtr/?tutorial
Automate the
process
Available AT
http://mkweb.bcgsc.ca/fun/hdtr/?CODE
Martin Krzywinski
Implementation
• Perl BASED
• PROS
• Easy setup &
RUN
• FREE
• No dependencies
(but Perl & libs)
• CONS
• Verbose
blending
config
• No tuning
posibility of
result image
@dgomezg @D_v_G
PS Scripting
alternative
• PROS
• Final image un
PSD format with
layers
• You could
further adjust
the result
• Easy config & run
• CONS
• PS License
required
• Harder to code
@dgomezg @D_v_G
PS scripting languages
@dgomezg @D_v_G
Photoshop JS
• Since PHOTOSHOP CS 1
(experimental support in PS 7.0 via an optional
plugin)
• Cross platform
• New DOM To access most of Photoshop
features and properties
@dgomezg @D_v_G
Photoshop’s DOM
• BUT Still some operations not
available: Gradients, Adjustment
Layers, Layer Effects, polygonal
selections....@dgomezg @D_v_G
Access to the “Hidden”
functionality
• JS Classes from original PS SDK
interface
• ActionDescriptor,
• ActionList
• ActionReference
• Use codes as parameters
@dgomezg @D_v_G
Access to the “Hidden” functionality
ScriptListener plugin
//-------------------------------------------------------------
var V1 = new ActionDescriptor();
var V2 = new ActionDescriptor();
V2.putUnitDouble(charIDToTypeID("Hrzn"),charIDToTypeID("#Pxl"), 345);
V2.putUnitDouble(charIDToTypeID("Vrtc"),charIDToTypeID("#Pxl"), 667);
V1.putObject(charIDToTypeID("From"),charIDToTypeID("Pnt "), V2);
var V3 = new ActionDescriptor();
[...]
Records User’s interaction to JS script
var fillWithGradient = function(startX, startY, endX, endY) {
var V1 = new ActionDescriptor();
var V2 = new ActionDescriptor();
V2.putUnitDouble(
charIDToTypeID("Hrzn"),
charIDToTypeID("#Pxl"),
startX); // start point X
V2.putUnitDouble(
charIDToTypeID("Vrtc"),
charIDToTypeID("#Pxl"),
startY); // start point Y
V1.putObject(
charIDToTypeID("From"),
charIDToTypeID("Pnt "), V2);
var V3 = new ActionDescriptor();
Access to the “Hidden” functionality
Code translation
//-------------------------------------------------------------
var V1 = new ActionDescriptor();
var V2 = new ActionDescriptor();
V2.putUnitDouble(charIDToTypeID("Hrzn"),charIDToTypeID("#Pxl"), 345);
V2.putUnitDouble(charIDToTypeID("Vrtc"),charIDToTypeID("#Pxl"), 667);
V1.putObject(charIDToTypeID("From"),charIDToTypeID("Pnt "), V2);
var V3 = new ActionDescriptor();
[...]
Translating codes
/*
lMID.maskHides = 1214529900;//"HdAl"
lMID.maskRevealsAll = 1383492673;//"RvlA"
lMID.maskReveals = 1383492691;//"Rvls"
lMID.mask = 1299409696;//"Msk "
lMID.at = 1098129440;//"At "
lMID.using = 1433628263;//"Usng"
lMID.userMask = 1433629261;//"UsrM"
lMID.make = 1298866208;//"Mk "
lMID.property = 1349677170;//"Prpr"
...
*/
cTID = function(s) { return app.charIDToTypeID(s); };
sTID = function(s) { return app.stringIDToTypeID(s); };
Photoshop Extended
Script
• SOME Photoshop classes are defined in
an extended and particular way
alert(app.activeDocument.height);
#include "modules/json/json.js"
alert(JSON.stringify(app.activeDocument.height));
Photoshop
ExtendScript
.JSX .JS
Convention
ExtendScript files Regular files
not using special Adobe
classes and functions
@dgomezg @D_v_G
DEVELOPMENT TOOLS
ExtendScript Toolkit
DEVELOPMENT TOOLS
ExtendScript Toolkit
• Delivered with every Creative Suite
product
• Need to set the target application
• Combo
• #target
• Benefits
• run on application
• Debug tools
• Inspector
DEVELOPMENT TOOLS
Any other JS editor
Launch script via File > Scripts > Browse ...
@dgomezg @D_v_G
the Photoshop
HDTR.jsx script
Process config
var hdtrConfig = {
direction : Direction.VERTICAL
, guidesOffset : 5
, maskOffset : 25
, guideSpacing : function () {
if (this.direction == Direction.VERTICAL) {
return this.docDimensions.width / this.shots;
} else {
return this.docDimensions.height / this.shots;
}
}
};
Added later:
- Image (document) dimensions
- Number of original shots
- Blending Offset (in Pixels # of Columns)
Source file selection
& further config
var files = app.openDialog();
hdtrConfig.shots = files.length;
hdtrConfig.docDimensions = getImageFileDimensions(files[0]);
hdtrConfig.offset =
hdtrConfig.maskOffset * hdtrConfig.guideSpacing();
var getImageFileDimensions = function(file) {
var imageDocument = app.open(file);
var documentDimensions = { "height" : document.height,
"width" : document.width,
"resolution" : document.resolution};
imageDocument.close();
return documentDimensions;
}
HDTR document
var hdtrDocument = app.documents.add(
hdtrConfig.docDimensions.width,
hdtrConfig.docDimensions.height,
hdtrConfig.docDimensions.resolution);
drawGuides(hdtrDocument, hdtrConfig.direction, hdtrConfig.shots);
var drawGuides = function(document, direction, number) {
var distance = (direction == Direction.HORIZONTAL)?
document.height / number :
document.width / number ;
for (var i = 0; i < number + 1; i++) {
var position;
position = i * distance;
document.guides.add(direction,
new UnitValue(position, position));
}
}
Main Loop
var refGuide;
var from;
var to;
for (index = 0; index < files.length; index++) {
addLayerFromFile(hdtrDocument, files[index]);
if (index > 0) {
refGuide = hdtrDocument.guides[index];
from = refGuide.coordinate - hdtrConfig.offset;
to = refGuide.coordinate + hdtrConfig.offset;
createLayerMask(hdtrDocument, hdtrDocument.activeLayer, false);
fillWithGradient(from, hdtrConfig.docDimensions.height /2,
to, hdtrConfig.docDimensions.height /2);
}
}
@dgomezg @D_v_G
Add Layer from File
var addLayerFromFile = function(hdtrDocument, file) {
var sourceDocument = app.open(file);
app.activeDocument = sourceDocument;
app.activeDocument.activeLayer.copy();
app.activeDocument = hdtrDocument;
hdtrDocument.paste();
hdtrDocument.activeLayer.name =
(hdtrDocument.artLayers.length -1) + "-" + sourceDocument.name;
sourceDocument.close();
}
@dgomezg @D_v_G
Create Layer Mask
var createLayerMask = function(doc, layer, fromSelection) {
var desc = new ActionDescriptor();
desc.putClass(cTID("Nw "), cTID("Chnl"));
var ref = new ActionReference();
ref.putEnumerated(cTID("Chnl"), cTID("Chnl"), cTID("Msk "));
desc.putReference(cTID("At "), ref);
if (fromSelection == true) {
desc.putEnumerated(cTID("Usng"), cTID("UsrM"), cTID("RvlS"));
} else {
desc.putEnumerated(cTID("Usng"), cTID("UsrM"), cTID("RvlA"));
}
executeAction(cTID("Mk "), desc, DialogModes.NO);
}
@dgomezg @D_v_G
Fill with Gradient
var fillWithGradient = function(startX, startY, endX, endY) {
var V1 = new ActionDescriptor();
var V2 = new ActionDescriptor();
V2.putUnitDouble(
charIDToTypeID("Hrzn"),
charIDToTypeID("#Pxl"),
startX); // start point X
V2.putUnitDouble(
charIDToTypeID("Vrtc"),
charIDToTypeID("#Pxl"),
startY); // start point Y
V1.putObject(
charIDToTypeID("From"),
charIDToTypeID("Pnt "), V2);
var V3 = new ActionDescriptor();
....
Better to see the source code
DEMO TIME!
Next Steps
Heterogeneous slice
distribution
@dgomezg @D_v_G
Easier configuration
Using Photoshop UI
Photoshop CS1
User Interaction via Alerts
Photoshop CS2
Added ScriptUI
(page 187 of PS CS2 JS Reference)
Photoshop CS3+
ScriptUI moved to PS JS TOOLS GUIDE
@dgomezg @D_v_G
Script UI
var dlg = new Window("dialog{text:'Script Interface',bounds:[100,100,561,269],
iwtfkhamhc:EditText{bounds:[16,16,444.95,94] , text:'Your text goes here' ,properties:
{multiline:false,noecho:false,readonly:false}},
button0:Button{bounds:[17,102,117,122] , text:'Save' },
button1:Button{bounds:[236,101,336,121] , text:'Cancel' },
button2:Button{bounds:[345,101,445,121] , text:'Whatever' },
slider0:Slider{bounds:[18,138,173,148] , minvalue:0,maxvalue:100,value:0},
checkbox0:Checkbox{bounds:[190,133,261,154] , text:'Checkbox Text' },
dropdown0:DropDownList{bounds:[299,134,443,149],properties:{items:['Select One']}}
};");
dlg.show();
@dgomezg @D_v_G
Further Reference
http://kcy.me/l7uohttp://kcy.me/l7ur
@dgomezg @D_v_G
Q & A
Thanks
@d_v_g
@dgomezg
https://github.com/dgomezg/hdtr-photoshop-js

T3chFest2016 - Uso del API JavaScript de Photoshop para obtener fotos HDTR

  • 1.
    Except where otherwisenoted, this work is licensed under: http://creativecommons.org/licenses/by-nc-sa/ 3.0/ Uso del API Javascript para obtener fotos HDTR Leganés, 11 y 12 de febrero David Gómez G.
  • 2.
    Dr Jeckyll &Mr Hide Haciendo Fotos desde los 16 años Exposiciones Colectivas e indivudales Ing. técnico en Informática de sistemas Sw Engineer & Trainer @dgomezg@d_v_g
  • 3.
    The HDTR technique Termcoined by Martin Krzywinski HDTR High Dynamic Time Range @dgomezg @D_v_G
  • 4.
    The HDTR Technique Termcoined by Martin KrzywinskiHDTR | High Dynamic Time Range http://mkweb.bcgsc.ca/fun/hdtr/
  • 5.
  • 6.
    The Planning Spot theplace (Find out if its going to be crowded at sunset) Find out when and where the sun sets Check the weather forecast (A rainy sunset looks quite different) @dgomezg @D_v_G
  • 7.
    Do you requirea Permit? @dgomezg @D_v_G
  • 8.
    Do you requirea Permit? (Even If they’re useless)
  • 9.
  • 10.
  • 11.
    Golden & BlueHours in Photography @dgomezg @D_v_G
  • 12.
    Photographic Shot Keep thecamera steady for several hours (a TRIPOD will help) Set a NEUTRAL White Balace Keep a const Depth of Field (Aperture Priority) Better if you can shot Tethered to a Computer Pick some BEERS & FRIENDS (but pay attention to the camera) @dgomezg @D_v_G
  • 13.
    TOOLS and Setup TetheredShooting Set Aperture Priority Set timered shooting (TIMELAPSE SHOOTING) @dgomezg @D_v_G
  • 14.
  • 15.
    Construction of a HDTRimage @dgomezg @D_v_G
  • 16.
    The Photoshop Process Describedat http://mkweb.bcgsc.ca/fun/hdtr/?tutorial
  • 17.
  • 18.
    Available AT http://mkweb.bcgsc.ca/fun/hdtr/?CODE Martin Krzywinski Implementation •Perl BASED • PROS • Easy setup & RUN • FREE • No dependencies (but Perl & libs) • CONS • Verbose blending config • No tuning posibility of result image @dgomezg @D_v_G
  • 19.
    PS Scripting alternative • PROS •Final image un PSD format with layers • You could further adjust the result • Easy config & run • CONS • PS License required • Harder to code @dgomezg @D_v_G
  • 20.
  • 21.
    Photoshop JS • SincePHOTOSHOP CS 1 (experimental support in PS 7.0 via an optional plugin) • Cross platform • New DOM To access most of Photoshop features and properties @dgomezg @D_v_G
  • 22.
    Photoshop’s DOM • BUTStill some operations not available: Gradients, Adjustment Layers, Layer Effects, polygonal selections....@dgomezg @D_v_G
  • 23.
    Access to the“Hidden” functionality • JS Classes from original PS SDK interface • ActionDescriptor, • ActionList • ActionReference • Use codes as parameters @dgomezg @D_v_G
  • 24.
    Access to the“Hidden” functionality ScriptListener plugin //------------------------------------------------------------- var V1 = new ActionDescriptor(); var V2 = new ActionDescriptor(); V2.putUnitDouble(charIDToTypeID("Hrzn"),charIDToTypeID("#Pxl"), 345); V2.putUnitDouble(charIDToTypeID("Vrtc"),charIDToTypeID("#Pxl"), 667); V1.putObject(charIDToTypeID("From"),charIDToTypeID("Pnt "), V2); var V3 = new ActionDescriptor(); [...] Records User’s interaction to JS script var fillWithGradient = function(startX, startY, endX, endY) { var V1 = new ActionDescriptor(); var V2 = new ActionDescriptor(); V2.putUnitDouble( charIDToTypeID("Hrzn"), charIDToTypeID("#Pxl"), startX); // start point X V2.putUnitDouble( charIDToTypeID("Vrtc"), charIDToTypeID("#Pxl"), startY); // start point Y V1.putObject( charIDToTypeID("From"), charIDToTypeID("Pnt "), V2); var V3 = new ActionDescriptor();
  • 25.
    Access to the“Hidden” functionality Code translation //------------------------------------------------------------- var V1 = new ActionDescriptor(); var V2 = new ActionDescriptor(); V2.putUnitDouble(charIDToTypeID("Hrzn"),charIDToTypeID("#Pxl"), 345); V2.putUnitDouble(charIDToTypeID("Vrtc"),charIDToTypeID("#Pxl"), 667); V1.putObject(charIDToTypeID("From"),charIDToTypeID("Pnt "), V2); var V3 = new ActionDescriptor(); [...] Translating codes /* lMID.maskHides = 1214529900;//"HdAl" lMID.maskRevealsAll = 1383492673;//"RvlA" lMID.maskReveals = 1383492691;//"Rvls" lMID.mask = 1299409696;//"Msk " lMID.at = 1098129440;//"At " lMID.using = 1433628263;//"Usng" lMID.userMask = 1433629261;//"UsrM" lMID.make = 1298866208;//"Mk " lMID.property = 1349677170;//"Prpr" ... */ cTID = function(s) { return app.charIDToTypeID(s); }; sTID = function(s) { return app.stringIDToTypeID(s); };
  • 26.
    Photoshop Extended Script • SOMEPhotoshop classes are defined in an extended and particular way alert(app.activeDocument.height); #include "modules/json/json.js" alert(JSON.stringify(app.activeDocument.height));
  • 27.
    Photoshop ExtendScript .JSX .JS Convention ExtendScript filesRegular files not using special Adobe classes and functions @dgomezg @D_v_G
  • 28.
  • 29.
    DEVELOPMENT TOOLS ExtendScript Toolkit •Delivered with every Creative Suite product • Need to set the target application • Combo • #target • Benefits • run on application • Debug tools • Inspector
  • 30.
    DEVELOPMENT TOOLS Any otherJS editor Launch script via File > Scripts > Browse ... @dgomezg @D_v_G
  • 31.
  • 32.
    Process config var hdtrConfig= { direction : Direction.VERTICAL , guidesOffset : 5 , maskOffset : 25 , guideSpacing : function () { if (this.direction == Direction.VERTICAL) { return this.docDimensions.width / this.shots; } else { return this.docDimensions.height / this.shots; } } }; Added later: - Image (document) dimensions - Number of original shots - Blending Offset (in Pixels # of Columns)
  • 33.
    Source file selection &further config var files = app.openDialog(); hdtrConfig.shots = files.length; hdtrConfig.docDimensions = getImageFileDimensions(files[0]); hdtrConfig.offset = hdtrConfig.maskOffset * hdtrConfig.guideSpacing(); var getImageFileDimensions = function(file) { var imageDocument = app.open(file); var documentDimensions = { "height" : document.height, "width" : document.width, "resolution" : document.resolution}; imageDocument.close(); return documentDimensions; }
  • 34.
    HDTR document var hdtrDocument= app.documents.add( hdtrConfig.docDimensions.width, hdtrConfig.docDimensions.height, hdtrConfig.docDimensions.resolution); drawGuides(hdtrDocument, hdtrConfig.direction, hdtrConfig.shots); var drawGuides = function(document, direction, number) { var distance = (direction == Direction.HORIZONTAL)? document.height / number : document.width / number ; for (var i = 0; i < number + 1; i++) { var position; position = i * distance; document.guides.add(direction, new UnitValue(position, position)); } }
  • 35.
    Main Loop var refGuide; varfrom; var to; for (index = 0; index < files.length; index++) { addLayerFromFile(hdtrDocument, files[index]); if (index > 0) { refGuide = hdtrDocument.guides[index]; from = refGuide.coordinate - hdtrConfig.offset; to = refGuide.coordinate + hdtrConfig.offset; createLayerMask(hdtrDocument, hdtrDocument.activeLayer, false); fillWithGradient(from, hdtrConfig.docDimensions.height /2, to, hdtrConfig.docDimensions.height /2); } } @dgomezg @D_v_G
  • 36.
    Add Layer fromFile var addLayerFromFile = function(hdtrDocument, file) { var sourceDocument = app.open(file); app.activeDocument = sourceDocument; app.activeDocument.activeLayer.copy(); app.activeDocument = hdtrDocument; hdtrDocument.paste(); hdtrDocument.activeLayer.name = (hdtrDocument.artLayers.length -1) + "-" + sourceDocument.name; sourceDocument.close(); } @dgomezg @D_v_G
  • 37.
    Create Layer Mask varcreateLayerMask = function(doc, layer, fromSelection) { var desc = new ActionDescriptor(); desc.putClass(cTID("Nw "), cTID("Chnl")); var ref = new ActionReference(); ref.putEnumerated(cTID("Chnl"), cTID("Chnl"), cTID("Msk ")); desc.putReference(cTID("At "), ref); if (fromSelection == true) { desc.putEnumerated(cTID("Usng"), cTID("UsrM"), cTID("RvlS")); } else { desc.putEnumerated(cTID("Usng"), cTID("UsrM"), cTID("RvlA")); } executeAction(cTID("Mk "), desc, DialogModes.NO); } @dgomezg @D_v_G
  • 38.
    Fill with Gradient varfillWithGradient = function(startX, startY, endX, endY) { var V1 = new ActionDescriptor(); var V2 = new ActionDescriptor(); V2.putUnitDouble( charIDToTypeID("Hrzn"), charIDToTypeID("#Pxl"), startX); // start point X V2.putUnitDouble( charIDToTypeID("Vrtc"), charIDToTypeID("#Pxl"), startY); // start point Y V1.putObject( charIDToTypeID("From"), charIDToTypeID("Pnt "), V2); var V3 = new ActionDescriptor(); .... Better to see the source code
  • 39.
  • 40.
  • 41.
  • 42.
    Easier configuration Using PhotoshopUI Photoshop CS1 User Interaction via Alerts Photoshop CS2 Added ScriptUI (page 187 of PS CS2 JS Reference) Photoshop CS3+ ScriptUI moved to PS JS TOOLS GUIDE @dgomezg @D_v_G
  • 43.
    Script UI var dlg= new Window("dialog{text:'Script Interface',bounds:[100,100,561,269], iwtfkhamhc:EditText{bounds:[16,16,444.95,94] , text:'Your text goes here' ,properties: {multiline:false,noecho:false,readonly:false}}, button0:Button{bounds:[17,102,117,122] , text:'Save' }, button1:Button{bounds:[236,101,336,121] , text:'Cancel' }, button2:Button{bounds:[345,101,445,121] , text:'Whatever' }, slider0:Slider{bounds:[18,138,173,148] , minvalue:0,maxvalue:100,value:0}, checkbox0:Checkbox{bounds:[190,133,261,154] , text:'Checkbox Text' }, dropdown0:DropDownList{bounds:[299,134,443,149],properties:{items:['Select One']}} };"); dlg.show(); @dgomezg @D_v_G
  • 44.
  • 45.
  • 46.