リンクをクリップボードにコピー
コピー完了
作業環境:Mac OS X 12.7.1_InDesign CC2023
【概要】
InDesignCCから搭載されているパッケージ機能では孫画像(AIやPSD等のリンクにリンクされているデータ)が収集出来ないという問題があります。これを回避する為にJavaScriptでデータを集められないか試しているところです。
【問題点】
データを移動させる時に更新日時が「移動した日」になってしまう。
【改善したい点】
・更新日時を変更せずに移動させたい
・コピーが出来たら完璧
【現状】
添付してあるテキストが「.jsx」の全文となりますが、問題となっている部分を此処に記述していきます。(実際のスクリプトではスプレッドを細切れに分けたりなどの作業が入りますのであくまでパッケージのみの範囲をピックアップしています)
// フォントのコピー関数
function copyFonts(sourceFontsFolder, saveFolder) {
var fontsFiles = sourceFontsFolder.getFiles();
if (fontsFiles.length === 0) return;
var fontsFolder = new Folder(saveFolder + "/Document fonts");
if (!fontsFolder.exists) fontsFolder.create();
for (var i = 0; i < fontsFiles.length; i++) {
var fontFile = fontsFiles[i];
if (fontFile instanceof File) {
try {
fontFile.copy(new File(fontsFolder + "/" + fontFile.name));
} catch (e) {
errorLog.writeln("フォントのコピー中にエラーが発生しました: " + fontFile.name + " - エラー: " + e.message);
}
}
}
}
// リンクの収集関数
function collectLinks(docFile, saveFolder) {
var doc;
try {
doc = app.open(docFile);
} catch (e) {
errorLog.writeln("リンク収集ドキュメントのオープン中にエラーが発生しました: " + docFile.name + " - エラー: " + e.message);
return;
}
var links = doc.links;
if (links.length === 0) {
doc.close(SaveOptions.NO);
return;
}
var linksFolder = new Folder(saveFolder + "/Links");
if (!linksFolder.exists) linksFolder.create();
var collectedLinks = {};
for (var i = 0; i < links.length; i++) {
var link = links[i];
var sourceFile = new File(link.filePath);
if (sourceFile.exists) {
processLink(sourceFile, link.name, linksFolder, collectedLinks);
} else {
errorLog.writeln("リンクが見つかりません: " + link.filePath);
}
}
doc.close(SaveOptions.NO);
}
function processLink(fileObj, linkName, linksFolder, collectedLinks) {
if (collectedLinks[linkName]) return;
collectedLinks[linkName] = true;
var originalDate = fileObj.modified;
var destFile = new File(linksFolder + "/" + linkName);
try {
fileObj.copy(destFile);
collectedLinks[linkName] = true;
var subLinks = getLinks(destFile.fsName);
for (var j = 0; j < subLinks.length; j++) {
var subLinkName = subLinks[j];
if (!collectedLinks[subLinkName]) {
var subLinkFile = new File(fileObj.path + "/" + subLinkName);
if (subLinkFile.exists) {
processLink(subLinkFile, subLinkName, linksFolder, collectedLinks);
}
}
}
updateLinkPath(fileObj, destFile.fsName);
destFile.modified = originalDate;
} catch (e) {
$.writeln("リンクの処理エラー: " + e.message);
}
}
// 無駄な抵抗_リンクの更新
function updateLinkPath(fileObj, newPath) {
try {
var doc = app.activeDocument;
var links = doc.links;
for (var i = 0; i < links.length; i++) {
if (links[i].filePath === fileObj.fsName) {
links[i].relink(new File(newPath));
links[i].update();
}
}
} catch (e) {
$.writeln("リンクパスの更新エラー: " + e.message);
}
}
function getLinks(fls) {
var prop = "Manifest";
var ns = "http://ns.adobe.com/xap/1.0/mm/";
if (typeof xmpLib === 'undefined') {
var xmpLib = new ExternalObject('lib:AdobeXMPScript');
}
var xmpFile = new XMPFile(fls, XMPConst.UNKNOWN, XMPConst.OPEN_FOR_READ);
var xmpPackets = xmpFile.getXMP();
var xmp = new XMPMeta(xmpPackets.serialize());
var str = "";
var result = [];
for (var i = 1; i <= xmp.countArrayItems(ns, prop); i++) {
str = xmp.getProperty(ns, prop + "[" + i + "]/stMfs:reference/stRef:filePath").toString();
result.push(str.slice(str.lastIndexOf("/") + 1));
}
return result;
}
【現実的な解決案の候補】
1:JavaScriptのpackageforprint にてまるごとパッケージ、データのxmpを参照して孫以降のデータのみを移動(更新日時が最新になってしまう事には目をつむる)
2:AppleScriptにてBridgeTalk を経由して移動させる(corecaraさん のdtp helper 参考)
3:xmpより更新日時情報を得て、移動先で更新日時の情報を変更させる
4:孫以下の一覧を出して手動で移動
現状BridgeTalkでしか更新日時を変更せずに移動できなさそう(そもそも移動やコピーという行為自体が変更日時に引っ掛かるのでどうにもならなさそう)ではないかと思っております。
もし、どなたかBridgeTalkなしに移動させる方法などを知っている方がいたら教えていただきたいと思い書かせていただきました。kekaなどの解凍アプリだと更新日時をそのままに移動(?)出来るのでその応用が出来たら一番なのですが…ここの更新日時周りの記述に悩みます。
最有力候補はBridgeTalkなのですが…勉強出来る場所や情報などが載っているサイトなどをご存じの方がいらっしゃれば教えていただけると幸いです。
更新日時が変わるのはFileオブジェクトのcopyメソッドの残念な仕様で、ExtendScript内ではどうしようもないと思っていたのですが、Ten Aさんがそれを覆す、すごい方法を教えてくれていますね。たとえばこんなコードでファイルのコピーができます。
copyFile("~/desktop/a.jpg","~/desktop/a_.jpg")
function copyFile(moto,saki){
var d1=app.documents.add();
var p=d1.spreads[0].place(File(moto));
p[0].itemLink.copyLink(File(saki));
d1.close(SaveOptions.NO);
}
とはいえ処理が重くなりそうなので、できることならAppleScriptやVBScriptと連携するのがいちばんだと思います。InDesignでExtendScriptからAppleScriptを呼び出すのはBridgeTalkではなくapp.doScriptです
リンクをクリップボードにコピー
コピー完了
一応ですがテスト用のファイルも置いておきます。
フォントはライセンスに引っ掛かるのを回避するためにあえて付けておりません
Linksフォルダに各.aiを置いてお使いください(親>子>孫の順番にリンクさせています)
「ブリの見分けがつかない.zip(2024.9.3時点〜100日間保管)」
https://27.gigafile.nu/1212-b774c5914f8f44083e57b3f3e2bd07fc4
リンクをクリップボードにコピー
コピー完了
どうもどうも。
いちど、一連の流れを日本語で書いてもらったほうが、と思うのですが(たぶんそれが必要なのは自分だけなのでいいです)
対象indd上のリンクでループ
リンクの情報を取得する関数 *
リンクの形式が .aiならIllustratorで開く(BridgeTalk)
関数 * に再帰
InDesignに返す
}
}
みたいな感じですかね?
「移動」「コピー」が散見されますが、標準機能のパッケージはIdもAiもすべてリンクファイルを「複製」(コピー)で集めます。
今回はそこをあえて「移動」でやりたい感じでしょうか?(難しそう)
リンクをクリップボードにコピー
コピー完了
Link周りがごちゃっとしていて読みづらいですよねー…わかります。
JSのみだと…
格納フォルダ作成
格納フォルダにLinks、Document fontsフォルダを作成
font移動(複製)
indd移動(複製)
リンクをLinksへ移動(複製)させる関数●1
xmpを参照してLinksへ移動(複製)させる関数●2
(inddを開いてリンク上でループ){
if{リンクが.aiか.psdの時 ●2
}そうでない時 ●1
}
BridgeTalk入りだと…
とりあえずパッケージ(packageforprint)
リンクの情報を取得する関数○1
(inddを開いてリンク上でループ){
if{リンクが.aiか.psdの時 ○1(BridgeTalkでLinksへ複製)
}
言語化できているかは不安ですがやりたいことは上記のような形です。
現状、作成しているのは「JSのみだと…」の方ですが、BridgeTalkの方を使って楽したい…というのが目的の一つでもあります。
移動またはコピーと言っているのは「複製」が頭から抜け落ちていた為ですね…!!
データをパッケージする為の関数は移動もまとめて「packageforprint」という定義だけで具体的にどうやって複製しているのか謎でした…。
改めて複製って定義(型)であるのですか…?
リンクをクリップボードにコピー
コピー完了
パッケージ処理は一般に
・リンク(とフォント)の複製による収集
・収集済みファイルへの再リンク
が行われるので(しなくもできますが、やる前提で)、
InDesignのpackageForPrint および Illustratorの「パッケージ」で末端までやるとなると
子孫→親 の順でやっていかないといけないんですかねえ。
リンクをクリップボードにコピー
コピー完了
再リンクも少し問題に思っていたところではあったんですよね。
移動したからといって自動的にリンクが更新されるかは微妙なところ(手動で複製またはコピーしても時々リンクが外れることがある)ので、やはり現実的に考えるのであればパッケージ処理をした上でxmpを参照して零れているものだけを複製(更新日時は移動した日時に)させるのが一番なのかしら…。
まあ、正直なところ子孫の更新日時は最新になっても問題はないとは思うのですが…事例があるかぎりやりようはあるはずなので、もう少し練って追求していきます。
リンクをクリップボードにコピー
コピー完了
inDesignからだとcopyLinkメソッドを利用すれば任意のパスにFinder上で操作した状態でコピーできるんですけど、元来そういった利用方法を行う為のメソッドではないので色々と調整は必要になります。
ちなみにBridgeTalkはExtendScriptを指定したアプリケーションで実行させる仕組みなのでターゲットアプリケーションを指定してスクリプトを渡すといった流れで処理します。一連の流れは定型なのでGithubとかで検索すれば参考になるものはたくさん見つかるでしょう。
あと、10年以上前に書いたXMP操作関数がそのまま利用され続けているのは感慨深いですね(^-^;
リンクをクリップボードにコピー
コピー完了
Tenさんご本人でしたか…!xmp関連は「孫まで収集します。」を参考にさせていただきました。ところどころ記号の類など少し手を加えている部分はあるのですが、シンプルかつわかりやすくて後々からでも応用が利くというところで組み込ませていただいています!
実のところGithubは使いこなせておらず、使い方がわかりにくい(情報量の多さ)という大きな壁とぶつかっているところですが、Githubで公開されている「BridgeTalkを使っているスクリプト」を見てみるとAppleScriptに似た何かを感じさせますね。targetからスタートするのは馴染みがあるようでないような…CS時代に時々見かけたような…。
見ていて思ったのはBridgeTalkはあくまでアプリケーション同士の橋渡しであってデータの移動は結局の所BridgeTalkでの作業外なのでは…という結論に至っています。BridgeTalkでAppleScriptに渡して移動…?
リンクをクリップボードにコピー
コピー完了
更新日時が変わるのはFileオブジェクトのcopyメソッドの残念な仕様で、ExtendScript内ではどうしようもないと思っていたのですが、Ten Aさんがそれを覆す、すごい方法を教えてくれていますね。たとえばこんなコードでファイルのコピーができます。
copyFile("~/desktop/a.jpg","~/desktop/a_.jpg")
function copyFile(moto,saki){
var d1=app.documents.add();
var p=d1.spreads[0].place(File(moto));
p[0].itemLink.copyLink(File(saki));
d1.close(SaveOptions.NO);
}
とはいえ処理が重くなりそうなので、できることならAppleScriptやVBScriptと連携するのがいちばんだと思います。InDesignでExtendScriptからAppleScriptを呼び出すのはBridgeTalkではなくapp.doScriptです
リンクをクリップボードにコピー
コピー完了
ありがとうございます!
まさにやろうとしていたことです!まさかitemLinkの時に収集先が設定できるとは…!
sakiをファイル名ではなくフォルダ名にしてあげることで望み通りの動きができました。
BridgeTalkの理解が浅くてAppleScript関連も大混乱してましたね……恥ずかしい。
ちなみにこの答えを得られるまでに考えていた別の手段としましては
AppleScriptをメインとして動かして外部JSでLinkのリスト作成と諸々
作成されたリストのデータをAppleScriptで移動させる
……というものでした。
AppleScriptで完結させない理由はInDesignをパッケージするだけではなく、データを弄ったり他の作業を入れたいからJSをどうしても動かしたかったんです。
AppleScript 案
set moto to choose folder with prompt "erande moto Foler"
set saki to "package"
set pack to POSIX path of moto & saki & "/"
do shell script "mkdir -p " & quoted form of pack
--各フォルダ作成(略)
set jsxScriptPath to "/Applications/Adobe InDesign 2023/Scripts/linkListSakusei.jsx"
tell application "Adobe InDesign 2023"
activate
do script jsScriptPath language javascript with arguments{pack}
end tell
--リストを読み込んで移動させる(略)
JSだけで完結する方法を教えていただいたので今日からゆっくり寝られるぞー!
リンクをクリップボードにコピー
コピー完了
リンクをクリップボードにコピー
コピー完了
初めまして、突然振られた仕事のインデザインで作成しているデータの管理が酷く、インデザインに配置したイラストレータの画像(孫データ)が回収できず悩んでいたところこちらにたどり着きました。
Githubののところでは「本番での運用にはフォントの収集含めてこれを改訂」とありますが本番のスクリプトの公開をされるご予定はありませんでしょうか。
ご検討のほどよろしくお願いいたしまます。