(API) Difference between CropAngle and straightenAngle?

Community Beginner ,
Dec 20, 2021 Dec 20, 2021

Copy link to clipboard

Copied

Hello everyone,

 

I try to crop and straighten images with the Lua SDK.

 

This is the code:

  if LrApplicationView.getCurrentModuleName() == "develop" and photo == catalog:getTargetPhoto() then
    LrDevelopController.setValue("CropLeft", cropLeft)
    LrDevelopController.setValue("CropRight", cropRight)
    LrDevelopController.setValue("CropTop", cropTop)
    LrDevelopController.setValue("CropBottom", cropBottom)
    LrDevelopController.setValue("straightenAngle", angle)
    LrDevelopController.setValue("CropConstrainAspectRatio", aspectRatio)
  else
    local settings = {}
    settings.CropLeft                 = cropLeft
    settings.CropRight                = cropRight
    settings.CropTop                  = cropTop
    settings.CropBottom               = cropBottom
    settings.CropAngle                = -angle
    settings.CropConstrainAspectRatio = aspectRatio
    photo:applyDevelopSettings(settings)
  end

 

The weird thing is that I am getting two different results. When the first if-statement is true the script works fine and the output is as desired: The image was cropped by the calculated values and the angle was corrected while maintaining the desired aspect ratio.

But in the second if-statement the result is different. The image was cropped by the calculated values, but the angle correction changed the desired aspect ratio. Somehow it adds size to the crop width or height.

 

I tried to research it but as far as I know the straightenAngle and CropAngle are supposed to be the same?

 

I tried settings.straightenAngle (instead of settings.CropAngle), but it didn't work at all.

 

Am I missing something here? Do I do something wrong?

 

Thank you all in advance!

TOPICS
SDK

Views

285

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Dec 20, 2021 Dec 20, 2021

Copy link to clipboard

Copied

If you post the exact values for the six crop settings, I'll take a look. I've got a lot of experience with manipulating crops in my Any Crop and Copy Settings plugins.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Dec 20, 2021 Dec 20, 2021

Copy link to clipboard

Copied

Hey John, thanks for your reply!

 

So the initial width of the image that I crop is 6240 x 4160 px.

The variables (in this case):

cropLeft = 0.514964809366862

cropRight = 0.8228476092529297

cropTop = 0.18166129150390625

cropBottom = 0.8280794311523437

angle = -1.3169

aspectRatio = true

 

Result of LrDevelopController.setValue-Method: 1921 x 2689 px. (That's the desired aspect ratio of 5/7).

Result of applyDevelopSettings-Method: 1982 x 2644 px. (That's not the desired aspect ratio of 5/7).

 

In both cases I use the same values.

 

When I skip the cropAngle/straightenAngle values, both methods return the desired aspect ratio: they are then both perfectly the same output.

 

Thanks in advance 🙂

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Dec 20, 2021 Dec 20, 2021

Copy link to clipboard

Copied

I'll dig in late afternoon when I get back to my desk.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Dec 20, 2021 Dec 20, 2021

Copy link to clipboard

Copied

In general, I've always used the keys from photo:applyDevelopSettings() with LrDevelopController.set/getValue().  I started doing this when LrDevelopContoller had woefully incomplete documentation (it's only somewhat incomplete now).

 

One issue is CropConstrainAspectRatio -- I don't think that corresponds to anything in the UI. The checkbox "Constrain to Image" in the Crop tool and the checkbox "Constrain To Crop" in the Transform panel both map to CropConstrainToWarp.

 

"straigenAngle" appears to be a synonym for - CropAngle; these invariants always hold:

 

LrDevelopController.getValue ("straightenAngle") == - photo:getDevelopSettings ().CropAngle

LrDevelopController.getValue ("straightenAngle") == - LrDevelopController.getValue ("CropAngle")

 

Taking all this into consideration, the following code produces the same crop regardless of whether "if true" or "if false":

 

s = {CropLeft = 0.514964809366862,
    CropRight = 0.8228476092529297,
    CropTop = 0.18166129150390625,
    CropBottom = 0.8280794311523437,
    CropAngle = -1.3169,
    CropConstrainToWarp = 1}

if true then 
    LrDevelopController.setValue ("CropLeft", s.CropLeft)
    LrDevelopController.setValue ("CropRight", s.CropRight)
    LrDevelopController.setValue ("CropTop", s.CropTop)
    LrDevelopController.setValue ("CropBottom", s.CropBottom)
    LrDevelopController.setValue ("CropAngle", s.CropAngle)
    LrDevelopController.setValue ("CropConstrainToWarp", s.CropConstrainToWarp)
else
    catalog:withWriteAccessDo ("crop", function ()
        targetPhoto:applyDevelopSettings (s) end)
    end

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Dec 20, 2021 Dec 20, 2021

Copy link to clipboard

Copied

Also, you can use photo:applyDevelopSettings() when LR is in Develop mode -- no need to use LrDevelopController (unless you're trying to do real-time control of the UI, e.g. by a MIDI controller).

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Dec 20, 2021 Dec 20, 2021

Copy link to clipboard

Copied

Thank you very much. I really appreciate your reply and help 🙂 Unfortunately it still doesn't work for me; the aspect ratio constantly changes with the applyDevelopSettings method. I try to post more in-depth information tomorrow.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Dec 20, 2021 Dec 20, 2021

Copy link to clipboard

Copied

Let's see if you're observing the same thing I do.  Save the following script into the file "crop-apply.lua" in the Scripts folder in the Lightroom settings folder (do Preferences > Presets > Show All Other Presets to get to that folder):

local LrDevelopController = import "LrDevelopController"
local LrTasks = import "LrTasks"

local catalog = import "LrApplication".activeCatalog ()
local photo = catalog:getTargetPhoto ()

local s = {CropLeft = 0.514964809366862,
    CropRight = 0.8228476092529297,
    CropTop = 0.18166129150390625,
    CropBottom = 0.8280794311523437,
    CropAngle = -1.3169,
    CropConstrainToWarp = 1}

LrTasks.startAsyncTask (function ()
    if false then 
        LrDevelopController.setValue ("CropLeft", s.CropLeft)
        LrDevelopController.setValue ("CropRight", s.CropRight)
        LrDevelopController.setValue ("CropTop", s.CropTop)
        LrDevelopController.setValue ("CropBottom", s.CropBottom)
        LrDevelopController.setValue ("CropAngle", s.CropAngle)
        LrDevelopController.setValue ("CropConstrainToWarp", 
            s.CropConstrainToWarp)
    else
        catalog:withWriteAccessDo ("crop", function ()
            photo:applyDevelopSettings (s) end)
        end
    end)

 

Then change "if false" to "if true" and save the script to the file "crop-develop.lua" in the same folder. Then restart LR.

 

You can now invoke these two scripts from the Scripts menu (looks like a scroll icon in Mac LR menu bar). When I open a photo in Develop, the two scripts produce identical crops.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Dec 22, 2021 Dec 22, 2021

Copy link to clipboard

Copied

So after some hours of testing: Your script produces exactly the same crop for me, when true and when false 🙂 I think for this part I have to figure out why my inital plugin script behaves differently.

 

For your script the unfortunate part is that the aspect ratio still isn't right for me. I desire a 5 x 7 aspect ratio but it seems that the crop angle alters it.

 

When I set

CropAngle = 0

the aspect ratio is fine. It's exactly 5 x 7 as desired. (In both scripts.)

 

When I set (for a more extreme example)

 

CropAngle = 5

the aspect ratio is way off the charts, it's coming closer to 1 x 1. (Also in both scripts.)

 

And now comes the interesting thing and it brings me back to my inital question:

 

When I set

 

CropAngle = 5

 

and using

LrDevelopController.setValue("straightenAngle", s.CropAngle)

with using "straightenAngle" instead of "CropAngle" than the aspect ratio is exactly 5 x 7. Of course only for the "true" setting. The "false" setting still produces an awfully wrong aspect ratio.

 

Can you reproduce this for your script aswell?

 

I am using Lightroom Classic 10.2 btw.

 

Thanks for your help! I really appreciate it 🙂

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Dec 22, 2021 Dec 22, 2021

Copy link to clipboard

Copied

[This post contains formatting and embedded images that don't appear in email. View the post in your Web browser.]

 

Some more experimentation confirms that the LrDevelopController key "straightenAngle" is not the same as setting CropAngle to minus the angle. 

 

Let's start from the beginning. LR represents a crop with five values. The upper-left corner of the crop is (CropLeft, CropTop), the lower-right corner is (CropRight, CropBottom), and the crop is rotated counterclockwise by CropAngle around the center point between the two corners:

johnrellis_0-1640205903339.png

 

For a given (CropLeft, CropTop) (CropRight, CropBottom), changing CropAngle will change the aspect ratio of the described crop. The larger the CropAngle, the smaller the width and larger the height.

 

In the Crop tool UI, changing the Angle slider doesn't directly change CropAngle -- rather, it rotates the current crop around its center point, preserving the crop's aspect ratio.  The LrDevelopController key "straightenAngle" represents the value of that slider, and changing the key's value with setValue() is exactly the same as moving the slider. This makes sense, since the primary purpose of LrDevelopController is to allow MIDI controllers to manipulate the UI.

 

As you move the Angle slider, the values of CropLeft, CropRight, CropTop, and CropBottom will necessarily change to preserve the width and height of the crop (in units of pixels). Thus, the order in which the key values are set is important; doing it in this order:

 

straightenAngle, CropLeft, CropRight, CropTop, CropBottom

 

will produce a different crop than doing it in this order:

 

CropLeft, CropRight, CropTop, CropBottom, straightenAngle

 

Unfortunately, photo:applyDevelopSettings() doesn't support the key "straightenAngle", so you can't use it to rotate a crop of a given aspect ratio around its center point. If you want your plugin to do that, you've got two options:

 

1. Use LrApplicationView.switchToModule ("develop") to switch to the Develop module and then use LrDevelopController.setValue ("straightenAngle", angle). 

 

2. Do high-school trig to rotate the current crop around its center point and use photo:applyDevelopSettings() in either Library or Develop modules. But one gotcha: You have to convert from the [0..1], [0..1] coordinate system of develop settings to pixel coordinates [0..width], [0..height], rotate the crop, and then convert back to [0..1] coordinates.

 

Another complication is handling rotated and flipped photos, which are represented by the "orientation" develop setting. LR's develop settings are specified with respect to the photo before any rotation or flipping is applied. So to apply the same crop to a portrait raw (rotated 90 degrees) and to a TIFF exported by Photoshop from that raw (rotated 0 degrees),  you've got to account for the rotation and flipping.  

 

My Any Crop and Copy Settings plugins use method 2.  They translate the crop from the develop-settings coordinate system to the "visible pixels" coordinate system (after rotation and flipping have been applied). They do any crop transformations in visible-pixels coordinates, then translate back to develop-settings coordinates.

 

(Note that LR's Copy/Sync Settings still don't correctly copy local adjustments between photos with different orientations, because the developers never bothered to implement the coordinate-system translations.)

 

For processing a large number of photos, method 2 should be much faster, since it's not manipulating the UI, and the re-rendering of the photos will occur in background.

 

It's not easy for me to provide you with a cookbook snippet of code for doing all this, since the code is embedded in the entire framework my plugins use for manipulating coordinates.

 

 

 

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Dec 27, 2021 Dec 27, 2021

Copy link to clipboard

Copied

Thank you very very much for your detailed reply. I really appreciate it!

 

I spend the last two days to figure out a way to use your solution #2, but I just can't wrap my head around it and I am about to give up.

 

In general I just can't figure out the math behind the CropAngle calculation. I understand that it's adding height and substracting width. So I tried to calculate the differences but with no success at all. I came close, but the aspect ratio was never on point.

 

And unfortunately I don't understand your suggestion of switching to pixel coordinates and rotate the crop. From what I understand I have to calculate new crop values that consider the CropAngle-height-adding-thing to basically work against it. How does working with pixels change the math?

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Dec 27, 2021 Dec 27, 2021

Copy link to clipboard

Copied

I'm not a math teacher, and it's been too many decades since I was in college, so I'm not a great explainer about this :-<

 

"How does working with pixels change the math?"

 

The core issue is that for photos that aren't square, the develop coordinates go from 0 to 1 for both the horizontal and vertical dimensions, while the pixel coordinates go from 0 to width-in-pixels and 0 to height-in-pixels.  So all angle computations must be done in pixel coordinates.  

 

To see why, consider a single camera pixel of a 6000 x 4000 photo. Let's compute the angle of the diagonal line from the lower-left to the upper-right corner:

johnrellis_1-1640631682746.png

In pixel coordinates, the width of the pixel is 1 and the height is 1. But in develop coordinates, the width is 1/6000 and the height is 1/4000.

 

Remembering my trig:

tan (angle) = h / w

angle = arctan (h / w)

 

In pixel coordinates then, the angle is computed correctly as 45 degrees:

angle = arctan (1 / 1) = 45 deg

 

But if we use develop coordinates, the angle is computed incorrectly as 56.3 degrees:

angle = arctan ((1/4000) / (1/6000)) = 56.3

 

 

 

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Dec 27, 2021 Dec 27, 2021

Copy link to clipboard

Copied

LATEST

Also, one thing that tripped me up initially doing angle computations in Lua: The trig functions in the math module (math.sin, math.tan, etc.) are all in units of radians, not degrees. So you have to use math.deg and math.rad to convert back and forth.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines