Photoshop: Breaked curves

  • 3
  • Idea
  • Updated 2 years ago
  • (Edited)
First, sorry for my bad english =) ... Hi, i`m a ceramic designer and in my daily routine with photoshop, I use curves all the time in all projects and they look like this:



And sometimes I have some trouble to drag the point because it mess with all the line:



in this case a need to create a lot of points to "lock" the curve:


so i imagine if it possible to create a new feature in the curves, like breaked curve like this:


Thanks!
Photo of Guilherme Colossi Rodrigues

Guilherme Colossi Rodrigues

  • 4 Posts
  • 0 Reply Likes
  • Creative

Posted 2 years ago

  • 3
Photo of christoph pfaffenbichler

christoph pfaffenbichler, Champion

  • 1224 Posts
  • 172 Reply Likes
»Draw to modify the curve« with pressed shift key seems pretty close to what you are describing. 
(Edited)
Photo of Guilherme Colossi Rodrigues

Guilherme Colossi Rodrigues

  • 4 Posts
  • 0 Reply Likes
in my case I need to be precise! Sometimes a need to move the dot in the curve so little, with the pen I don`t have this accuracy... thanks for the help
Photo of christoph pfaffenbichler

christoph pfaffenbichler, Champion

  • 1224 Posts
  • 172 Reply Likes
I expect one could create a Script that takes numerical entries (pairs of integers), then calculates the points in between and creates the corresponding Curves Layer. 
Not sure if it would work for more that 8bit images. 

Should you want to pursue that you could ask for help over at 
https://forums.adobe.com/community/photoshop/photoshop_scripting/content
Photo of Jaroslav Bereza

Jaroslav Bereza

  • 779 Posts
  • 166 Reply Likes
I agree that sometimes is hard to set desired curve
Photo of Cristen Gillespie

Cristen Gillespie

  • 1259 Posts
  • 323 Reply Likes
I've asked to have the corner curves you find in HDR Toning put into Curves, but so far, they've pretty much resisted everyone's requests to modify Curves.

I don't know if it will help you to work on a duplicate in HDR Toning and Local Adaptation with everything set to 0, except for Edge Glow which has a minimum of 1 and 0.10. You can use Corner Points and you can nudge them with the arrow keys, but only you know if that Edge Glow section messes with it or not.

If you haven't used it, you have to work on a duplicate of your image because it only works on a single background layer, but you can drag that layer into your main document after setting the curves. Nothing to lose by trying, I should imagine. And of course, I'm voting for this.
Photo of Guilherme Colossi Rodrigues

Guilherme Colossi Rodrigues

  • 4 Posts
  • 0 Reply Likes
So.. the HDR toning is only available with RGB images and I work with CMYK unfortunately. Thanks for the help!
Photo of Cristen Gillespie

Cristen Gillespie

  • 1259 Posts
  • 323 Reply Likes
And for such precision you're looking for, I wouldn't even want to recommend converting temporarily. <sigh> So one has to hope implementing Corner Points on the regular Curves feature is a JDI and they just do it.
Photo of Guilherme Colossi Rodrigues

Guilherme Colossi Rodrigues

  • 4 Posts
  • 0 Reply Likes
Yeah, converting is impossible on my workflow, I work with large images (8gb), and in a lot of  case I need to recover the lost information caused by the curves so i work with layers. Like i`m working now
Photo of Jaroslav Bereza

Jaroslav Bereza

  • 779 Posts
  • 166 Reply Likes
Some curves already has "corner option" (this is from layers style)

Photo of Cristen Gillespie

Cristen Gillespie

  • 1259 Posts
  • 323 Reply Likes
Yes, Adobe obviously has the knowledge to turn regular Curves into Corner Curves, but I can't see how accessing the Contour Curve in Layer Styles will do anything for the OP??? The HDR Toning Curve (Image > Adjustments > HDR Toning) can be used on ordinary image layers, so might be a workaround—far from ideal, but it is available.
Photo of Jaroslav Bereza

Jaroslav Bereza

  • 779 Posts
  • 166 Reply Likes
My Image is broken... it should be ok on this link: http://sklad.bereza.cz/00-jarda/00_screenshot/2016-09-08_174247.jpg
Photo of Cristen Gillespie

Cristen Gillespie

  • 1259 Posts
  • 323 Reply Likes
Yes, I knew that you meant the Contour editors. I suppose if the OP can use a layer style to create the image, it will be easier to get at than HDR Toning. Without seeing what the OP is using Curves on, it's hard to tell if there's a solution in either feature.
Photo of christoph pfaffenbichler

christoph pfaffenbichler, Champion

  • 1224 Posts
  • 172 Reply Likes
If someone wants to give it a try I made a script that offers a dialog for numeric entry of points for a »drawn« Curves Layer which calculates the points in between. 

// create curves layer drawn according to numeric input of pairs of integers;// 2016, use it at your own risk;  
#target photoshop
if (app.documents.length > 0) {
if (activeDocument.mode != DocumentMode.BITMAP && activeDocument.mode != DocumentMode.INDEXEDCOLOR && activeDocument.mode != DocumentMode.MULTICHANNEL) {
// determine which channels are present;
switch (activeDocument.mode) {
case DocumentMode.CMYK: 
var theResult = ["Cmps", "Cyn ", "Mgnt", "Yllw", "Blck"];
break;
case DocumentMode.RGB: 
var theResult = ["Cmps", "Rd  ", "Grn ", "Bl  "];
break;
case DocumentMode.LAB: 
var theResult = ["Lght", "A   ", "B   "];
break;
case DocumentMode.GRAYSCALE: 
var theResult = ["Gry "];
break;
default: 
break;
};
//filter for checking if entry is numeric, whole and positive, thanks to xbytor;
wholePosNumberKeystrokeFilter = function() {
if (this.text.match(/[^\-\.\d]/)) {
this.text = this.text.replace(/[^\-\.\d]/g, '');
};
if (this.text == "") {this.text = 0};
if (Number(this.text) < 0) {this.text = 0};
if (Number(this.text) > 255) {this.text = 255};
};
////////////////////////////////////
var width = (theResult.length * 130) + (15 * (theResult.length + 1));
////////////////////////////////////
var dlg = new Window('dialog', "draw curves layer", [500,300,(500+width),745]);
// create entry field for all channels;
var theX = 15;
for (var b = 0; b < theResult.length; b++) {
// entry-fields;
dlg.theNumbers = dlg.add('panel', [theX,15,theX+130,370], theResult[b]+"_in/out");
// 0;
dlg.theNumbers.number1b = dlg.theNumbers.add('statictext', [12,12,60,32], 0, {multiline:false});
dlg.theNumbers.number1 = dlg.theNumbers.add('edittext', [70,12,118,32], 0, {multiline:false});
dlg.theNumbers.number1.onChange = wholePosNumberKeystrokeFilter;
// additional values;
var vert = 42;
for (var a = 0; a < 9; a++) {
dlg.theNumbers.add('edittext', [12,vert,60,vert+20], "", {multiline:false});
dlg.theNumbers.children[dlg.theNumbers.children.length - 1].onChange = wholePosNumberKeystrokeFilter;
dlg.theNumbers.add('edittext', [70,vert,118,vert+20], "", {multiline:false});
dlg.theNumbers.children[dlg.theNumbers.children.length - 1].onChange = wholePosNumberKeystrokeFilter;
vert = vert+30;
};
// 255;
dlg.theNumbers.number255b = dlg.theNumbers.add('statictext', [12,312,60,332], 255, {multiline:false});
dlg.theNumbers.number255 = dlg.theNumbers.add('edittext', [70,312,118,332], 255, {multiline:false});
dlg.theNumbers.number255.onChange = wholePosNumberKeystrokeFilter;
theX = theX + 145
};
////////////////////////////////////
// buttons for ok, and cancel;
dlg.buttons = dlg.add('panel', [15,380,width-15,430], '');
var thisWidth = Math.round(width-30);
var theHalf = thisWidth/2-5;
dlg.buttons.buildBtn = dlg.buttons.add('button', [5,13,5+theHalf,33], 'OK', {name:'ok'});
dlg.buttons.cancelBtn = dlg.buttons.add('button', [thisWidth-5-theHalf,13,thisWidth-5,33], 'Cancel', {name:'cancel'});
// show the dialog;
dlg.center();
var myReturn = dlg.show ();
////////////////////////////////////
if (myReturn != 1) {}
else {
// get the arrays for the points;
var theArrays = new Array;
for (var x = 0; x < theResult.length; x++) {
theArrays.push(processChannelPanelEntries(dlg.children[x]))
};
// create curves layer;
createPenCurvesLayer (theArrays, theResult);
}
};
};
////// sort a double array, thanks to sam, http://www.rhinocerus.net/forum/lang-javascript/ //////
function sortArrayByIndexedItem(a,b) {
var theIndex = 0;
if (a[theIndex]<b[theIndex]) return -1;
if (a[theIndex]>b[theIndex]) return 1;
return 0;
};
////// process the entries for one channel //////
function processChannelPanelEntries (thePanel) {
var theX = new Array;
// collect the pairs from the dialog;
for (var d = 0; d < thePanel.children.length/2; d++) {
if (thePanel.children[d*2].text != "" && thePanel.children[d*2+1].text != "" ) {
theX.push([Number(thePanel.children[d*2].text), Number(thePanel.children[d*2+1].text)])
}
};
// sort according to the first value of each pair;
theX.sort(sortArrayByIndexedItem);
// remove mzltiple input values;
var theY = [theX[0]];
for (var e = 1; e < theX.length; e++) {
if (theY[theY.length - 1][0] != theX[e][0]) {
theY.push(theX[e])
}
};
return theY
};
////// calculate points //////
function calculateInBetweenPoints (theX) {
// new array for points;
var theArray = new Array;
// determine points between the defined ones;
for (var n = 0; n < theX.length-1; n++) {
var thisOne = theX[n];
var nextOne = theX[n + 1];
theArray.push(thisOne[1]);
// determine incline;
var theIncline = (nextOne[1] - thisOne[1]) / (nextOne[0] - thisOne[0]);
// add points;
for (var x = 1; x < (nextOne[0]-thisOne[0]); x++) {
theArray.push(Math.round(thisOne[1]+theIncline*x));
};
};
theArray.push(nextOne[1]);
return theArray
};
////// curves layer as drawn with pen //////
function createPenCurvesLayer (theValues, theNames) {
// =======================================================
var idMk = charIDToTypeID( "Mk  " );
    var desc2 = new ActionDescriptor();
    var idnull = charIDToTypeID( "null" );
        var ref1 = new ActionReference();
        var idAdjL = charIDToTypeID( "AdjL" );
        ref1.putClass( idAdjL );
    desc2.putReference( idnull, ref1 );
    var idUsng = charIDToTypeID( "Usng" );
        var desc3 = new ActionDescriptor();
        var idType = charIDToTypeID( "Type" );
            var desc4 = new ActionDescriptor();
            desc4.putEnumerated( stringIDToTypeID( "presetKind" ), stringIDToTypeID( "presetKindType" ), stringIDToTypeID( "presetKindCustom" ) );
        var idCrvs = charIDToTypeID( "Crvs" );
        desc3.putObject( idType, idCrvs, desc4 );
    desc2.putObject( idUsng, idAdjL, desc3 );
executeAction( idMk, desc2, DialogModes.NO );
// edit the curves layer:
var desc1 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putEnumerated(charIDToTypeID('AdjL'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
desc1.putReference(charIDToTypeID('null'), ref1);
var desc2 = new ActionDescriptor();
desc2.putEnumerated(stringIDToTypeID("presetKind"), stringIDToTypeID("presetKindType"), stringIDToTypeID("presetKindCustom"));
// if grayscale;
if (theNames.length == 1) {
var list1 = new ActionList();
var desc3 = new ActionDescriptor();
var ref2 = new ActionReference();
ref2.putEnumerated(charIDToTypeID('Chnl'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
desc3.putReference(charIDToTypeID('Chnl'), ref2);
var list2 = new ActionList();
// get points;
var theArray = calculateInBetweenPoints(theValues[0]);
for (var m = 0; m < 256; m++) {list2.putInteger(theArray[m])};
desc3.putList(charIDToTypeID('Mpng'), list2);
list1.putObject(charIDToTypeID('CrvA'), desc3);
}
// if rgb, lab or cmyk;
else {
var idsetd = charIDToTypeID( "setd" );
var idAdjs = charIDToTypeID( "Adjs" );
var list1 = new ActionList();
var idChnl = charIDToTypeID( "Chnl" );
////////////////////////////////////
for (var n = 0; n < theNames.length; n++) {
var desc7 = new ActionDescriptor();
var ref3 = new ActionReference();
var idCmps = charIDToTypeID( theNames[n] );
ref3.putEnumerated( idChnl, idChnl, idCmps );
desc7.putReference( idChnl, ref3 );
var idMpng = charIDToTypeID( "Mpng" );
var list2 = new ActionList();
// get points;
var theArray = calculateInBetweenPoints(theValues[n]);
for (var m = 0; m < 256; m++) {list2.putInteger(theArray[m])};
desc7.putList( idMpng, list2 );
var idCrvA = charIDToTypeID( "CrvA" );
list1.putObject( idCrvA, desc7 );
};
};
desc2.putList(charIDToTypeID('Adjs'), list1);
desc1.putObject(charIDToTypeID('T   '), charIDToTypeID('Crvs'), desc2);
executeAction(charIDToTypeID('setd'), desc1, DialogModes.NO);
};