The process of creating HDTR images from the photographic shot to the processing via a Photoshop JS script explained.
This is the slide I used for my talk at the monthly MadridJS meeting held on May, 23rd 2013.
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
6. 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)
8. 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)
9. TOOLS and Setup
Tethered Shooting
Set Aperture Priority
Set timered shooting
(TIMELAPSE SHOOTING)
15. 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
17. 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
18. Photoshop’s DOM
• BUT Still some operations not
available: Gradients, Adjustment
Layers, Layer Effects, polygonal
selections....
19. Access to the “Hidden”
functionality
• JS Classes from original PS SDK
interface
• ActionDescriptor,
• ActionList
• ActionReference
• Use codes as parameters
20. 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();
22. Photoshop Extended
Script
• SOME Photoshop classes are defined in
an extended an particular way
alert(app.activeDocument.height);
#include
"modules/json/json.js"
alert(JSON.stringify(app.activeDocument.height));
25. 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
28. Process config
var
hdtrConfig
=
{
direction
:
Direction.VERTICAL
,
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)
29. 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;
}
30. 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));
}
}
31. 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);
}
}
33. 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);
}
34. 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