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

[SCRIPTING] Issues modifying color of PathItem

Explorer ,
Jan 30, 2021 Jan 30, 2021

Copy link to clipboard

Copied

Hello community!

 

I have written a script to modify the saturation of certain colors in a PDF. I can click on PathItem elements and modify their fill and/or stroke color manually no issues whatsoever. However, when I run my script there seems to be some issues with the colors, because if I print the "filled" and "stroked" attributes I get "undefined" rather than true/false. Not sure what is causing this and would be super grateful if someone could help out.

Here is the PDF and you can see that there are PathItems with a fill:

PDF with PathITem.png

 

Here is the essential part of the code:

var paths = docRef.pathItems;
var modifier = 0.5;
$.writeln('Num paths: ' + paths.length); //There are 188
if(paths.length > 0) {
  for(i = 0; i < paths.length; i++) {
    var path = paths[i];
    //Always return undefined for both values
    $.writeln('Filled: ' + path.filled + ", Stroked: " + path.stroked); 

    //This is never the case, it nevers executes the code within this if
    if (path.filled === true) {
      $.writeln('Test 2'); 
      var hsvColfill = rgb2hsv(path.fillColor.red, path.fillColor.green, path.fillColor.blue);
      var newSfill = hsvColfill.s + (Math.random()*2-1)*modifier*100;
      $.writeln('Saturation Pre: ' + hsvColfill.s + ", Post: " + newSfill);
      if (newSfill >100) {newSfill = 100;}else if (newSfill < 0) {newSfill = 0;};
      path.fillColor = new RGBColor(hsv2rgb(hsvColfill.h, newSfill, hsvColfill.v));

    //This is never the case, it nevers executes the code within this if
    } else if(path.stroked === true) {
      $.writeln('Test 3'); 
      var hsvColstroke = rgb2hsv(path.fillColor.red, path.fillColor.green, path.fillColor.blue);
      var newSstroke = hsvColstroke.s + (Math.random()*2-1)*modifier*100;
      $.writeln('Saturation Pre: ' + hsvColstroke.s + ", Post: " + newSstroke);
      if (newSstroke >100) {newSstroke = 100;}else if (newSstroke < 0) {newSstroke = 0;};
      path.fillColor = new RGBColor(hsv2rgb(hsvColstroke.h, newSstroke, hsvColstroke.v));
    }
  }
}

The important part is that there seems to be no colors to manipulate.

 

Find the PDF attached in case you want to do some further investigating.

 

Thank you everyone 🙂

TOPICS
Scripting

Views

485

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

Guide , Jan 30, 2021 Jan 30, 2021

The word "path" is an app property referring to the file path of the app.  Call your variable something else, e.g.

 

var path1 = paths[i];

 

Votes

Translate

Translate
Adobe
Guide ,
Jan 30, 2021 Jan 30, 2021

Copy link to clipboard

Copied

The word "path" is an app property referring to the file path of the app.  Call your variable something else, e.g.

 

var path1 = paths[i];

 

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
Explorer ,
Feb 02, 2021 Feb 02, 2021

Copy link to clipboard

Copied

Hello again,

 

Sorry for the alte answer, but some new issues popped up and I wanted to go through them before posting about it further here. As both you and @Charu Rajput pointed out, the variable name "path" is reserved and i could not use it. Thanks a lot for that, it solved my problem, however I was still not able to solve my ultimate goal, which was to saturate the image.

 

Let me tell you how I did it. I found some scripts made by other people to convert from RGB to HSL / HSV and vice versa. I used these functions in order to translate the RGB color of the PathItem elements into HSL and then adding 20% to the saturate variable. I then translated back to RGB. Seems like it does something at least, because the colours are updated, but not the way they should be (like the Edit --> Edit Colors --> Saturate function in Illustrator). 

 

The code is essentially this:

 

var paths = docRef.pathItems;
var modifier = 0.2;
$.writeln('Num paths: ' + paths.length); //There are 188
if (paths.length > 0) {
    for (i = 0; i < paths.length; i++) {
        var _path = paths[i];
        $.writeln('Path color Pre: [' + _path.fillColor.red + ", " + _path.fillColor.green + ", " + _path.fillColor.blue + "]");
        if (_path.filled === true) {
            
            var hsvColfill = rgb2hsv(_path.fillColor.red/255, _path.fillColor.green/255, _path.fillColor.blue/255);

            var newSfill2 = hsvColfill[1] * (1 + modifier);
            $.writeln('hsv values: [' + hsvColfill[0] + ", " + hsvColfill[1] + ", " + hsvColfill[2] + "]");

            if (newSfill2 > 100) { newSfill2 = 100; } else if (newSfill2 < 0) { newSfill2 = 0; };  
            if(newSfill2 < 20) { newSfill2 = newSfill2 + 20 };

            var checkers2 = hsv2rgb(hsvColfill[0], newSfill2, hsvColfill[2]);
            $.writeln('Function2 returns: [' + checkers2[0] + ", " + checkers2[1] + ", " + checkers2[2] + "]");
            
            var newColor = new RGBColor();
            _path.fillColor.red = checkers2[0];
            _path.fillColor.green = checkers2[1];
            _path.fillColor.blue = checkers2[2];      
            
        }
    }
}

/**
* Converts an RGB color value to HSL. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes r, g, and b are contained in the set [0, 255] and
* returns h, s, and l in the set [0, 1].
*
* @param   {number}  r       The red color value
* @param   {number}  g       The green color value
* @param   {number}  b       The blue color value
* @return  {Array}           The HSL representation
*/
function rgbToHsl(r, g, b){
	r /= 255, g /= 255, b /= 255;
	var max = Math.max(r, g, b), min = Math.min(r, g, b);
	var h, s, l = (max + min) / 2;

	if(max == min){
			h = s = 0; // achromatic
	}else{
			var d = max - min;
			s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
			switch(max){
					case r: h = (g - b) / d + (g < b ? 6 : 0); break;
					case g: h = (b - r) / d + 2; break;
					case b: h = (r - g) / d + 4; break;
			}
			h /= 6;
	}

	return [h, s, l];
}

/**
 * Converts an HSL color value to RGB. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes h, s, and l are contained in the set [0, 1] and
 * returns r, g, and b in the set [0, 255].
 *
 * @param   {number}  h       The hue
 * @param   {number}  s       The saturation
 * @param   {number}  l       The lightness
 * @return  {Array}           The RGB representation
 */
function hslToRgb(h, s, l){
  var r, g, b;

  if(s == 0){
      r = g = b = l; // achromatic
  }else{
      var hue2rgb = function hue2rgb(p, q, t){
          if(t < 0) t += 1;
          if(t > 1) t -= 1;
          if(t < 1/6) return p + (q - p) * 6 * t;
          if(t < 1/2) return q;
          if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
          return p;
      }

      var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
      var p = 2 * l - q;
      r = hue2rgb(p, q, h + 1/3);
      g = hue2rgb(p, q, h);
      b = hue2rgb(p, q, h - 1/3);
  }

  return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}

The result I get is more or less this, first is the orginal PDF, second is the updated one:

first.png

second.png

I finally found a solution by using actions which I found in a thread by @Silly-V and that actually works. The code is this:

app.executeMenuCommand("selectall"); 
//app.executeMenuCommand("ungroup");

var f = File("C:/originalpeople/Winetumbler/My Actions.aia");

f.open('w');

var actionString = "/version 3 /name [ 10 4d7920416374696f6e73 ] /isOpen 1 /actionCount 1 /action-1 { /name [ 14 4164642053617475726174696f6e ]" +
	"/keyIndex 0 /colorIndex 0 /isOpen 0 /eventCount 1 /event-1 { /useRulersIn1stQuadrant 0 /internalName (ai_plugin_saturate) /localizedName [ 8 5361747572617465 ]" + 
		"/isOpen 0 /isOn 1 /hasDialog 1 /showDialog 0 /parameterCount 1 /parameter-1 { /key 1768846446 /showInPalette -1 /type (real) /value 30.0 } } }"

f.write(actionString);

f.close();

app.doScript("Add Saturation", "My Actions");

app.unloadAction("My Actions", "");

 

The result is this:

third.png

It works, but I don't love having to use file paths because I need this solution to work across multiple devices. Any ideas by anyone how I might solve this neatly?

 

Thank you very much!

 

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
Explorer ,
Feb 04, 2021 Feb 04, 2021

Copy link to clipboard

Copied

Hello again,

 

After doing some investigation of my own I ultimately became a bit wiser. The script does what it is supposed to, just that my saturation formula is different from the "Edit --> Edit Colors --> Saturate" function. The greys are turning yellowish because I saturate from 1% to around 21% whereas illustrator saturates from 1% to around 1.4%. This is because I saturate like this: NewS = OldS + (1 - OldS)/3, and illustrator does it like this: NewS = OldS * 1.x (x being the percentage you wish to saturate by).

 

Moreover, I was working with a HSL --> RGB and vice versa function, it's better to use HSB/HSV -->  RGB and vice versa because the saturation will depend on which you pick. If you edit the color of any PathItem in illustrator manually it will show you RGB and HSB, so use that rather than HSL.

 

Here's the working code for saturating every PathItem in the document:

var paths = docRef.pathItems;
var modifier = 0.3;
$.writeln('Num paths: ' + paths.length); //There are 188

if (paths.length > 0) {
    for (i = 0; i < paths.length; i++) {
        var _path = paths[i];
        if (_path.fillColor && _path.filled) {
            
            var hslColfill = rgbToHsv(_path.fillColor.red, _path.fillColor.green, _path.fillColor.blue);
            var newSfill = hslColfill[1] + (1 - hslColfill[1])/3;
            
            if(newSfill > 1) { newSfill = 1; } else if (newSfill < 0) { newSfill = 0; };  
            if(newSfill < 0.2) { newSfill = newSfill + 0.2 };

            $.writeln('hsv fill values: [' + hslColfill[0] + ", " + newSfill + ", " + hslColfill[2] + "]");

            var newRGBfill = hsvToRgb(hslColfill[0], newSfill, hslColfill[2]);
            $.writeln('Function returns fill: [' + newRGBfill[0] + ", " + newRGBfill[1] + ", " + newRGBfill[2] + "]");
            
            _path.fillColor.red = newRGBfill[0];
            _path.fillColor.green = newRGBfill[1];
            _path.fillColor.blue = newRGBfill[2];      
        }

        if (_path.strokeColor && _path.stroked) {

            var hslColstroke = rgbToHsv(_path.strokeColor.red, _path.strokeColor.green, _path.strokeColor.blue);
            var newSstroke = hslColstroke[1] + (1 - hslColstroke[1])/3;

            if (newSstroke > 1) { newSstroke = 1; } else if (newSstroke < 0) { newSstroke = 0; };

            $.writeln('hsv stroke values: [' + hslColstroke[0] + ", " + newSstroke + ", " + hslColstroke[2] + "]");

            var newRGBstroke = hsvToRgb(hslColstroke[0], newSstroke, hslColstroke[2]);
            $.writeln('Function returns stroke: [' + newRGBstroke[0] + ", " + newRGBstroke[1] + ", " + newRGBstroke[2] + "]");

           _path.strokeColor.red = newRGBstroke[0];
           _path.strokeColor.green = newRGBstroke[1];
           _path.strokeColor.blue = newRGBstroke[2];    
        }
    }
}

 

It works fine, however the saturation does change the color, e.g. the grey becomes yellowish. I would ideally like to intensify the colors without modifying them too much. Any ideas on how to achieve this? Will continue digging and post if I find a neater solution.

 

Thanks!

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
Guide ,
Feb 04, 2021 Feb 04, 2021

Copy link to clipboard

Copied

Sorry. I don't know anything about saturation/HSL/HSV and won't be able to help you with this.  

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
Explorer ,
Feb 08, 2021 Feb 08, 2021

Copy link to clipboard

Copied

LATEST

Not to worry, the solution above basically works for me already. Essentially, if you or anyone else is interested, it is better to work with HSB if you want to just change the intensity of the colors without modifying the colors themselves very much. I increment saturation for colors to make them stronger and decrease B (blackness) for greys to become stronger. 

You can use the two functions above to change between RGB and HSB freely, so that you can modify any value you wish. Just letting you know so that you can point back to this thread if you encounter any similar doubts in the future.

Thanks a lot for all the useful help @femkeblanco 

 

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 ,
Jan 30, 2021 Jan 30, 2021

Copy link to clipboard

Copied

As specified by femkeblanco, path is alreday defined property. Try 

docRef = app.activeDocument;
var paths = docRef.pathItems;
var modifier = 0.5;
$.writeln('Num paths: ' + paths.length); //There are 188
if (paths.length > 0) {
    for (i = 0; i < paths.length; i++) {
        var _path = paths[i];
        //Always return undefined for both values
        $.writeln('Filled: ' + _path.filled + ", Stroked: " + _path.stroked);

        //This is never the case, it nevers executes the code within this if
        if (_path.filled === true) {
            $.writeln('Test 2');
            var hsvColfill = rgb2hsv(_path.fillColor.red, _path.fillColor.green, _path.fillColor.blue);
            var newSfill = hsvColfill.s + (Math.random() * 2 - 1) * modifier * 100;
            $.writeln('Saturation Pre: ' + hsvColfill.s + ", Post: " + newSfill);
            if (newSfill > 100) { newSfill = 100; } else if (newSfill < 0) { newSfill = 0; };
            _path.fillColor = new RGBColor(hsv2rgb(hsvColfill.h, newSfill, hsvColfill.v));

            //This is never the case, it nevers executes the code within this if
        } else if (_path.stroked === true) {
            $.writeln('Test 3');
            var hsvColstroke = rgb2hsv(_path.fillColor.red, _path.fillColor.green, _path.fillColor.blue);
            var newSstroke = hsvColstroke.s + (Math.random() * 2 - 1) * modifier * 100;
            $.writeln('Saturation Pre: ' + hsvColstroke.s + ", Post: " + newSstroke);
            if (newSstroke > 100) { newSstroke = 100; } else if (newSstroke < 0) { newSstroke = 0; };
            _path.fillColor = new RGBColor(hsv2rgb(hsvColstroke.h, newSstroke, hsvColstroke.v));
        }
    }
}

 

Best regards

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