femkeblanco
Guide
femkeblanco
Guide
Activity
‎Dec 29, 2023
12:09 AM
I thank you very much Femke and Kurt for the script ! But I think I will use the existing polar grid tool that is perfect for my use.
... View more
‎Dec 27, 2023
11:04 PM
2 Upvotes
UV is aggressive with links. If you want to attach a link to a sample script or an article about a problem. I lost my account there once because the system banned me as a spammer. Reports posted from that account became anonymous. And no one at Adobe can restore the account because it is a third-party platform. I had to create a new account on UV, and now I'm afraid to post something unnecessary there and get banned again. Ugh!
... View more
‎Dec 26, 2023
12:55 PM
hey everybody. my sincere apologies for the delay. i got busy, and then i forgot.
Heres the workaround code to make a request to some website from illustrator (or theoretically, any other adobe software that doesnt offer a native solution). Warning, this was purpose built for my purposes quite a while ago and i havent bothered updating it since its working for me, so it likely needs tweaks and is definitely pretty messy. and it might have some dependencies from my own utilities, but those are generic and easy.
for my needs, i have a single URL and i just paste in an identifier (order number or something) to the end of the URL and that gives me the data i need. If you are accessing data from some public API that requires credentials to be sent with the payload, im not exactly sure how to manage that. but hopefully this mess helps point someone in the right direction.
//curl data from a specified url and return the data as an anonymous object
function curlData ( url, arg )
{
var result, status = "empty";;
var htmlRegex = /<html>/gmi;
var scriptText,
scriptFile,
executor,
killExecutor;
url = url + arg;
//variables for the local data stuff
var documentsPath = "path/to/documents/folder/"
var curlDataPath = documentsPath + "curlData/"
var curlDataFolder = new Folder( curlDataPath );
if ( !curlDataFolder.exists )
{
curlDataFolder.create();
}
var localDataFile = File( curlDataPath + "curlData.txt" );
//clear out the local data file..
//make sure we always start with an empty string
localDataFile.open( "w" );
localDataFile.write( "" );
localDataFile.close();
if ( $.os.match( "Windows" ) )
{
//write the bat file that will be
//used to execute the vbs script
writeVbsFile();
//define the executor script
//cscript.exe runs the .vbs file as though the CL is being used
scriptText = "cscript.exe \"";
//path to vbs script
scriptText += curlDataPath + "socket_xhttpRequest.vbs\"";
//vbs argument 1 = url
scriptText += " \"" + url + "\" \"";
//vbs argument 2 = path to curlData.txt file
scriptText += curlDataPath + "curlData.txt";
scriptFile = File( curlDataPath + "batFile.bat" );
writeScriptFile( scriptFile, scriptText )
executor = scriptFile;
}
else
{
scriptText = [
"do shell script ",
"\"curl \\\"" + url,
"\\\" > \\\"",
curlDataPath + "curlData.txt" + "\\\"\""
].join( "" );
/
scriptFile = File( curlDataPath + "curl_from_illustrator.scpt" );
writeScriptFile( scriptFile, scriptText );
executor = File( resourcePath + "curl_from_illustrator.app" );
var localExecutor = File( documentsPath + "curlData/curl_from_illustrator.app" );
if ( localExecutor.exists )
{
executor = localExecutor;
}
}
var maxExecutorCalls = 5;
var currentExecutorCalls = 0;
var checkDelay = 200;
var numberOfChecks = 200;
var totalChecks = 0;
var parseFailResults = 0;
do
{
totalChecks = 0;
//go get the data
executor.execute();
//check the data
for ( var a = 0; a < numberOfChecks && status !== "valid"; a++ )
{
if ( status != "valid" )
{
checkData()
totalChecks++;
}
else if ( status === "html" )
{
break;
}
$.sleep( checkDelay );
}
}
while ( status !== "valid" && status !== "html" && currentExecutorCalls < maxExecutorCalls );
//validate
if ( status === "html" || ( status === "empty" && parseFailResults.length ) )
{
alert( "The request to \"" + url + arg + "\" returned invalid data for " + arg );
}
return result;
function readDataFile ()
{
var file = localDataFile;
file.open( "r" );
var contents = file.read();
file.close();
return contents;
}
function writeScriptFile ( file, txt )
{
file.open( "w" );
file.write( txt );
file.close();
}
function writeVbsFile ()
{
//go to the network and copy the contents of the
//socket_xhttpRequest.vbs file
//this allows me to manage updates by updating a
//single central file, but each person will be executing
//their own copy, which should avoid someone being denied
//access because another person is already executing the file?
//central file
var srcFile = File( dataPath + "socket_xhttpRequest.vbs" );
//local file
var destFile = File( curlDataPath + "socket_xhttpRequest.vbs" );
//read the source file's contents
srcFile.open( "r" );
var srcContents = srcFile.read();
srcFile.close();
//write the contents to the local file
writeDatabase( destFile, srcContents );
}
function checkData ()
{
var contents = readDataFile();
if ( contents === "" )
{
status = "empty";
}
else if ( contents.match( htmlRegex ) )
{
status = "html";
}
else
{
try
{
result = JSON.parse( contents );
status = "valid";
}
catch ( e )
{
status = "parseFail";
parseFailResults++;
}
}
}
}
... View more
‎Dec 26, 2023
07:35 AM
I have made my graphic and selected it, then I have done "File/Export the selection" and would like to export my selection in SVG : Is it possible to export the selection with a little margin that I could set ? How to set this margin ?
... View more
‎Dec 26, 2023
02:47 AM
I hope you don't mind me piggybacking on this post because my question is very similar. I'm making a card game for my students, and the card text is linked to a CSV using variables. In my Illustrator file, I have a rectangle with a stroke (and no fill) as the card border (let's call this "border"), and another rectangle with a fill (and no stroke) as the card title background (let's call this "background"). I want these colours to be determined by the variable called "CONTINENT", which also determines the card title text (i.e. "Europe", "Asia", "Africa", "Americas", "Oceania"), and to be interpreted as specific CMYK values. I've tried my hand at modifying your script, but I'm a complete novice when it comes to Illustrator scripting (and to JS in general), so I don't really know what I'm doing. (TBH, I don't even know how to run the script in Illustrator.) I'd be very grateful if you could lend your support. // Store all our colors in a global object with key values matching CONTINENT names:
var continents = {
Europe: createCMYK(100, 40, 0, 0),
Americas: createCMYK(0, 95, 90, 0),
Africa: createCMYK(0, 0, 0, 100),
Asia: createCMYK(0, 35, 100, 0),
Oceania: createCMYK(100, 0, 100, 0)
}
// Create a simple utility function to allow us to more easily make CMYK colors:
function createCMYK(cyan, magenta, yellow, black) {
var temp = new CMYKColor();
temp.cyan = cyan;
temp.magenta = magenta;
temp.yellow = yellow;
temp.black = black;
return temp;
}
// Now we dynamically retreive all our key CONTINENT names:
var keys = [];
for (var key in continents) keys.push(key);
// And create a RegEx to check them:
var continentRX = new RegExp("^(" + keys.join("|") + ")$");
// Equivalent to /^(Europe|Americas|Asia|Oceania|Africa)$/
// TJWD note: I'm really not sure how to modify this part...
function setCustomCrop() {
var aDoc = app.activeDocument;
var selMask = selection[0];
customCrop = selMask.name;
var CropGroup = aDoc.groupItems['CropGroup'];
var myItem = CropGroup.pageItems;
var myMask = myItem[customCrop];
myMask.locked = false;
// If the name matches our RegEx above:
if (maskRX.test(selMask.name))
selMask.fillColor = continents[selMask.name]
// ^ We use the name to match the color from our continents variable
}
... View more
‎Dec 25, 2023
12:23 PM
Oh I see, still many thanks to both of you ☺ As of now, it isn't tragic, would simply have been an additional nice to have. However, I edited the setAllThings script from Wundes to copy all four transform settings (x,y, width, height) of a specific object / layer to all other selected one's. This anyway, isn't a use case I encounter very often, therefore I am fine that I at least orientate myself on the most upper layer as the origin for the transform values to be copied. Many thanks to all answerers and Merry Christmas 🎅
... View more
‎Dec 22, 2023
08:57 AM
Thanks guys, this works beautifully!
... View more
‎Dec 19, 2023
12:26 PM
can you see this file? https://drive.google.com/file/d/1TubLY0-FSlyRZcUpEqq3Epu7k0okli-J/view?usp=sharing https://drive.google.com/file/d/1nReX0nNQ5HL4wBHtBoRLUluGkJlzKGiP/view?usp=sharing
... View more
‎Dec 08, 2023
08:06 AM
Wow, this is really neat. Unfortunately, my implementation of this requires very high accuracy. The script I am working on divides paths that are used to cut fabric on an industrial cutting machine. It essentially allows the user to draw a line across a cut shape and then splits the shape and includes the necessary overlap between the two panels. A lot of times these cut paths are in 10th scale so a very slight shift in the decimal point would mean a drastic shift in the cut shape at full scale.
... View more
‎Dec 05, 2023
12:14 PM
yes please
... View more
‎Dec 05, 2023
01:23 AM
1 Upvote
Thank you for the tip! This script below worked. function calculateArea(pathItem) { var area = 0; // Check if the pathItem has a fill color if (pathItem.filled) { // Get the color of the fill var fillColor = pathItem.fillColor; // Check if the fill color is a solid color if (fillColor instanceof RGBColor || fillColor instanceof CMYKColor || fillColor instanceof GrayColor) { // Calculate the area of the pathItem area += pathItem.area; } } return area; } function calculateTotalArea() { var doc = app.activeDocument; var totalArea = 0; // Loop through all page items in the document for (var i = 0; i < doc.pageItems.length; i++) { var currentItem = doc.pageItems[i]; totalArea += calculateArea(currentItem); } // Display the total area alert("Total Fill Color Area: " + totalArea.toFixed(2) + " square units"); } calculateTotalArea();
... View more
‎Dec 01, 2023
03:47 AM
Yeah @Jeffosaure, your Regex is definitely working! Excellent!
By the way, you can also write it like this:
/<\/?(i|b|a|p|br|strong|em)>
I put the options i, b, a, p, br, strong and em into parenthesis (called a capture group) which, in this case just serves to contain the options (without the parentheses, it would match <\/?i as the first option and b as the second, etc.).
- Mark
... View more
‎Nov 27, 2023
06:21 PM
Call the script and select the folder containing the PDF. Delete the object based on its location. If this does not seem to work, try changing the value of [Parameters] in the script. How does it work? //Parameters
iheader_px = 80
ifooter_px = 80
iheader_margin = 20
ifooter_margin = 20
//
sFileType = "pdf"
main();
function main(){
coordinateSystemOrg = app.coordinateSystem;
try{
app.coordinateSystem = CoordinateSystem.ARTBOARDCOORDINATESYSTEM;
folderRef = Folder.selectDialog("Select Folder");
if( folderRef != false){
fileList = folderRef.getFiles("*." + sFileType)
if( fileList != false){
ifl = fileList.length
for (var i=0;i<ifl;i++){
fileObj = new File(fileList[i].fsName);
app.userInteractionLevel=UserInteractionLevel.DONTDISPLAYALERTS;
open(fileObj);
app.userInteractionLevel=UserInteractionLevel.DISPLAYALERTS;
oDoc = app.activeDocument;
iwidth = oDoc.artboards[0].artboardRect[2]-oDoc.artboards[0].artboardRect[0]
iheight = oDoc.artboards[0].artboardRect[3]-oDoc.artboards[0].artboardRect[1]
hx1 = 0;
hy1 = 0;
hx2 = iwidth;
hy2 = iheader_px + iheader_margin;
fx1 = 0
fy1 = -(iheight + ifooter_px + ifooter_margin);
fx2 = iwidth;
fy2 = -iheight;
opg = oDoc.pageItems
ipg = opg.length
for( j=ipg-1;j>-1;j--){
if(checkinout(opg[j])){
try{
opg[j].remove()
}catch(e){;
};
};
};
oDoc.close(SaveOptions.SAVECHANGES);
oDoc = null
};
};
};
app.coordinateSystem = coordinateSystemOrg;
}catch(e){;
app.coordinateSystem = coordinateSystemOrg;
};
}
function checkinout(obj){
if (obj.geometricBounds){
var x1 = obj.geometricBounds[0];
var y1 = -obj.geometricBounds[1];
var x2 = obj.geometricBounds[2];
var y2 = -obj.geometricBounds[3];
if (x1 > hx1 && x2 < hx2 && y1 > hy1 && y2 < hy2)
return true
else{
if (x1 > fx1 && x2 < fx2 && y1 > fy1 && y2 < fy2)
return true
else{
return false
}
}
}
}
... View more
‎Nov 26, 2023
10:26 AM
Wow this is amazing thank you
... View more
‎Nov 21, 2023
02:29 AM
Yes I suspect you are right, Jacob. Truly the project has now lost much of its appeal. Haha.
... View more
‎Nov 20, 2023
02:50 PM
I had this once. Restarting the PC solved it.
... View more
‎Nov 19, 2023
03:13 AM
2 Upvotes
Below is a simple script for a grid of random symbols. It's a slow running script, so I've limited the number of symbols to 1000. Remove the limit by deleting line 2. Randomly distributed spacing may be achieved with a more complex script. (200 * 200 mm artboard.) var limit;
limit = Math.sqrt(1000);
var size = 12; // font (cell) size
var doc = app.activeDocument;
var num_x = doc.width / size;
var num_y = doc.height / size;
if (limit && num_x > limit) num_x = limit;
if (limit && num_y > limit) num_y = limit;
var x = size;
for (var i = 0; i < num_x - 1; i++) {
var y = - size;
for (var j = 0; j < num_y - 1; j++) {
var min = 32;
var max = 127;
var n = Math.floor(Math.random() * (max - min + 1)) + min;
var text = doc.textFrames.pointText( [x, y] );
text.contents = String.fromCharCode(n);
text.textRange.textFont = textFonts["TimesNewRomanPSMT"];
text.textRange.size = size;
text.textRange.justification = Justification.CENTER;
text.rotate(-90);
y = y - size;
}
x = x + size;
}
... View more
‎Nov 15, 2023
08:30 PM
My previous code has a flaw because if one paragraph does not fit in a line and is wrapped to next lines, lines will be added to the textFrame.lines without being any newline character in the original text. The solution is to first count characters of all lines as before; then removing every carriage return in the full text and counting the remaining charactes in it; then comparing two numbers. Note that as far as I have tested, Illustrator uses carriage return (\r) to separate paragraphs. I use Illustrator on Windows 10. I used a regular expression to remove the carriage return characters. Updated version of my code: function is_text_overflow(text){
var char_count_lines = 0;
var text_without_cr = text.textRange.contents.replace(/\r/g,"");
for(var i = 0; i < text.lines.length; i++)
char_count_lines += text.lines[i].contents.length;
return text_without_cr.length != char_count_lines;
}
... View more
‎Nov 14, 2023
07:24 PM
1 Upvote
@LoveYou阿逗逼6666, you could try something like this:
var doc = app.open(File(File($.fileName).parent + '/SUPPLIED/test.ai'));
var text = doc.layers[0].textFrames[0].textRange;
text.paragraphStyles[0].clear();
text.contents = "عنب كرز";
but it is actually altering the Paragraph Style and I think it might mess up your text. In my test, it changed the arabic—probably because of a setting needed in the style that I cleared. If you know the settings needed, we can set those with the script though.
If that doesn't help, the final thing would be to have your script apply a correct paragraph style. It often becomes important to fixing bad paragraph styles because of these kinds of problems.
- Mark
... View more
‎Nov 13, 2023
02:42 AM
Copy and paste the code to a .jsx file. (You can create a .txt file and change the extension to .jsx.) Then, while your document is open in Illustrator, go to File > Scripts > Other Script (Ctrl+F12). Find the file you just created and open it; this will run the code.
... View more
‎Nov 09, 2023
09:39 PM
For anyone interested in a solution. I found a brilliant script written by Matthew Ericson which exports as PDF or PNGs with optional layers visible. All you have to do is download the script and install it into your illustrator scripts library. Example use case. For more instructions please see this link.
... View more
‎Nov 03, 2023
09:44 PM
1 Upvote
Thank you so much femkeblanco That worked perfectly
... View more
‎Nov 03, 2023
03:29 PM
Hi @Dayzia32719039bp03, just checking that you are trying to re-color *vector* graphics? \
If so, I suggest you put together a small demo file with a demo .ai document, the scripts, and short instructions for which script to use and in what order. That way, people here can follow along with your demo and see where it fails—and then they have a chance of helping you most easily.
- Mark
(If you are wanting to re-color raster graphics , the solution will be very different, and probably more difficult. Let us know that too.)
... View more
‎Oct 27, 2023
02:19 AM
updated code, // LINE SEGMENTS//
var doc = app.activeDocument;
//REMOVE THIS AFTER FIXED//
// Set stroke properties for the line segments
function setStrokeProperties(item) {
item.stroked = true; // Ensure it's stroked
item.strokeWidth = 2; // Set the stroke width
var newColor;
// Set the stroke color based on the document's color space
if (doc.documentColorSpace == DocumentColorSpace.RGB) {
newColor = new RGBColor();
newColor.red = 0;
newColor.green = 0;
newColor.blue = 0;
} else if (doc.documentColorSpace == DocumentColorSpace.CMYK) {
newColor = new CMYKColor();
newColor.cyan = 0;
newColor.magenta = 0;
newColor.yellow = 0;
newColor.black = 100;
}
item.strokeColor = newColor;
}
// Function to set the bezier handle properties
function BEZIER(point, pathPoints, index) {
// Check if the segment is a curve and avoid generating lines
if (
(point.leftDirection[0] !== point.anchor[0] || point.leftDirection[1] !== point.anchor[1]) &&
(point.rightDirection[0] !== point.anchor[0] || point.rightDirection[1] !== point.anchor[1])
) {
return true;
}
// Skip line segment creation of open paths
if (
(pathPoints.parent.closed === false) &&
(index === 0 || index === pathPoints.length - 1)
) {
return true;
}
// If none of the above conditions are met, generate lines
return false;
}
// Function to create line segments with a stable stroke color
function createLineSegment(startPoint, endPoint) {
var newLine = doc.pathItems.add();
newLine.setEntirePath([startPoint, endPoint]);
setStrokeProperties(newLine); // Set stroke properties and color
// Place the line segment in the "LINE SEGMENTS" layer
newLine.layer = lineLayer;
}
// Create a new layer for line segments
var lineLayer = doc.layers.add();
lineLayer.name = "LINE SEGMENTS";
// Function to process different item types
function processItem(item) {
if (item.typename === "GroupItem") {
var groupItems = item.pageItems;
for (var j = 0; j < groupItems.length; j++) {
processItem(groupItems[j]);
}
} else if (item.typename === "PathItem") {
var pathPoints = item.pathPoints;
if (pathPoints.length === 2) {
if (
(pathPoints[0].leftDirection[0] !== pathPoints[0].anchor[0] || pathPoints[0].leftDirection[1] !== pathPoints[0].anchor[1]) &&
(pathPoints[1].rightDirection[0] !== pathPoints[1].anchor[0] || pathPoints[1].rightDirection[1] !== pathPoints[1].anchor[1])
) {
return; // Skip line segment creation
}
createLineSegment(pathPoints[0].anchor, pathPoints[1].anchor);
} else {
for (var k = 0; k < pathPoints.length; k++) {
var startPoint = pathPoints[k];
var endPoint = pathPoints[(k + 1) % pathPoints.length];
if (BEZIER(startPoint, pathPoints, k) && BEZIER(endPoint, pathPoints, (k + 1) % pathPoints.length)) {
continue; // Skip line segment creation
}
createLineSegment(startPoint.anchor, endPoint.anchor);
}
}
} else if (item.typename === "CompoundPathItem") {
// Recursively process each path item within the compound path
for (var i = 0; i < item.pathItems.length; i++) {
processItem(item.pathItems[i]);
}
}
}
// Now, process the selected items to generate lines
var selectedItems = doc.selection;
for (var i = 0; i < selectedItems.length; i++) {
var currentItem = selectedItems[i];
if (currentItem.layer.name === "DUP") {
continue;
}
processItem(currentItem);
} The last thing I want to remove is in red :
... View more
‎Oct 22, 2023
05:41 PM
Hi Bobby Henderson, Thank you for your response. I've tried the trial version, and I found it work for creating patterns, but in this case, I want it to have physical properties(like Physics Now on After Effect can make). Thank you and have a nice day!
... View more
‎Oct 22, 2023
03:37 PM
1 Upvote
I would do the first and second, skipping over any sections that may be uninteresting.
... View more
‎Oct 18, 2023
03:24 PM
2 Upvotes
Hi @femkeblanco, you can access JSON.stringify using an external library, eg. see this post.
- Mark
... View more
‎Oct 17, 2023
07:34 PM
Thank you for clarity on the issue.
... View more
‎Oct 17, 2023
04:11 AM
Ofcourse, Its possible to define global var in main.jsx and read it in lib, but I want to avoid it
... View more
‎Oct 14, 2023
10:17 PM
Thank you for the timely hep!!!
... View more