Color change with color balance

In JavaScript, I can adjust the color balance of an image using a function like

colorBalanceLayer(-50,0,0)

function colourBalanceLayer(cya, mag, yel)
{
  // cyan, magenta, yellow values are between -100 & +100
    var id713 = charIDToTypeID( "ClrB" );
    var desc162 = new ActionDescriptor();
    var id714 = charIDToTypeID( "ShdL" );
    var list37 = new ActionList();
    list37.putInteger( 0 );
    list37.putInteger( 0 );
    list37.putInteger( 0 );
    desc162.putList( id714, list37 );
    var id715 = charIDToTypeID( "MdtL" );
    var list38 = new ActionList();
    list38.putInteger( cya );
    list38.putInteger( mag );
    list38.putInteger( yel );
    desc162.putList( id715, list38 );
    var id716 = charIDToTypeID( "HghL" );
    var list39 = new ActionList();
    list39.putInteger( 0 );
    list39.putInteger( 0 );
    list39.putInteger( 0 );
    desc162.putList( id716, list39 );
    var id717 = charIDToTypeID( "PrsL" );
    desc162.putBoolean( id717, true );
    executeAction( id713, desc162, DialogModes.NO );
}

      

This works great and my example adds blue to the midtones of the image. What I want to know is this: If I wanted to change the RGB color with a similar -50 cyan value (as in the example above), how would I do it? It would be better to change the color to CMKY, adjust it accordingly, and then switch back to RGB. Only I read somewhere that it is best to go from RGB to L * ab first (which I know how to do).

+3


source to share


2 answers


If you want to use this feature in RGB colors, you need to convert them to CMY as it is colorBalanceLayer

designed to work with CMY colors. It can be easily accomplished with the following function:

// r, g, b and c, m, y are in the range of 0 to 255

function rgb_cmy(r, g, b) {
    return [].map.call(arguments, function(v) {return 255 - v;});
}

// return value is an array of the form: [cyan, magenta, yellow]

      

After processing, convert back to RGB using the same function:

rgb_cmy(c, m, y) // returns an array of the form: [red, green, blue]

      

Should we convert to L * ab as an intermediate step? Not.

RGB and CMY are two different color spaces with the same size: this means both contain the same number of colors. But both spaces don't exactly overlap. This means: RGB contains some colors that cannot be accurately expressed as CMY color, and vice versa. Therefore, each transformation may introduce some inaccuracy.

The L * ab color space is much larger than the others and completely covers RGB and CMY. This means that every RGB (or CMY) color can be accurately expressed as an L * ab color, but there are many L * ab colors that do not display in RGB or CMY.

Having an RGB color that does not exactly match CMY occurs:

RGB --inaccurate--> CMY --inaccurate--> RGB // output !== input
RGB --accurate--> L*ab --inaccurate--> CMY --accurate--> L*ab --inaccurate--> RGB

      



We see that the same inaccuracies have been introduced.

EDIT Inside colorBalanceLayer

you are calling some other functions. I don't see what exactly they are doing, so I can only give the following as a draft.

It is of course possible to change cyan, magenta, or yellow within RGB without conversion. To do this, we need to know two things:

1) CMY works with printed pigments, RGB with emitted light, so they complement brightness. This means: adding some value to CMY makes the color darker, adding some value to RGB makes it brighter.

2) RGB and CMY color wheels rotated 60 degrees so they complement colors. This means that the opposite colors of both form additional cyan / red, magenta / green and yellow / blue pairs.

Thus, the following operations lead to identical results (CMY left-, RGB right-hand):

cyan += 20   ===   red -= 20;
magenta  -= 30   ===   green += 30;
yellow += 40   ===   blue -= 40;

      

You might be able to tweak your functions to work with RGB.

+3


source


To answer my own question, it is possible to return the value of a "balanced" color. This is not an elegant solution:



colourBalanceLayer("C0FFEE", 100,0,0);

function colourBalanceLayer(hexcol, cya, mag, yel)
{

  var pixH = 10;
  var pixV = 10;

  // create a document to work with
  var docRef = app.documents.add(pixH *2, pixV *2, 72, "colours")
  var newDoc = app.activeDocument;

  // =======================================================
  var id70 = charIDToTypeID( "Fl  " );
  var desc18 = new ActionDescriptor();
  var id71 = charIDToTypeID( "From" );
  var desc19 = new ActionDescriptor();
  var id72 = charIDToTypeID( "Hrzn" );
  var id73 = charIDToTypeID( "#Pxl" );
  desc19.putUnitDouble( id72, id73, 10.000000 );
  var id74 = charIDToTypeID( "Vrtc" );
  var id75 = charIDToTypeID( "#Pxl" );
  desc19.putUnitDouble( id74, id75, 9.000000 );
  var id76 = charIDToTypeID( "Pnt " );
  desc18.putObject( id71, id76, desc19 );
  var id77 = charIDToTypeID( "Tlrn" );
  desc18.putInteger( id77, 32 );
  var id78 = charIDToTypeID( "AntA" );
  desc18.putBoolean( id78, true );
  var id79 = charIDToTypeID( "Usng" );
  var id80 = charIDToTypeID( "FlCn" );
  var id81 = charIDToTypeID( "FrgC" );
  desc18.putEnumerated( id79, id80, id81 );
  executeAction( id70, desc18, DialogModes.NO );

  // cyan, magenta, yellow values are between -100 & +100
  var id713 = charIDToTypeID( "ClrB" );
  var desc162 = new ActionDescriptor();
  var id714 = charIDToTypeID( "ShdL" );
  var list37 = new ActionList();
  list37.putInteger( 0 );
  list37.putInteger( 0 );
  list37.putInteger( 0 );
  desc162.putList( id714, list37 );
  var id715 = charIDToTypeID( "MdtL" );
  var list38 = new ActionList();
  list38.putInteger( cya );
  list38.putInteger( mag );
  list38.putInteger( yel );
  desc162.putList( id715, list38 );
  var id716 = charIDToTypeID( "HghL" );
  var list39 = new ActionList();
  list39.putInteger( 0 );
  list39.putInteger( 0 );
  list39.putInteger( 0 );
  desc162.putList( id716, list39 );
  var id717 = charIDToTypeID( "PrsL" );
  desc162.putBoolean( id717, true );
  executeAction( id713, desc162, DialogModes.NO );

  // =======================================================
  var id40 = charIDToTypeID( "setd" );
  var desc11 = new ActionDescriptor();
  var id41 = charIDToTypeID( "null" );
  var ref5 = new ActionReference();
  var id42 = charIDToTypeID( "Clr " );
  var id43 = charIDToTypeID( "FrgC" );
  ref5.putProperty( id42, id43 );
  desc11.putReference( id41, ref5 );
  var id44 = charIDToTypeID( "T   " );
  var desc12 = new ActionDescriptor();
  var id45 = charIDToTypeID( "Rd  " );
  desc12.putDouble( id45, 255.000000 );
  var id46 = charIDToTypeID( "Grn " );
  desc12.putDouble( id46, 255.000000 );
  var id47 = charIDToTypeID( "Bl  " );
  desc12.putDouble( id47, 255.000000 );
  var id48 = charIDToTypeID( "RGBC" );
  desc11.putObject( id44, id48, desc12 );
  executeAction( id40, desc11, DialogModes.NO );

  var selRegion = null;
  selRegion = Array(Array(pixH, pixV),
  Array(pixH + 1, pixV),
  Array(pixH + 1, pixV + 1),
  Array(pixH, pixV + 1),
  Array(pixH, pixV));
  newDoc.selection.select(selRegion);
  var histR = newDoc.channels.getByName("Red").histogram;
  var histG = newDoc.channels.getByName("Green").histogram;
  var histB = newDoc.channels.getByName("Blue").histogram;
  var returnColor = new RGBColor();

  for (iHistR in histR)
  {
  if (histR[iHistR]!=0)
    {
      returnColor.red = iHistR;
    }
  }
  for (iHistG in histG)
  {
  if(histG[iHistG]!=0)
    {
      returnColor.green = iHistG;
    }
  }
  for (iHistB in histB)
  {
    if(histB[iHistB]!=0)
    {
      returnColor.blue = iHistB;
    }
  }

  alert(returnColor.red+","+returnColor.green+","+returnColor.blue);

  return returnColor;
}

      

0


source







All Articles