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:
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 🙂
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];
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];
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:
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:
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!
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!
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.
Copy link to clipboard
Copied
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
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));
}
}
}