【Illustrator】PhotoshopのダイナミックテキストをIllustratorで実現する
2025年6月リリースのPhotoshop 26.8にダイナミックテキスト機能を追加されました。Adobe Expressの人気機能が移植されたものです。
新機能「ダイナミックテキスト」の使い方を紹介します!
— タマケン | デザイン (@DesignSpot_Jap) June 17, 2025
(音あり解説)#PR #AdobePhotoshop #Photoshop #AdobePartner@creativecloudjp pic.twitter.com/WnhHU09Yd4
でも、これってIllustratorにこそ、欲しいですよね!ということで作ってみました。
制限事項
横書きのみ
欧文で語尾にスペースがあるとき、スペースを計算してしまいます。
カーニングや文字ツメなどの情報がクリアされてしまいます。これは保持したいところ…
コード
コピーしてテキストエディタにペーストして保存。拡張子を.jsxに変更すればスクリプトファイルとして実行できます。
#target illustrator
app.preferences.setBooleanPreference('ShowExternalJSXWarning', false);
// エリア内文字をポイント文字に変換し、変換後のTextFrameを取得
function convertAreaTextToPointText(areaTextFrame, originalContents, originalPosition) {
areaTextFrame.convertAreaObjectToPointObject();
var allTextFrames = app.activeDocument.textFrames;
for (var i = 0; i < allTextFrames.length; i++) {
var tf = allTextFrames[i];
var dx = Math.abs(tf.position[0] - originalPosition[0]);
var dy = Math.abs(tf.position[1] - originalPosition[1]);
if (dx < 1 && dy < 1) {
return tf;
}
}
return null;
}
// エリア内文字を行単位に分割し、ポイント文字のTextFrameとして再配置
function splitTextFrameIntoLines(textFrame) {
var lines = textFrame.contents.split('\r');
var originalPosition = textFrame.position;
var currentY = originalPosition[1];
var textSize = textFrame.textRange.characterAttributes.size;
var textFont = textFrame.textRange.characterAttributes.textFont;
var textColor = textFrame.textRange.characterAttributes.fillColor;
var hScale = textFrame.textRange.characterAttributes.horizontalScale;
var splitLines = [];
for (var i = 0; i < lines.length; i++) {
var newLine = app.activeDocument.textFrames.pointText([originalPosition[0], currentY]);
newLine.contents = lines[i];
newLine.textRange.characterAttributes.size = textSize;
newLine.textRange.characterAttributes.textFont = textFont;
newLine.textRange.characterAttributes.fillColor = textColor;
var actualWidth = newLine.width;
var scaleX = (textFrame.width / actualWidth);
if (scaleX > 0) {
newLine.textRange.characterAttributes.size = textSize * scaleX;
newLine.textRange.characterAttributes.horizontalScale = 100;
newLine.textRange.characterAttributes.verticalScale = 100;
}
currentY -= newLine.height;
splitLines.push(newLine);
}
var mergedFrame = mergeTextFramesVertically(splitLines);
if (mergedFrame) {
// 行間を自動に設定し、autoLeadingAmount を 100 に設定
mergedFrame.textRange.characterAttributes.autoLeading = true;
var paragraphs = mergedFrame.paragraphs;
for (var i = 0; i < paragraphs.length; i++) {
paragraphs[i].paragraphAttributes.autoLeadingAmount = 110;
}
redraw();
textFrame.remove();
mergedFrame.convertPointObjectToAreaObject();
}
}
// 垂直比率を水平比率に合わせて統一
function matchVerticalScaleToHorizontal(item) {
var currentHorizontalScale = item.textRange.characterAttributes.horizontalScale;
item.textRange.characterAttributes.verticalScale = currentHorizontalScale;
}
// テキストフレームのみをリストに追加
function collectTextFrame(item, list) {
if (item.typename === 'TextFrame') {
list.push(item);
}
}
// 複数のテキストフレームを縦方向に連結して再構成
function mergeTextFramesVertically(frames) {
if (frames.length < 2) {
return;
}
var sortedFrames = sortTextFramesByPosition(frames);
var splitFrames = [];
for (var i = 0; i < sortedFrames.length; i++) {
var lines = sortedFrames[i].contents.split('\r');
for (var j = 0; j < lines.length; j++) {
if (lines[j] !== "") {
var tf = sortedFrames[i].duplicate();
tf.contents = lines[j];
tf.top -= j * 2000; // 行順を維持するために位置調整
splitFrames.push(tf);
}
}
sortedFrames[i].remove();
}
sortedFrames = sortTextFramesByPosition(splitFrames);
var baseFrame = sortedFrames[0];
for (var k = 1; k < sortedFrames.length; k++) {
baseFrame.paragraphs.add('\n');
var paragraphs = sortedFrames[k].paragraphs;
for (var p = 0; p < paragraphs.length; p++) {
paragraphs[p].duplicate(baseFrame);
}
sortedFrames[k].remove();
}
return baseFrame;
}
// テキストフレームを位置情報(上→下、左→右)でソート
function sortTextFramesByPosition(frameList) {
try {
var copyList = [];
var i;
for (i = 0; i < frameList.length; i++) {
copyList.push(frameList[i]);
}
copyList.sort(function(a, b) {
if (a.position[1] > b.position[1]) {
return -1;
}
if (a.position[1] < b.position[1]) {
return 1;
}
if (a.position[1] === b.position[1]) {
if (a.position[0] < b.position[0]) {
return -1;
}
if (a.position[0] > b.position[0]) {
return 1;
}
return 0;
}
});
return copyList;
} catch (e) {
alert("ソート中にエラーが発生しました: " + e.message);
return frameList;
}
}
function main() {
// 選択確認
if (app.documents.length === 0 || app.activeDocument.selection.length === 0) {
alert("エリア内文字を選択してください。");
return;
}
var areaTextFrame = app.activeDocument.selection[0];
if (areaTextFrame.typename !== "TextFrame" || areaTextFrame.kind !== TextType.AREATEXT) {
alert("エリア内文字を選択してください。");
return;
}
var areaWidth = areaTextFrame.width;
// 分割
splitTextFrameIntoLines(areaTextFrame);
// 連結
var selectionItems = app.activeDocument.selection;
if (selectionItems.length >= 2) {
var textFrames = [];
for (var i = 0; i < selectionItems.length; i++) {
collectTextFrame(selectionItems[i], textFrames);
}
if (textFrames.length >= 2) {
mergeTextFramesVertically(textFrames);
}
}
}
main();備考
思いっきり車輪の大発明ですが、今回のスクリプトはエリア内文字の横幅を見ます。
ダウンロード
ここから先は
0字
/
1ファイル
¥ 100
Amazon Payで支払うと最大2%還元のチャンス! 9/30まで
定期マガジンを購読されるとサンプルファイルをダウンロードいただけます。 https://note.com/dtp_tranist/m/mebd7eab21ea5
