Repository navigation
Expand file tree
/
Copy pathExactCrop.lua
More file actions
161 lines (136 loc) · 4.36 KB
/
Copy pathExactCrop.lua
File metadata and controls
161 lines (136 loc) · 4.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
local LrApplication = import 'LrApplication'
local LrBinding = import 'LrBinding'
local LrDialogs = import 'LrDialogs'
local LrFunctionContext = import 'LrFunctionContext'
local LrTasks = import 'LrTasks'
local LrView = import 'LrView'
local function getOrientedDimensions(photo)
local dims = photo:getRawMetadata('dimensions') or { width = 0, height = 0 }
local width = tonumber(dims.width) or 0
local height = tonumber(dims.height) or 0
local orientation = photo:getRawMetadata('orientation')
if orientation == 'BC' or orientation == 'DA' or orientation == 'CB' or orientation == 'AD' then
width, height = height, width
end
return width, height
end
local function applyExactCropToPhoto(photo, width, height)
local maxWidth, maxHeight = getOrientedDimensions(photo)
local settings = photo:getDevelopSettings()
local cropWidth = width / maxWidth
local cropHeight = height / maxHeight
local left = (1 - cropWidth) / 2
local top = (1 - cropHeight) / 2
settings.CropLeft = left
settings.CropTop = top
settings.CropRight = left + cropWidth
settings.CropBottom = top + cropHeight
settings.CropAngle = 0
photo:applyDevelopSettings(settings)
end
local function applyExactCrop(catalog, photos, width, height)
catalog:withWriteAccessDo('Apply exact crop', function()
for _, photo in ipairs(photos) do
applyExactCropToPhoto(photo, width, height)
end
end)
end
local function showExactCropDialog()
LrFunctionContext.callWithContext('showExactCropDialog', function(context)
local catalog = LrApplication.activeCatalog()
if not catalog then
LrDialogs.message('Exact Crop', 'No Lightroom catalog is open.', 'warning')
return
end
local photos = catalog:getTargetPhotos() or {}
if #photos == 0 then
LrDialogs.message('Exact Crop', 'Please select at least one image before using Exact Crop.', 'warning')
return
end
-- The smallest selected image's dimensions bound what every photo in the batch can be cropped to.
local minWidth, minHeight
for _, photo in ipairs(photos) do
local width, height = getOrientedDimensions(photo)
minWidth = minWidth and math.min(minWidth, width) or width
minHeight = minHeight and math.min(minHeight, height) or height
end
local props = LrBinding.makePropertyTable(context)
props.width = ''
props.height = ''
props.warning = 'Enter width and height in pixels.'
props.actionEnabled = false
local function updateValidity()
local width = tonumber(props.width)
local height = tonumber(props.height)
if width == nil or height == nil then
props.warning = 'Enter width and height in pixels.'
props.actionEnabled = false
return
end
if width <= 0 or height <= 0 then
props.warning = 'Width and height must be greater than zero.'
props.actionEnabled = false
return
end
if width > minWidth or height > minHeight then
props.warning = 'Width and height must not exceed the smallest selected image size (' .. minWidth .. ' x ' .. minHeight .. ').'
props.actionEnabled = false
return
end
props.warning = ''
props.actionEnabled = true
end
props:addObserver('width', updateValidity)
props:addObserver('height', updateValidity)
local f = LrView.osFactory()
local c = f:column {
spacing = f:control_spacing(),
bind_to_object = props,
f:row {
f:static_text { title = 'Width' },
f:edit_field {
value = LrView.bind('width'),
immediate = true,
width_in_digits = 8,
},
},
f:row {
f:static_text { title = 'Height' },
f:edit_field {
value = LrView.bind('height'),
immediate = true,
width_in_digits = 8,
},
},
f:static_text {
title = LrView.bind('warning'),
fill_horizontal = 1,
height_in_lines = 2,
font = '<system>',
},
}
local result = LrDialogs.presentModalDialog {
title = 'Exact Crop',
contents = c,
actionVerb = 'OK',
actionBinding = {
enabled = {
bind_to_object = props,
key = 'actionEnabled',
},
},
}
if result == 'ok' then
local width = tonumber(props.width)
local height = tonumber(props.height)
applyExactCrop(catalog, photos, width, height)
local message = 'Cropped ' .. #photos .. ' image'
if #photos ~= 1 then
message = message .. 's'
end
message = message .. ' to ' .. width .. ' x ' .. height .. ' pixels.'
LrDialogs.message('Exact Crop', message, 'info')
end
end)
end
LrTasks.startAsyncTask(showExactCropDialog)