基于Adobe Illustrator JavaScript实现按颜色添加数字的脚本需求
按颜色为Illustrator图形添加数字编号解决方案
需求说明
需要为Illustrator文档中同一颜色的所有图形添加相同的数字编号(比如绿色标1、黄色标2),替代原脚本按图层编号的逻辑。
原脚本(仅按图层编号)
(function() { var doc = app.activeDocument, lays = doc.layers, WORK_LAY = lays.add(), NUM_LAY = lays.add(), i = lays.length - 1, lay; // main working loop for (; i > 1; i--) { //process each layer lay = lays[i]; lay.name = lay.name + " Num:" + (i - 1); // i-1 as 2 layers beed added. process(lay.pathItems, false); process(lay.compoundPathItems, true); // if any } //clean up NUM_LAY.name = "Numbers"; WORK_LAY.remove(); function process(items, isCompound) { var j = 0, b, xy, s, p, op; for (; j < items.length; j++) { // process each pathItem op = items[j]; // add stroke if (isCompound) { strokeComPath(op); } else { !op.closed && op.closed = true; op.filled = false; op.stroked = true; }; b = getCenterBounds(op); xy = [b[0] + (b[2] - b[0]) / 2, b[1] + (b[3] - b[1]) / 2]; s = ( Math.min(op.height, op.width) < 20 || (op.area && Math.abs(op.area) < 150) ) ? 4 : 6; // adjust font size for small area paths. add_nums(i - 1, xy, s); } } function getMinVisibleSize(b) { var s = Math.min(b[2] - b[0], b[1] - b[3]); return Math.abs(s); } function getGeometricCenter(p) { var b = p.geometricBounds; return [(b[0] + b[2]) / 2, (b[1] + b[3]) / 2]; } // returns square of distance between p1 and p2 function getDist2(p1, p2) { return Math.pow(p1[0] + p2[0], 2) + Math.pow(p1[1] + p2[1], 2); } // returns visibleBounds of a path in a compoundPath p // which is closest to center of the original path op function findBestBounds(op, p) { var opc = getGeometricCenter(op); var idx = 0, d; var minD = getDist2(opc, getGeometricCenter(p.pathItems[0])); for (var i = 0, iEnd = p.pathItems.length; i < iEnd; i++) { d = getDist2(opc, getGeometricCenter(p.pathItems[i])); if (d < minD) { minD = d; idx = i; } } return p.pathItems[idx].visibleBounds; } function applyOffset(op, checkBounds) { var p = op.duplicate(WORK_LAY, ElementPlacement.PLACEATBEGINNING), // offset value the small the better, but meantime more slow. offset = function() { var minsize = Math.min(p.width, p.height); if (minsize >= 50) { return '-1' } else if (20 < minsize && minsize < 50) { return '-0.5' } else { return '-0.2' // 0.2 * 2 (both side ) * 50 (Times) = 20 } }, xmlstring = '<LiveEffect name="Adobe Offset Path"><Dict data="I jntp 2 R mlim 4 R ofst #offset"/></LiveEffect>' .replace('#offset', offset()), TIMES = 100; // if shapes are too large, should increase the value. if (checkBounds) { // check its size only if it needs, because it's too slow while (TIMES-- && getMinVisibleSize(p.visibleBounds) > 3) p.applyEffect(xmlstring); } else { while (TIMES--) p.applyEffect(xmlstring); } return p; } function getCenterBounds(op) { var originalMinSize = getMinVisibleSize(op.visibleBounds); var p = applyOffset(op, false); if (getMinVisibleSize(p.visibleBounds) > originalMinSize) { // in some cases, path p becomes larger for some unknown reason p.remove(); p = applyOffset(op, true); } var b = p.visibleBounds; if (getMinVisibleSize(b) > 10) { activeDocument.selection = [p]; executeMenuCommand("expandStyle"); p = activeDocument.selection[0]; if (p.typename == "CompoundPathItem") { b = findBestBounds(op, p); } } p.remove(); return b; } function add_nums(n, xy, s) { var txt = NUM_LAY.textFrames.add(); txt.contents = n; txt.textRange.justification = Justification.CENTER; txt.textRange.characterAttributes.size = s; txt.position = [xy[0] - txt.width / 2, xy[1] + txt.height / 2]; } function strokeComPath(compoundPath) { var p = compoundPath.pathItems, l = p.length, i = 0; for (; i < l; i++) { !p[i].closed && p[i].closed = true; p[i].stroked = true; p[i].filled = false; }; } })();
修改后的脚本(按颜色编号)
(function() { var doc = app.activeDocument; var NUM_LAY = doc.layers.add(); NUM_LAY.name = "颜色编号"; // 存储颜色分组:key为RGB字符串,value为图形数组 var colorGroups = {}; // 存储颜色对应的编号 var colorNumberMap = {}; var currentNumber = 1; // 遍历所有图层的路径和复合路径 function collectColoredItems() { for (var layIdx = 0; layIdx < doc.layers.length; layIdx++) { var layer = doc.layers[layIdx]; // 处理普通路径 for (var pathIdx = 0; pathIdx < layer.pathItems.length; pathIdx++) { var path = layer.pathItems[pathIdx]; if (path.filled) { addToColorGroup(path); } } // 处理复合路径 for (var compIdx = 0; compIdx < layer.compoundPathItems.length; compIdx++) { var compPath = layer.compoundPathItems[compIdx]; if (compPath.filled) { addToColorGroup(compPath); } } } } // 将图形按填充色分组 function addToColorGroup(item) { var fillColor = item.fillColor; // 仅处理RGB颜色(可扩展支持CMYK等) if (fillColor.typename === "RGBColor") { var rgbKey = `${fillColor.red},${fillColor.green},${fillColor.blue}`; if (!colorGroups[rgbKey]) { colorGroups[rgbKey] = []; colorNumberMap[rgbKey] = currentNumber++; } colorGroups[rgbKey].push(item); } } // 为每组颜色的图形添加编号 function addNumbersToGroups() { for (var rgbKey in colorGroups) { var number = colorNumberMap[rgbKey]; var items = colorGroups[rgbKey]; items.forEach(function(item) { var center = getGeometricCenter(item); var size = Math.min(item.height, item.width); var fontSize = size < 20 || (item.area && Math.abs(item.area) < 150) ? 4 : 6; addNumberText(number, center, fontSize); }); } } // 以下复用原脚本的工具函数 function getGeometricCenter(p) { var b = p.geometricBounds; return [(b[0] + b[2]) / 2, (b[1] + b[3]) / 2]; } function getMinVisibleSize(b) { var s = Math.min(b[2] - b[0], b[1] - b[3]); return Math.abs(s); } function getDist2(p1, p2) { return Math.pow(p1[0] + p2[0], 2) + Math.pow(p1[1] + p2[1], 2); } function findBestBounds(op, p) { var opc = getGeometricCenter(op); var idx = 0, d; var minD = getDist2(opc, getGeometricCenter(p.pathItems[0])); for (var i = 0, iEnd = p.pathItems.length; i < iEnd; i++) { d = getDist2(opc, getGeometricCenter(p.pathItems[i])); if (d < minD) { minD = d; idx = i; } } return p.pathItems[idx].visibleBounds; } function applyOffset(op, checkBounds) { var WORK_LAY = doc.layers.add(); var p = op.duplicate(WORK_LAY, ElementPlacement.PLACEATBEGINNING); var offset = function() { var minsize = Math.min(p.width, p.height); if (minsize >= 50) return '-1'; else if (20 < minsize && minsize < 50) return '-0.5'; else return '-0.2'; }; var xmlstring = '<LiveEffect name="Adobe Offset Path"><Dict data="I jntp 2 R mlim 4 R ofst #offset"/></LiveEffect>' .replace('#offset', offset()); var TIMES = 100; if (checkBounds) { while (TIMES-- && getMinVisibleSize(p.visibleBounds) > 3) p.applyEffect(xmlstring); } else { while (TIMES--) p.applyEffect(xmlstring); } var result = p; WORK_LAY.remove(); return result; } function getCenterBounds(op) { var originalMinSize = getMinVisibleSize(op.visibleBounds); var p = applyOffset(op, false); if (getMinVisibleSize(p.visibleBounds) > originalMinSize) { p.remove(); p = applyOffset(op, true); } var b = p.visibleBounds; if (getMinVisibleSize(b) > 10) { doc.selection = [p]; executeMenuCommand("expandStyle"); p = doc.selection[0]; if (p.typename == "CompoundPathItem") { b = findBestBounds(op, p); } } p.remove(); return b; } function addNumberText(number, center, fontSize) { var txt = NUM_LAY.textFrames.add(); txt.contents = number; txt.textRange.justification = Justification.CENTER; txt.textRange.characterAttributes.size = fontSize; txt.position = [center[0] - txt.width / 2, center[1] + txt.height / 2]; } // 执行流程 collectColoredItems(); addNumbersToGroups(); })();
关键说明
- 脚本自动遍历文档中所有带填充色的路径和复合路径,忽略无填充的图形
- 基于RGB颜色值精确分组,完全相同的RGB颜色会被分配同一个编号
- 编号位置、字体大小逻辑复用原脚本,适配不同尺寸的图形
- 所有编号会集中放在名为"颜色编号"的独立图层,方便管理
内容的提问来源于stack exchange,提问作者Teodoro Angel Dehesa Mitre
相关产品推荐
相关产品推荐

