読者です 読者をやめる 読者になる 読者になる

ごんれのラボ

iOS、Android、Adobe系ソフトの自動化スクリプトのことを書き連ねています。

Illustratorのドキュメント上で使用されているフォントを取得して超雑にアラートで表示する方法

JavaScript Illustrator

概要

Illustrator のドキュメント上で使用されているフォントを取得して超雑にアラートで表示するJavaScript。
表示される内容は

  • name

検証バージョンは Illustrator CC 2015.3。

InDesign 版はこちら。

www.macneko.com

使い方

  1. JavaScript を ExtendScript Toolkit にコピペして、左上のプルダウンから使用したい Illustrator のバージョンを指定する
  2. Illustrator でドキュメントを1つ以上開く
  3. ExtendScpirt Toolkit から実行する
  4. ドキュメント上で使用しているフォントの一部情報がアラートで表示される
  5. テキストがないフレームが存在した場合は、「※テキストのないフレームで使用しているフォントは含まれておりません。」とお知らせする

実行結果のキャプチャ

f:id:macneko-ayu:20170322134629p:plain

ソースコード

var docObj = app.activeDocument;
var textFrames = docObj.textFrames;
var textFramesLen = textFrames.length;
var tmpFontsNamesArr = new Array();
var usedFontsNamesArr = new Array();
var usedFontsNames = "";
var isNoContents = false;

for (var i = 0; i < textFramesLen; i++) {
    var textFrame = textFrames[i];
    var characters = textFrame.textRange.characters;
    var charactersLength = characters.length;
    if (charactersLength === 0) {
        isNoContents = true;
        continue;
    }
    for (var j = 0; j < charactersLength; j++) {
        tmpFontsNamesArr = tmpFontsNamesArr.concat(characters[j].characterAttributes.textFont.name);
    }
}

var usedFontsNamesArr = unique(tmpFontsNamesArr);
for (var i = 0; i < usedFontsNamesArr.length; i++) {
    if (i === 0) {
        usedFontsNames += usedFontsNamesArr[i];
    } else {
        usedFontsNames += "\n" + usedFontsNamesArr[i];
    }
}
if (isNoContents) {
    usedFontsNames += "\n\n" + "※テキストのないフレームで使用しているフォントは含まれておりません。";
}

alert(usedFontsNames);

function unique(array) {
    var storage = {};
    var uniqueArray = [];
    var i, value;
    for (i = 0; i <array.length; i++) {
        value = array[i];
        if (!(value in storage)) {
            storage[value] = true;
            uniqueArray.push(value);
        }
    }
    return uniqueArray;
}

注意点

InDesign と違い、ドキュメントがフォント情報を持っていないようなので、テキストフレームをぐるぐるして、その中の一文字一文字からフォント名を取得しているので、環境やドキュメントの作り込み方によっては、とても遅いかも。
あと使い方にも書いたけど、テキストのないテキストフレームに適用されているフォント名は取得できないので、注釈という形でその旨報告しています。
レイヤーのロック状態も見ていないので、必要であれば足してください。

もっと詳しく

要望があれば、Twitter にて。

InDesignのドキュメント上で使用されているフォントを取得して超雑にアラートで表示する方法

JavaScript InDesign

概要

InDesign のドキュメント上で使用されているフォントを取得して超雑にアラートで表示するJavaScript。
表示される内容は

  • fontFamily
  • fontStyleName
  • name
  • version

使い方

  1. JavaScript を ExtendScript Toolkit にコピペして、左上のプルダウンから使用したい InDesign のバージョンを指定する
  2. InDesign でドキュメントを1つ以上開く
  3. ExtendScpirt Toolkit から実行する
  4. ドキュメント上で使用しているフォントの一部情報がアラートで表示される

実行結果のキャプチャ

f:id:macneko-ayu:20170315134334p:plain

ソースコード

var docObj = app.activeDocument;
var str = "";
for (var i = 0; i < docObj.fonts.length; i++) {
    var font = docObj.fonts[i];
    str += "\n\n\nfontFamily: " + font.fontFamily;
    str += "\nfontStyleName: " + font.fontStyleName;
    str += "\nname: " + font.name;
    str += "\nversion: " + font.version;
}

alert(str);

注意点

段落スタイルなどのスタイル系で指定しているフォントは、実際にドキュメント上でそのスタイルが使用されていないと拾えない模様。
段落スタイルで使用しているフォントもほしい場合は、スタイル取得して for でぐるぐる回すなどするといいです。

もっと詳しく

要望があれば、Twitter にて。

CEP ExtensionsとInDesignをCallbackで仲良くしてもらう方法

CEP Extensions InDesign

概要

今日は CEP Extensions のお話。
これの続き。

www.macneko.com

やりたかったこと

とりあえず、Extensions と InDesign とで、値のやり取りができないことには面白くないので、やりとりする方法を知りたかった。

道のり

Illustrator版のCallbackのサンプルコードを見つける

まず真っ先に調べるのはいつも Twitter で質問攻めにしているてまりさんのサイト。
Callbackについての記事を発見。

Call Back from Extendscript - 手抜きLab@DTPの現場

しかし、飲み込みの悪い私はこれを読んでも全然わからない…。
どうしたものかと頭を悩ませていると、なんとてまりさんが Github で公開されていたサンプルプロジェクトの中に callbacktest なるものがあるじゃないですか。
これは参考にするしかないということで、早速ゲット。

github.com

こちらは Illustrator 用に書かれていたので、取り急ぎ Illustrator で動作確認してみたら、バッチリ動いた。
これは manifest.xml を書き換えたら InDesign でも簡単に動くでしょー。

現実は甘くなかった

InDesign に前述の Extensions を突っ込んで動作確認してみたが、Callback を経由しての応答がない。
どうやらそう簡単に Adobe 神は微笑んでくれないようだ…。

改めて、InDesign 用の Callback について調査をしたところ、下記のサイトにヒントが書いてあった。

aphall.com

ツールがネイティブに発送するイベント以外にも、好きなイベントをツールVMから発送するExtendScriptのAPIもある。(現時点ではJSFL用のAPIは無いので、ネイティブイベントを利用する必要となる。)

方法は、PlugPlugExternalObject というプラグインを使う。現状ではPhotoshop、Illustrator、Premiere ProとAfter Effectsはそれぞれこのプラグインを内部的に実装するので、エクステンションに追加する必要は無い。InDesign、InCopyで使うには、プラグインをエクステンションのソースに置いて、CEPドキュメンテーションのp41のようなコードを実装する必要がある。

なるほど、InDesign と Illustrator では、実装されている内容というか形式が違うのね。
InDesign はユーザー数が Photoshop、Illustrator、Premiere Pro と After Effects より少ないから実装が先送りになっているのかなぁ(邪推)

PlugPlugExternalObject を使おうとして、四苦八苦

まず、PlugPlugExternalObject をダウンロードする。
私は Mac ユーザーなので、PlugPlugExternalObject-Mac.zip をダウンロードした。

github.com

解凍したら PlugPlugExternalObject.framework が入っているので、これを (project_dir)/jsx/ の中に入れる。

続いて、 CEP ドキュメント を参考にして、PlugPlugExternalObject を jsx から読み込めるように実装する。
ドキュメントに書いてあるコードがこちら。

try {
    var xLib = null;
    var ppLibFile =
        File(File($.fileName).parent).fullName+"/PlugPlugExternalObject");
    if (ppLibFile.exists) {
        var xLib = new ExternalObject("lib:"+ ppLibFile.fullName);
    }
    else {
        throw new Error("Can't find PlugPlugExternalObject: " 
                        +ppLibFile.fullName+,$.fileName,$.line);
    }
}
catch(e) { alert(e); }

これで動くと思うでしょ?
ざーんねん、このソースコードはそもそもシンタックスエラーで実行すらできません!
ExtendScript Toolkit を使っていれば気づいたんだろうけど、Brackets でさくさく開発環境を楽しんでいたので、気づくのが遅れた。
久しぶりの Adobe クオリティを突きつけられたので、Twitter で報告したよ。

そして、修正したコードは ExtendScript Toolkit では動作するものの、Extensions に組み込むと動作しないという二重の罠。
どうやら jsx の Helper Object ($ で表現されているやつ)がうまく動作していない模様。

こういうときは、てまりさんに教えてもらうに限る。
いただいた回答によれば、CSInterface クラスに systemPath クラスがあるので、そこから extensions のパスを取得したりできるとのこと。
なるほど、Extensions で自身のパスを取得して、それを jsx に渡せばいいのね。
csInterface.evalScript() で引数を扱う書き方がわからなくて、だいぶ試行錯誤したけど、

csInterface.evalScript('methodName("' + argument + '")'); 

という書き方になるようだ。

そんなわけで、

main.js

(function () {
    'use strict';
    var csInterface = new CSInterface();
    function init() {
        themeManager.init();
        // プロジェクト内のjsxディレクトリのパスを取得
        var jsxDirPath = csInterface.getSystemPath(SystemPath.EXTENSION) + "/jsx";
        // jsxにjsxディレクトリのパスを渡す
        csInterface.evalScript('setDirPath("' + jsxDirPath + '")');
    }
    init();
}());

hostscript.jsx

// グローバル変数でjsxディレクトリのパスを保持
var dirPath = "";

// 引数で渡ってきたパスをグローバル変数に代入する
function setDirPath(jsxDirPath) {
    dirPath = jsxDirPath;
}

これで jsx から (project_dir)/jsx/ を知ることができるようになった。

紆余曲折あったけど、念願のCallback処理にたどり着いた

とりあえず Callback が動作していることがわかればいいので、ボタンを押したら jsx から渡されたメッセージをテキストエリアに反映するという簡単なものを。

main.js

(function () {
    'use strict';
    var csInterface = new CSInterface();
    var message = "";
    function init() {
        themeManager.init();
        // プロジェクト内のjsxディレクトリのパスを取得
        var jsxDirPath = csInterface.getSystemPath(SystemPath.EXTENSION) + "/jsx";
        // jsxにjsxディレクトリのパスを渡す
        csInterface.evalScript('setDirPath("' + jsxDirPath + '")');

        // コールバックを受け取って、テキストエリアに反映する
        csInterface.addEventListener("getCallback", function (evt) {
            message = evt.data;
            $("#textarea").text(message);
        });
        // ボタンをクリックしたらコールバックをセットする
        $("#button").click(function () {
            var str = "sample";
            csInterface.evalScript('setCallback("' + str + '")', function (e) {
            });
        });
    }
    init();
}());

hostscript.jsx

// グローバル変数でjsxディレクトリのパスを保持
var dirPath = "";

// 引数で渡ってきたパスをグローバル変数に代入する
function setDirPath(jsxDirPath) {
    dirPath = jsxDirPath;
}

// コールバックをセットする
function setCallback(str) {
    try {
        var xLib = null;
        // PlugPlugExternalObject.frameworkのパスを生成
        var ppLibFile = File(dirPath + "/PlugPlugExternalObject.framework");
        if (ppLibFile.exists) {
            // ExternalObjectを生成
            xLib = new ExternalObject("lib:"+ ppLibFile.fullName);
        }
        else {
            throw new Error("Can't find 'PlugPlugExternalObject.framework'.");
        }
    }  catch(e) { alert(e); }

    // コールバック処理
    var eventObj = new CSXSEvent();
    eventObj.type = "getCallback";
    eventObj.data = createMessage(str);
    eventObj.dispatch();
    xLib.unload();
    return true;
}

function createMessage(str) {
    return "Hello extension " + str + ".";
}

テキストエリアに入力した文字を加工して表示させるほうが良かったかもと思ったけど、疲れたのでスルー。

わからないこともたくさんある

eventObj.data に入れるものは string じゃないとInDesignが落ちてしまうんだけど、たとえば Object を Extensions にそのまま渡したい時はどうしたらいいんだろうか。
ParagraphStyles なんて膨大なプロパティがあって、その中に別の Object も格納されているわけで、そのまま渡ってこないと厳しいよね。

サンプルコードはこちら

github.com

try! Swift Tokyo 2017の2日目にボランティアスタッフとして参加してきた

Swift 勉強会 iOS

※お気持ち的な感想しか書いていないので、セッションについて知りたい方は他の方のブログやQiitaをご覧になることを強くおすすめします。

安定のクラスメソッドさんとかどうでしょうか。 dev.classmethod.jp

さて。 try! Swift Tokyo 2017の2日目にボランティアスタッフとして参加してきた。
きっかけは上司がSlackで「ボランティアスタッフ募集しているから行きたい人は応募してね」って言ってくれたこと。
try! Swift Tokyo 2017が開催されることは知っていて、行きたいなーと思ってはいたものの、「Swift最近書いてないしなー英語話せないしなー」と踏ん切りがつかず諦めかけていたんだけど、上司の言葉に後押しされてその場で応募。

当日会場に行ってみると、とても広くて綺麗で、開場前のホールにずらっと並んだ椅子の多さにちょっとビビった。
スタッフの方々の中に数名知っている方がいて、ホッとした。

担当したのは翻訳レシーバーの受け渡しで、手の空いたときは他のところのお手伝いをする感じだった。
スクリーンの正面だったのでセッションも聞けてよかった。

以下、個条書きで感想。

  • 英語は話せなくてもなんとかなったけど(日本語話せる海外の方が多かった)、話せたほうがさらに楽しそう
  • テストに関するセッションが多くて、「テストせな!」と背中を押されている感あった
  • 色に関するセッションは、元印刷系のお仕事でデザインやってたこともあるので、色大事って再確認できた
  • 懇親会は謎の乾杯をする一団に混ざって面白かった。そのあともいろんな方とお話できて楽しかった
  • 「お仕事は?」「iOSとAndroidやってます。あと猫の世話です」「え?」みたいなやりとり、たくさんやって満足。猫社員はいいぞ。

来年もお手伝いしたいなと思える1日でした。
お会いした皆様に感謝。

InDesignのExtensions開発スタート

CEP InDesign Visual Studio Team Services

Creative Cloudを購入した目的の一つが「Extensionsの開発、やってみたい!」だったわけですが、例によって全然進んでませんでした。
そんな中、Twitterでお題をいただいたので、がんばってやってみるよ!

作りたいものは

  • InDesignの段落スタイルを作るときに、継承するのではなく、必要な設定だけコピーできるようにしたい
  • 段落スタイルパレットのようなUIを用意したい

といったようなもの。
段落スタイルの各設定を取得して、取り回しがいいように設計できれば、UIを作ることがメインになりそう。
まぁ、罠はたくさんありそうだ。

あと、Extensions実装には関係ないんだけど、やることを整理して進めたいので、Visual Studio Team Services(以下、VSTS) を使って、バックログとかタスクとか管理してみようと思う。

www.visualstudio.com

下記のような感じで、ユーザーストーリーとタスクを順次追加して進めていこうかな。
本来は事前にユーザーストーリーを決めてから設計などするんだろうけど、そっちに力を入れすぎると飽きる可能性が高いので、ひとまず自分のタスク管理帳代わり程度に使っていこう。

f:id:macneko-ayu:20170226155449p:plain

Visual Studio Team Services の始め方に関しては、そのものズバリをブログに書いてくれている方がいるので、そちらを参考にしてください。

changesworlds.com

レイヤーごとにPNG形式で画像を書き出す

AppleScript Illustrator

レイヤーごとにJPEG形式で画像を書き出すというスクリプトを書いて、公開しています。

www.macneko.com

そのコメントで「PNG形式で書き出すバージョンもほしい」という要望があったので、書いてみました。

<仕様>

  • 共通して書き出したいオブジェクトは表示レイヤーに入れてある
  • レイヤーには必要なオブジェクトが格納されている
  • レイヤーの表示のオン/オフで書き出すPNGを決める
  • PNGの名前はレイヤー名から取得
  • PNGはPNG24形式
  • エラー処理はすっとばす
--保存場所を決める
set filePath to choose folder with prompt "保存するフォルダを選択してください" as string

--ここからIllustratorの処理
tell application "Adobe Illustrator"
    activate
    set myDoc to document 1
    tell myDoc
        --非表示レイヤーをリスト化して変数へ
        set visibleFalseLayer_list to every layer whose visible is false
    end tell
    
    --非表示レイヤーの数だけ繰り返す
    repeat with a from 1 to count of visibleFalseLayer_list
        tell myDoc
            set currentLayer to item a of visibleFalseLayer_list --処理用に代入
            set visible of currentLayer to true --レイヤーを表示状態に
            set myLayerName to name of currentLayer
            set newFilePath to filePath & myLayerName & ".jpg" as string --保存ファイル名を代入
        end tell
        export myDoc to newFilePath as PNG24 with options {class:PNG24 export options, antialiasing:true, artboard clipping:false, horizontal scaling:100.0, matte:true, matte color:{red:255, green:255, blue:255}, saving as HTML:false, transparency:true, vertical scaling:100.0}
        --antialiasing:trueはアンチエイリアス有効
        --transparency:trueは透過有効
        --vertical scaling:100.0は書き出す倍率(vertical scaling:200.0は縦方向に200%)
        --matte color:{red:255, green:255, blue:255}はRGBってことだと思う?
        tell myDoc
            set visible of currentLayer to false --再度非表示にする
        end tell
    end repeat
end tell
activate
display dialog ((count of visibleFalseLayer_list) as string) & "ファイル書き出しました"

ダウンロードはこちら

レイヤーごとにPNG書き出し

Illustratorを開かずに配置ファイルを収集する 続編

Illustrator AppleScript Ruby

[Illustrator][AppleScript][Ruby]Illustratorを開かずに配置ファイルを収集するの続編です。

 

2017/2/18追記

下記の環境で動作確認しました。

  • OS X El Capitan(10.11.6)
  • CC 2015.3

 

本編

上記エントリで公開したAppleScriptは結構たくさんの方から評価をしてもらっているようです。

Twitterなり勉強会なりで「使ってます!」「助かってます!」というお言葉も頂戴しており、嬉しい限りです。

ただ、いろいろな不具合も起きてしまっているようで、「早く修正してー」と言われてしまうこともしばしばありました。

直そう直そうと思ってはいたものの、仕事やレノくんもふもふするのが忙しくて延び延びになってしまっていました。

フィードバックしていただいた方々、申し訳ないです。

 

ということで、今日頑張って修正しました!

Rubyのコードを大幅に書き換えて、AppleScriptのほうもいろいろリファクタリングしました。

この数ヶ月、暇を見つけては会社でいろんなスクリプト(Ruby含む)を書きまくっていたので、その辺の経験と知識を反映したつもりです。

 

修正した箇所は

●バージョン判別をRuby内で行うように修正(Adobe Illustrator CS2という文字があるかどうか)

●XMPだけを取得するように修正

●XMPのフルパスが存在しないときは次にIllustratorの同階層の画像を複製できるか試すように修正

●Windows環境で作成されたファイルの配置画像収集も可能なように修正

●同じような処理を行うサブルーチンを一つに統合した

●AppleScriptにRubyをバンドルさせるのをやめた

 

まず重いIllustratorファイル対応のためXMPだけを変数に代入して、その中で文字列操作することにしました。

ただしXMPの終了タグを検知して例外を発生させているためCS2以降のファイルでしか効果はでません。

次に不安定だったAppleScriptでのIllustratorのバージョン判定をやめて、Rubyで処理することにしました。

判定方法はXMPの中に「Adobe Illustrator CS2」という文字があったら例外を発生させて処理を中止するというものです。

バージョンダウンしたファイルだとうまく動かないかもしれませんが、バージョンダウンしないよね?

次にXMPから取得したフルパスが存在しないときはIllustratorファイルと同階層にあるファイルを複製するようにして、それでも見つからないものだけエラーログに書き出すようにしました。

次にざっくりとではありますがWindows環境で作成されたIllustratorファイルからも配置画像を複製できるようにしました。

Windowsのフルパスの中にバックスラッシュが入っていることを利用しているのでWindowsのバージョンや環境によってはうまく動かないと思います。

おまけ程度の機能追加だと思ってもらえれば。

次にサブルーチンを整理しました。

最後にRubyのバンドルをやめました。

ついでにAppleScriptの名前も変えました。

 

今回の修正でだいぶ完成に近づいたと思います。

不具合などあればコメントなどでお知らせください。

ご自分で直せるのであれば、どこを直したか教えていただけるとうれしいです。

 

以下のコードでは10.9には対応できていません、。

更新が面倒になったのでコードを読みたい方はダウンロードして読んでください。

 

Ruby

#! ruby -Ku
require 'CGI'
require 'kconv'

temp = ""
linkFilePath = "" ; #リンクファイルのパスの入れ物

#XMP情報を抽出して変数に代入
def xmpRead(fileObj, temp)
    begin
        while line = fileObj.gets
            line = CGI.unescapeHTML(line)#HTMLエスケープされてるのでアンエスケープ
            line = line.toutf8
            
            #XMP終了時に例外を発生させる
            if /^<\/x:xmpmeta>/ =~ line then
                raise "loop stop" #raiseで例外を発生できる
            end
            
            if temp == ""
                temp = line
                else
                temp = temp + line
            end
        end
        rescue
        return temp #tempを返す
    end
end

def illustratorPackage(temp, linkFilePath)
    if /Adobe Illustrator CS2/ =~ temp
        raise "before CS2"
    end
    
    linkFilePath = temp.scan(/^\s+?(.+?)<\/stRef:filePath>/)
    
    if linkFilePath == []
        linkFilePath = "nil"
    end
    return linkFilePath #linkFilePathを返す
    rescue
end

temp = xmpRead(ARGF, temp)
result = illustratorPackage(temp, linkFilePath)
puts result

 

AppleScript

on open thisList
    tell application "Finder"

        --Rubyのバージョンチェック
        if exists ((home as text) & ".bash_profile") then
            set ruby_version to do shell script "source ~/.bash_profile; ruby -e 'print \"ERROR\" if RUBY_VERSION <= \"1.8.1\"'"
        else
            set ruby_version to do shell script "ruby -e 'print \"ERROR\" if RUBY_VERSION <= \"1.8.1\"'"
        end if
        
        if ruby_version is "ERROR" then
            display dialog "このスクリプトはRubyバージョンが1.8.2以上で動作します"
            error number -128
        end if
        
        --変数初期化
        set dPath to desktop as text --デスクトップのパス取得
        set noExtractFileList to "" --エラーが出たリンクファイルのパスを入れる箱
        set textFile to dPath & "収集できなかったリンクファイル.txt" --ログ書き出し 用のテキストファイルの名前
        set errorFileLog to "" --エラーが出たファイルのパスを入れる箱
        set skipFile to 0 --CS2以下のファイルのカウント用
        
        --Rubyのファイルを取得
        set my_script_name to "IllustratorPackage.rb"
        set my_script_folder to parent of (path to me) as Unicode text
        set my_script to my_script_folder & my_script_name
        set my_script to (quoted form of POSIX path of my_script)
        
        --ここからメイン処理
        repeat with k in thisList
            set input_file to (quoted form of POSIX path of contents of k) as Unicode text --Unicode textに変換しないとダメ

            if exists ((home as text) & ".bash_profile") then
                do shell script "source ~/.bash_profile; ruby " & my_script & " " & input_file --Rubyで処理して戻り値を取得
            else
                do shell script "ruby " & my_script & " " & input_file --Rubyで処理して戻り値を取得
            end if
            
            set outputList to result --変数に代入
            
            --Rubyの戻り値がnilじゃなかったら(CS3以上でリンクファイルがあれば)
            if outputList is not "nil" then
                set linkFileList to my serchSplit(outputList, ASCII character (13)) --リストにする

                --デスクトップにフォルダを作成しリンクファイルをコピーする処理へ
                set resultList to my LinkFilePackage(linkFileList, noExtractFileList, k)
                duplicate k to item 1 of resultList --デスクトップのbackFolに複製する
                
                if (item 2 of resultList) is not "" then
                    set errorFilePath to k as string
                    set errorFile to last item of (my serchSplit(errorFilePath, ":"))
                    set errorFileLog to errorFileLog & "★" & errorFile & "で収集できなかったリンクファイル" & return & (item 2 of resultList) & return
                end if
                
                delay (0.5) --同名フォルダ作成のエラーを回避するため1秒待つ
            else if outputList is "nil" then --2012.09.24追記--リンクファイルなしも収集するように変更
                set linkFileList to my serchSplit(outputList, ASCII character (13)) --リストにする
                set resultList to my LinkFilePackage(linkFileList, noExtractFileList, k)
                duplicate k to item 1 of resultList
                delay (0.5)
            else
                set skipFile to skipFile + 1
            end if
        end repeat
        
        --エラーログの書き出し
        if errorFileLog is not "" then
            try
                set OutPutText to open for access textFile with write permission
                set eof OutPutText to 0
                write "ここに書き出されたファイルは収集できませんでした。Illsutratorデータのリンク情報が正しくない可能性があります。Illustratorデータを再保存した後、再度スクリプトを使用してください。" & return & return to OutPutText
                write errorFileLog to OutPutText
                close access OutPutText
            on error errMsg
                display dialog errMsg
                close access OutPutText
            end try
        end if
    end tell
    
    if ((count thisList) - skipFile) > 0 then
        display dialog ((count thisList) as string) & "ファイル中の" & (((count thisList) - skipFile) as string) & "ファイルを収集しました"
    else
        display dialog "収集されませんでした"
    end if
end open

--デスクトップにフォルダを作成しリンクファイルをコピーする処理
to LinkFilePackage(linkFileList, noExtractFileList, k)
    tell application "Finder"
        --バックアップファイルのコピー用にデスクトップに現在時刻名のフォルダを作成する
        set dPath to desktop as text --デスクトップのパス取得
        set folName to (do shell script "date '+%Y-%m-%d %H-%M-%S'") --現在時刻取得
        set backFol to make new folder at dPath with properties {name:folName} --デスクトップにフォルダ作成
        set label index of backFol to 2 --ラベルを付ける
        
        repeat with i from 1 to count linkFileList
            try
                set linkFilePath to (item i of linkFileList) as POSIX file --as POSIX fileで:区切りのパスに戻せる
                set linkFilePath to file linkFilePath --file 〜ってしないとダメ(ファイル参照させないとダメ)
                duplicate linkFilePath to backFol with replacing --デスクトップのbackFolに複製する(同名ファイルは上書き)
            on error --複製できなかったファイルの処理(Illustratorファイルと同階層のファイルを複製)
                --Windowsで作成されたデータもざっくり判別(パスの中に\があるかどうかで判別)
                if "\\" is in (item i of linkFileList) then
                    set errorLinkName to last item of (my serchSplit((item i of linkFileList), "\\")) --ファイル名をサブルーチンで取得
                else
                    set errorLinkName to last item of (my serchSplit(linkFilePath as Unicode text, ":")) --ファイル名をサブルーチンで取得
                end if
                
                --同一階層からリンクファイルをコピーする
                try
                    set illFileFol to (container of k) as Unicode text --illustratorファイルの内包されているフォルダを取得
                    set linkFilePath2 to file (illFileFol & errorLinkName) as Unicode text --file 〜ってしないとダメ(ファイル参照させないとダメ)
                    duplicate linkFilePath2 to backFol with replacing --デスクトップのbackFolに複製する(同名ファイルは上書き)
                on error
                    --同階層からもコピーできなければエラーログに代入する
                    set noExtractFileList to noExtractFileList & (errorLinkName as string) & return
                end try
            end try
        end repeat
        
        return {backFol, noExtractFileList} --メインルーチンにListで戻す
    end tell
end LinkFilePackage

--分割サブルーチン
to serchSplit(targetStr, splitStr)
    set str to targetStr as Unicode text
    set OriginalDelimiters to AppleScript's text item delimiters
    set AppleScript's text item delimiters to splitStr
    set itemsList to text items of str
    set AppleScript's text item delimiters to OriginalDelimiters
    
    --itemsListにリストで代入されているからあとはご自由に
    return itemsList
end serchSplit

 

 

ダウンロードはこちら。

IllustratorPackage