• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Level Horizon with Action assistance

Participant ,
Jun 04, 2024 Jun 04, 2024

Copy link to clipboard

Copied

Hi,

I have a regular need to level horizon and do so by using ruler>Image Rotation>Arbitary

Id like to streamline this process by drawing line 1st then the rest of the process is done by action. Catch is that the degree value will be different every time.

Is there a way to do this in an action where the different value is read every time?

Thanks in advance

Todd

TOPICS
Actions and scripting

Views

113

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

correct answers 1 Correct answer

Community Expert , Jun 05, 2024 Jun 05, 2024

I forgot to mention that you can just record the ruler tool straighten button press into an action and use an F-key, where it will use the script mentioned above. No need for a custom installation of the script unless you require a custom keyboard shortcut.

Votes

Translate

Translate
Adobe
Community Expert ,
Jun 04, 2024 Jun 04, 2024

Copy link to clipboard

Copied

@Tango.......... 

 

It's currently a 2-step process... Draw the line with the ruler tool to set the angle, then press the "straighten layer" button – which calls the "Straighten.jsx" script that ships with Photoshop.

 

// (c) Copyright 2011.  Adobe Systems, Incorporated.  All rights reserved.

//
// Straighten.jsx - Straighten and crop a photo, based on the ruler position.
// Added prototype Layer transform via shift modifier-steveg, 2011
//
// John Peterson, Adobe Systems, 2009
//

/*
@@@BUILDINFO@@@ Straighten.jsx 3.0.0.4
*/

/*
// BEGIN__HARVEST_EXCEPTION_ZSTRING

<javascriptresource>
<name>$$$/JavaScripts/Straighten/Menu=Straighten to Ruler</name>
<menu>automate</menu>
</javascriptresource>

// END__HARVEST_EXCEPTION_ZSTRING
*/

// on localized builds we pull the $$$/Strings from a .dat file
$.localize = true;

var g_StackScriptFolderPath = app.path + "/"+ localize("$$$/ScriptingSupport/InstalledScripts=Presets/Scripts") + "/"
										+ localize("$$$/private/Exposuremerge/StackScriptOnly=Stack Scripts Only/");


$.evalFile( g_StackScriptFolderPath + "Geometry.jsx");

$.evalFile(g_StackScriptFolderPath + "Terminology.jsx");

// Create a base object to scope the rest of the functions in the file
function Straightener()
{
	this.pluginName = "Straighten";
}

straighten = new Straightener();

straighten.getUnitPoint = function( desc )
{
	var x = desc.getUnitDoubleValue( kxStr );
	var y = desc.getUnitDoubleValue( kyStr );
	return new TPoint( x, y );
}

// Special version of crop supporting the hidePixels option (DOM FIX)
straighten.hideCrop = function( cropRect, hidePixels )
{
	if (typeof hidePixels == "undefined")
		hidePixels = true;
		
	// Hiding  pixels does not work on simple documents
	if ((app.activeDocument.layers.length == 1)
		&& (app.activeDocument.activeLayer.isBackgroundLayer))
		hidePixels = false;
		
    var desc = new ActionDescriptor();
	var cropDesc = new ActionDescriptor();
	cropDesc.putUnitDouble( enumTop, unitPixels, cropRect.fTop );
	cropDesc.putUnitDouble( enumLeft, unitPixels, cropRect.fLeft );
	cropDesc.putUnitDouble( keyBottom, unitPixels, cropRect.fBottom );
	cropDesc.putUnitDouble( enumRight, unitPixels, cropRect.fRight );
    desc.putObject( keyTo, classRectangle, cropDesc );
    desc.putUnitDouble( enumAngle, unitAngle, 0.0 );
	if  (hidePixels)
		desc.putBoolean( eventHide, true );
	executeAction( eventCrop, desc, DialogModes.NO );
}

// Remove the ruler and update the display (DOM FIX)
straighten.clearRuler = function()
{
	desc = new ActionDescriptor();
	var eventClearRuler = app.stringIDToTypeID("clearRuler");
	executeAction( eventClearRuler, desc, DialogModes.NO );
}

// Get the endpoints from the ruler (DOM FIX)
straighten.getRulerEndpoints = function()
{
	var desc1 = new ActionDescriptor();
	var ref1 = new ActionReference();
	ref1.putProperty( classProperty, krulerPointsStr );
	ref1.putEnumerated( classDocument, typeOrdinal, enumTarget );
	desc1.putReference( typeNULL, ref1 );

	var result = executeAction( eventGet, desc1, DialogModes.NO );

	if  (result.hasKey( kpointsStr ))
	{
		var i, ptList = result.getList( kpointsStr );
		// The middle item in the list is an unused "midpoint" (currently == p0)
		var p0 = this.getUnitPoint( ptList.getObjectValue(0) );
		var p1 =  this.getUnitPoint( ptList.getObjectValue(2) );
		if (p0.fX < p1.fX)
			return [p0, p1];
		else
			return [p1, p0];
	}
	else
		return [];
}

// Given two ruler endpoints, compute the rotation (in radians)
// needed to make the ruler horizontal or vertical.
straighten.getRotationAngle = function( p0, p1 )
{
	// Perfectly horizontal or vertical - no rotation
	if ((p0.fX == p1.fX) || (p0.fY == p1.fY))
		return 0.0;
		
	var a, t, v = p1 - p0;
	if (Math.abs(v.fY) > Math.abs(v.fX))
	{
		// If the line is mostly vertical, adjust the angle to
		// straighten to the vertical axis.
		t = v.fX;
		v.fX = v.fY;
		v.fY = t;
		if (v.fX < 0) 
		{
			v.fX = - v.fX;
			a = v.vectorAngle();
		}
		else
			a = -v.vectorAngle();
	}
	else 
		a = v.vectorAngle();
		
	return -a;
}

// Given an angle and a rectangle, compute the rotated
// rectangle and a new bounding rectangle for it.
straighten.computeRotation = function( angle, rect )
{
	// Rotate rect about the origin, and find the bounds of the rotated rectangle.
	rect.setCenter( TPoint.kOrigin );
	var i;
    this.fRotatedPoints = rect.getCornerPoints();
	
	this.fRotatedBounds = new TRect(0,0,0,0);
	for (i in this.fRotatedPoints)
	{
		this.fRotatedPoints[i] = this.fRotatedPoints[i].rotate(angle);
		this.fRotatedBounds.extendTo( this.fRotatedPoints[i] );
	}

	// Move the origin back to top left corner of the enclosing rect,
	// the new center is based on that.
	this.fRotatedBounds.offset( -this.fRotatedBounds.getTopLeft() );
	this.fNewCenter = this.fRotatedBounds.getCenter();

	for (i in this.fRotatedPoints)
		this.fRotatedPoints[i] += this.fNewCenter;	
}

// Given an rectange and a rotation angle, find a new rectangle with the
// same proportions that fits inside the original.
straighten.getCropRect = function( angle, rect )
{
    this.computeRotation( angle, rect );
 
	rect.setCenter( this.fNewCenter );

	var cropPts = [];
	
	// So sign test works below
	if (angle < -Math.PI)
		angle += 2*Math.PI;
		
	var off1 = (angle > 0) ? 3 : 0;
	var off2 = (angle > 0) ? 0 : 1;
	
	// Draw lines from the center through the corners of the original rect.
	// Record where those lines intersect the rotated rect.
	var ii, rectPoints = [rect.getTopLeft(), rect.getTopRight(), rect.getBottomRight(), rect.getBottomLeft()];
	for (ii in rectPoints)
	{
		i = Number(ii);	// Whacky Javascript uses strings, not numbers, for index
		cropPts[i] = TPoint.lineSegmentIntersect( this.fRotatedPoints[(i + off1) % 4], 
                                                                       this.fRotatedPoints[(i + off2) % 4], 
                                                                       this.fNewCenter, rectPoints[i] );
	}
			
	// The new crop is based on the minimum bounds of the intersections found above.
	var cropRect = new TRect( Math.max(cropPts[0].fX, cropPts[3].fX), Math.max(cropPts[0].fY, cropPts[1].fY), 
	                          Math.min(cropPts[1].fX, cropPts[2].fX), Math.min(cropPts[2].fY, cropPts[3].fY) );
	return cropRect;
}

straighten.getRulerAngle = function()
{
	var rulerPts = this.getRulerEndpoints();
	if (rulerPts.length == 0)
		return 0.0;
		
	return this.getRotationAngle( rulerPts[0], rulerPts[1] );
}

// Straighten the layer to the ruler with transform.  Returns the rotation angle,
// or zero if there was no rotation (or no ruler).
straighten.rotateLayerToRuler = function()
{
	var angle = this.getRulerAngle();

    if (angle == 0.0)
        return;

    if(!app.activeDocument.activeLayer.visible){
        alert(localize("$$$/Straighten/StraightenHiddenLayer=Could not straighten the layer because the target layer is hidden."));
        return;
    }

	layerRef = app.activeDocument.activeLayer;
	layerRef.rotate( angle * 180.0 / Math.PI );
	return angle;
}
// Straighten the image to the ruler.  Returns the rotation angle,
// or zero if there was no rotation (or no ruler).
straighten.rotateCanvasToRuler = function()
{
	var angle = this.getRulerAngle();
	app.activeDocument.rotateCanvas( angle * 180.0 / Math.PI );
	return angle;
}

// Crop the image to the bounds, rotated by angle (in radians)
straighten.cropRotatedImage = function( angle, bounds )
{
	var newBounds = this.getCropRect( angle, bounds );
	
	// Ideally we'd report an error here, but since it's past RC, we'll just silently fail.
	if (newBounds.isValid())
		this.hideCrop( newBounds, true );
//	app.activeDocument.crop( [UnitValue(newBounds.fLeft, 'px'), UnitValue(newBounds.fTop, 'px'), 
//							UnitValue(newBounds.fRight, 'px'), UnitValue(newBounds.fBottom, 'px')] );
}

// Original functionality, now not used.
straighten.rotateAndCropCanvas = function ()
{
    var angle, bounds = new TRect( 0, 0, app.activeDocument.width.as('px'), app.activeDocument.height.as('px') );
    angle = straighten.rotateCanvasToRuler();
    straighten.cropRotatedImage( angle, bounds );
}

// Main interactive entry.
straighten.doInteractive = function()
{
    var angle, bounds = new TRect( 0, 0, app.activeDocument.width.as('px'), app.activeDocument.height.as('px') );
    if (app.activeDocument.activeLayer.isBackgroundLayer == true)
        app.activeDocument.activeLayer.isBackgroundLayer = false;
        
    angle = straighten.rotateLayerToRuler() 
 
 // alert(localize("$$$/Straighten/Script/NoBGLayer=Operation cannot be performed on background layer"));
 
	if (angle != 0.0)
		straighten.clearRuler();
}

// Set runstraightenFromScript if you want to load this script w/o running it.
if ((typeof(runstraightenFromScript) == 'undefined')
	|| (runstraightenFromScript==false))
	straighten.doInteractive();

 

What other steps do you wish to do via action?

 

Another option is using Filter > Camera Raw Filter to geometry to transform, which can be automated via a script:

 

https://community.adobe.com/t5/photoshop/jsx-gt-camera-raw-filter-gt-transform-possible/m-p/11197302

 

/*
https://community.adobe.com/t5/photoshop/jsx-gt-camera-raw-filter-gt-transform-possible/m-p/11197302?page=1#M338216
JSX > Camera Raw Filter > Transform. Possible?

Camera Raw Filter - Transform Values:
1 = Auto, 2 = Full, 3 = Level, 4 = Vertical
*/
transformCRF(transValue = 1);

function transformCRF() {
    var actDesc = new ActionDescriptor();
    var transCode = charIDToTypeID("PerU");
    actDesc.putInteger(transCode, transValue);
    executeAction(stringIDToTypeID("Adobe Camera Raw Filter"), actDesc, DialogModes.NO);
}

 

 

 

 

Votes

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
Participant ,
Jun 05, 2024 Jun 05, 2024

Copy link to clipboard

Copied

Thanks @Stephen_A_Marsh Is there a way to linik that script to a function button, say F13?

Votes

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 Expert ,
Jun 05, 2024 Jun 05, 2024

Copy link to clipboard

Copied

quote

Thanks @Stephen_A_Marsh Is there a way to linik that script to a function button, say F13?


By @Tango..........

 

If you want an F-key, then record the execution of the script into an action.

 

Either install the script in the Presets/Scripts folder or use the File > Scripts > Browse command, more here:

 

https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html

 

P.S. If you install the script (not browse), then it can have a standard keyboard shortcut applied via Edit > Keyboard Shortcuts.

 

Votes

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 Expert ,
Jun 05, 2024 Jun 05, 2024

Copy link to clipboard

Copied

LATEST

I forgot to mention that you can just record the ruler tool straighten button press into an action and use an F-key, where it will use the script mentioned above. No need for a custom installation of the script unless you require a custom keyboard shortcut.

Votes

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