【Illustrator】アートボードを追加

Adobeフォーラムに投稿された「新規アートボードの位置が不便」という話が、いかにもスクリプト向きで、自分でも同じように不便だったのを思い出し、練習がてら書いてみたものです。
新規アートボードを追加する場所は変えられますか?Illustratorコミュニティフォーラム (Japan)

「いいね!」 1
  • すべてのアートボードサイズが同一で、規則正しいピッチで配置されていることを前提とします
  • 実行前にすべてのアートボードを再配置…にて位置を整えておいてください
  • 最初のアートボードと、次のアートボードの位置関係を見て、追加すべき位置を計算します
  • アートボードが一つしかない場合は、右横に追加します
  • アートボードが折り返している個数を調べ、それに従います
  • アートボードがはみ出す際のエラー処理は行っていません(要改善)
/*
AddArtboard.jsx
Copyright (c) 2018 Takeshi Umeda (noellabo)
Released under the MIT license
http://opensource.org/licenses/mit-license.php
http://noellabo.jp/
ver. 0.1.0
*/

#target "illustrator"

(function() {

	var SCRIPT_TITLE = 'AddArtboard';
	var SCRIPT_VERSION = '0.1.0';

    // Alert Messages (Please translate to the language you use)
    var MESSAGE = {
        en : {
            DocumentNotExist : 'Can not execute, becouse document is not exist.',
            ExceptionMessage : 'An error occurred and processing could not be executed.\nError Message:',
        },
        ja : {
            DocumentNotExist : 'ドキュメントがないため実行できません',
            ExceptionMessage : 'エラーが発生して処理を実行できませんでした\nエラー内容:',
        },
    }.ja; // Replacing with your language key.

    if(app.documents.length == 0) {
		alert(MESSAGE.DocumentNotExist);
    } else {
        try {
            var doc = app.activeDocument;
            mainProcess();
        } catch(e) {
            alert(MESSAGE.ExceptionMessage + e);
       }
    }

	function mainProcess() {
        var artboards = doc.artboards;
        var rect_0 = artboards[0].artboardRect;

        var distance = [
            (rect_0[2] - rect_0[0]) * 1.1,
            (rect_0[3] - rect_0[1]) * 1.1
        ];
        var columns = 0;
        var x = 0;
        var y = 1;

        if(artboards.length >= 2) {
            var rect_1 = artboards[1].artboardRect;
            x = (rect_0[1] == rect_1[1]) ? 0 : 1;
            y = 1 - x;
            distance[x] = rect_1[x]-rect_0[x];
            for(var i=2; i<artboards.length; i++) {
                var rect_i = artboards[i].artboardRect;
                if(rect_0[y] != rect_i[y]) {
                    distance[y] = rect_i[y] - rect_0[y];
                    columns = i;
                    break;
                }
            }
        }

        if(columns == 0) {
            distance[x] = artboards.length * distance[x];
            distance[y] = 0;
        } else {
            distance[x] =            artboards.length % columns  * distance[x];
            distance[y] = Math.floor(artboards.length / columns) * distance[y];
        }
        artboards.add([
            rect_0[0] + distance[0],
            rect_0[1] + distance[1],
            rect_0[2] + distance[0],
            rect_0[3] + distance[1],
        ]);
    }
}());
「いいね!」 1

やり方がわからないものリスト(わかったら誰か教えて!)

  • Illustratorの最大作業エリア(?)のサイズの取得
    • 固定値という話もあるので、調べれば済むのかと思いますが……
    • これを使って、アートボードがはみ出る場合は折り返しするようにしたい
    • 「それ以上いけない」というエラーを出すべき
  • ブリードの取得
    • 設定出来ないのはBleed.aip.zipにて @ten_A_cclab さんがねじ伏せてましたがw、取得するだけならプラグイン無しで解決できないか?
    • アートボードが単独の時の初期値に使おうと思うが、別に要らないかもしれない……
  • 新規や再配置の際の設定値ってどこかに記録されてる?
  • アートボードの最大作成可能数
    • 本体バージョンをみるしかないかなー

ほへー勉強になる……
en/jaのキー切り替えとか……

『連想配列を使ったプロパティへの値の代入と参照 - オブジェクト - JavaScript入門』https://www.ajaxtower.jp/js/object/index4.html

ほー

言語切り替えライブラリとか大げさ過ぎるので、こーゆー簡易な書き方もアリじゃないかと。

フォーマットの大部分は高橋としゆきさんのマネだよ!
いろんな人のスクリプト見ると、ちょっとずつ書き方違ってて勉強になるよね〜。

言語切替には
localizeという関数が用意されているのでそれを使うとよさそうです。
$.localize = true;
localize({ja:“日本語”, en : “English”});
こうすれば多言語対応楽勝ですよ。

「いいね!」 1

localize、Illustratorのドキュメントだけ探してると全く見つからない……。

JavaScript Tools Guide CCLocalizing ExtendScript stringsが参照しやすいですね。
(サイト自体はAfter Effectsのリソースみたいですが……)

  • 言語による語順の入れ替わり対応に%1, %2などで順番を指定して埋め込みできる
    • localize({ja:"%2年%1月", en:"%1/%2"}, date.getMonth() + 1, date.getFullYear())
  • 複数の言語から実行環境に合わせて適切なものを選んでくれる
    • 該当する言語がなければenを表示
    • en_GB, en_US など、リージョンによるアメリカ式、イギリス式の区別等も可
    • en_GB_Win, en_GB_Mac など、‘Win’, ‘Mac’, ‘Unix’ があればプラットフォームの区別も可
  • $.locale = "en";などとして上書きすることで、特定の環境での結果をテストできる
    • $.locale = null;で元に戻る
  • $.localize = true; としておけばlocalize()としなくても自動で言語切り替えしてくれる機能あり
    • これだけでOKということ
    $.localize = true;
    const DocumentNotExist = {
        en: 'Can not execute, becouse document is not exist.',
        ja: 'ドキュメントがないため実行できません',
    };

    alert(DocumentNotExist);

というわけで、さっそく変更しました。便利ネー。

「いいね!」 2

あー設定ファイル掘ると出てくる%1ってのはこれかー

◎Illustratorの最大作業エリアのサイズの取得
これは達人も苦労しているものです。最近omotiさんがシンプルな記法を開発しました。
https://forums.adobe.com/thread/2459293
ただ単にtryで囲って,エラーが出たら座標をずらすほうが簡単かもしれません。

◎ブリード・新規や再配置の際の設定取得

var pref = app.preferences ;

// 新規ドキュメントのときのブリード。開いている書類がこの設定かどうかはわからない。
// CCで新規ドキュメント画面が変わったので今は使われてないかもしれない
pref.getRealPreference('artnewdialog/leftBleedSize') ;
pref.getRealPreference('artnewdialog/topBleedSize') ;
pref.getRealPreference('artnewdialog/rightBleedSize') ;
pref.getRealPreference('artnewdialog/bottomBleedSize') ;

// 新規ドキュメントのときのアートボード間隔
pref.getRealPreference('artnewdialog/artboardSpacing') ;

// 再配置のアートボード間隔
pref.getRealPreference('plugin/ArtboardRearrange/ArtboardSpacing') ;

◎アートボードの最大作成可能数
複数バージョン対応を考えると,バージョンを見るのが楽そうです。

「いいね!」 1

話はずれますが、わたしはというと基本的に某社のドキュメント類は全く信用していませんのでスクリプトを書く場合はオブジェクトの調査から始めます。例えば

var tg=app.selection[0];for(var a in tg) $.writeln(a+":"+tg[a]);

このようなコードでオブジェクト総ざらいを行って対象のプロパティと値をリストアップします。
以下はIllustrator2017にて$.globalについてリストアップしたものです。

app:[Application Adobe Illustrator]
ElementPlacement:ElementPlacement
ScreenMode:ScreenMode
ColorType:ColorType
DocumentColorSpace:DocumentColorSpace
DocumentPresetType:DocumentPresetType
DocumentRasterResolution:DocumentRasterResolution
DocumentTransparencyGrid:DocumentTransparencyGrid
DocumentPreviewMode:DocumentPreviewMode
DocumentArtboardLayout:DocumentArtboardLayout
ImageColorSpace:ImageColorSpace
StrokeCap:StrokeCap
StrokeJoin:StrokeJoin
PathPointSelection:PathPointSelection
PointType:PointType
TextType:TextType
TextAntialias:TextAntialias
GradientType:GradientType
TextOrientation:TextOrientation
CropOptions:CropOptions
RasterLinkState:RasterLinkState
TabStopAlignment:TabStopAlignment
Justification:Justification
Transformation:Transformation
LibraryType:LibraryType
DocumentType:DocumentType
ExportType:ExportType
ColorReductionMethod:ColorReductionMethod
ColorDitherMethod:ColorDitherMethod
Compatibility:Compatibility
PDFXStandard:PDFXStandard
PDFCompatibility:PDFCompatibility
PhotoshopCompatibility:PhotoshopCompatibility
CompressionQuality:CompressionQuality
ColorConversion:ColorConversion
ColorDestination:ColorDestination
ColorProfile:ColorProfile
MonochromeCompression:MonochromeCompression
PDFTrimMarkWeight:PDFTrimMarkWeight
PDFOverprint:PDFOverprint
PDFPrintAllowedEnum:PDFPrintAllowedEnum
PDFChangesAllowedEnum:PDFChangesAllowedEnum
DownsampleMethod:DownsampleMethod
EPSPreview:EPSPreview
EPSPostScriptLevelEnum:EPSPostScriptLevelEnum
PrinterPostScriptLevelEnum:PrinterPostScriptLevelEnum
SaveOptions:SaveOptions
RulerUnits:RulerUnits
BlendModes:BlendModes
KnockoutState:KnockoutState
ZOrderMethod:ZOrderMethod
SVGDTDVersion:SVGDTDVersion
SVGFontType:SVGFontType
SVGFontSubsetting:SVGFontSubsetting
SVGDocumentEncoding:SVGDocumentEncoding
SVGCSSPropertyLocation:SVGCSSPropertyLocation
SVGIdType:SVGIdType
RasterImageLocation:RasterImageLocation
OutputFlattening:OutputFlattening
ColorModel:ColorModel
SpotColorKind:SpotColorKind
FlashExportStyle:FlashExportStyle
ArtClippingOption:ArtClippingOption
FlashExportVersion:FlashExportVersion
FlashImageFormat:FlashImageFormat
LayerOrderType:LayerOrderType
BlendAnimationType:BlendAnimationType
FlashJPEGMethod:FlashJPEGMethod
FlashPlaybackSecurity:FlashPlaybackSecurity
VariableKind:VariableKind
AutoCADExportFileFormat:AutoCADExportFileFormat
AutoCADCompatibility:AutoCADCompatibility
AutoCADUnit:AutoCADUnit
AutoCADColors:AutoCADColors
AutoCADRasterFormat:AutoCADRasterFormat
AutoCADExportOption:AutoCADExportOption
AutoCADGlobalScaleOption:AutoCADGlobalScaleOption
TIFFByteOrder:TIFFByteOrder
UserInteractionLevel:UserInteractionLevel
PolarityValues:PolarityValues
JavaScriptExecutionMode:JavaScriptExecutionMode
PrintArtworkDesignation:PrintArtworkDesignation
PrintingBounds:PrintingBounds
PrintColorSeparationMode:PrintColorSeparationMode
PrintOrientation:PrintOrientation
PrintPosition:PrintPosition
PrintTiling:PrintTiling
PageMarksTypes:PageMarksTypes
PrintFontDownloadMode:PrintFontDownloadMode
FontSubstitutionPolicy:FontSubstitutionPolicy
PostScriptImageCompressionType:PostScriptImageCompressionType
PrintColorProfile:PrintColorProfile
PrintColorIntent:PrintColorIntent
PrinterTypeEnum:PrinterTypeEnum
PrinterColorMode:PrinterColorMode
InkPrintStatus:InkPrintStatus
InkType:InkType
TrappingType:TrappingType
AutoKernType:AutoKernType
AutoLeadingType:AutoLeadingType
CaseChangeType:CaseChangeType
FontCapsOption:FontCapsOption
FontBaselineOption:FontBaselineOption
FontOpenTypePositionOption:FontOpenTypePositionOption
FigureStyleType:FigureStyleType
BaselineDirectionType:BaselineDirectionType
LanguageType:LanguageType
AlternateGlyphsForm:AlternateGlyphsForm
StyleRunAlignmentType:StyleRunAlignmentType
WariChuJustificationType:WariChuJustificationType
BurasagariTypeEnum:BurasagariTypeEnum
KinsokuOrderEnum:KinsokuOrderEnum
PDFBoxType:PDFBoxType
TracingMethodType:TracingMethodType
TracingModeType:TracingModeType
TracingColorType:TracingColorType
ViewType:ViewType
RasterizationColorModel:RasterizationColorModel
AntiAliasingMethod:AntiAliasingMethod
ColorConvertPurpose:ColorConvertPurpose
FXGVersion:FXGVersion
FiltersPreservePolicy:FiltersPreservePolicy
TextPreservePolicy:TextPreservePolicy
GradientsPreservePolicy:GradientsPreservePolicy
BlendsExpandPolicy:BlendsExpandPolicy
CoordinateSystem:CoordinateSystem
SymbolRegistrationPoint:SymbolRegistrationPoint
PerspectiveGridPlaneType:PerspectiveGridPlaneType
FirstBaselineType:FirstBaselineType
DocumentLayoutStyle:DocumentLayoutStyle
aftereffects14:[object Object]
aftereffects:[object Object]
bridge7:[object Object]
bridge:[object Object]
bridge8:[object Object]
indesign12:[object Object]
apps:aftereffects-14.0,ame-11.0,ame-6.0,audition-10.0,bridge-2.0,bridge-5.064,bridge-7.064,bridge-8.064,devicecentral-1.0,dreamweaver-17.0,estoolkit-2.0,estoolkit-3.8,estoolkit-4.0,exman-6.0,flash-16.0,illustrator-17.064,illustrator-20.064,illustrator-21.064,illustrator-22.064,indesign-12.064,indesign-13.064,indesign-5.0,indesign-8.0,photoshop-110.032,photoshop-120.032,premierepro-11.0,stockphotos-1.5,switchboard-2.0
indesign:[object Object]
indesign13:[object Object]
tempPSVersionInfo:[object Object]
photoshop:[object Object]
AvailabilityCheckOptions:
function AvailabilityCheckOptions (inBusyAction, inWarnIfUnavailable)
	{
	// control how a busy PS is handled	
	this.busyAction = (inBusyAction == null) ? AvailabilityCheckOptions.kBusyAsk : inBusyAction;
	this.warnBusyText = localize ("$$$/PSBI/Error/PSBusyWarn=Photoshop %1 is currently busy with another task. Please finish that task in Photoshop and try again.", photoshop.versionInfo.displayVersion);
	this.askBusyText = localize ("$$$/PSBI/Error/PSBusyAsk=Photoshop %1 is currently busy with another task. Would you like to queue this command?", photoshop.versionInfo.displayVersion);
	
	// control how an uninstalled version of PS is controlled
	this.warnIfUnavailable = (inWarnIfUnavailable == null) ? true : inWarnIfUnavailable;
	this.warnInsidePSText = localize ("$$$/PSBI/Error/OtherVersionRunningInPS=Photoshop %1 is required for this command. Please quit this version and try again.", photoshop.versionInfo.displayVersion);

	// used to prevent UI from being shown twice in same call stack;
	// this gets set and the return value is remembered
	this.alreadyUsed = false;
	this.alreadyUsedReturnValue = false;
	}

photoshop110:[object Object]
FL:[object Object]
fl:[object Object]
flashAppName:flash-16.0
bridgeAppName:bridge
placeInFlashMenu:undefined
placeInFlashLibMenu:undefined
placeLinkCmd:undefined
contextMenu:undefined
subMenuBrush:undefined
subMenuGraphic:undefined
subMenuSwatch:undefined
subMenuSymbol:undefined
illustrator:[object Object]
Point:
function (x,y) { return new Array( x, y ); }

Rect:
function (l,t,r,b) { return new Array( l,t,r,b ); }

場合によってはparentやchildも対象に調べて機能実装が可能かどうかを検討します。しかし。掘り進めると何だコレってオブジェクトが見つかるので脇にそれて本来何を調べていたのか忘れてしまいますw
…しかしながら調査にはPropertyExplorer使うのが一番楽チンではあります(^-^)/

「いいね!」 1

いろいろ反映させたヤツです。

  • @kurosuke さんにアドバイスいただいた多言語対応を取り入れました
  • omotiさんのチート記法を使わせていただいて、キャンバスに収まるように折り返し、はみ出る場合に警告して止まるようにしました
  • @sttk3com さんに教えていただいたアートボード間隔を取得して、間隔のデフォルト値にしました
  • アートボードの最大作成可能数をバージョン判別でチェックするようにしました
  • こっそり複数追加できるようにしましたが、UIがないので、numを直接変更してください
#target "illustrator"
/*
AddArtboard.jsx
Copyright (c) 2018 Takeshi Umeda (noellabo)
Released under the MIT license
http://opensource.org/licenses/mit-license.php
http://noellabo.jp/
ver. 0.2.0
*/

(function() {

	const SCRIPT_TITLE = 'AddArtboard';
	const SCRIPT_VERSION = '0.2.0';

    // Alert Messages (Please translate to the language you use)
    $.localize = true;
    const DocumentNotExist = {
        en: 'Can not execute, becouse document is not exist.',
        ja: 'ドキュメントがないため実行できません',
    };
    const ExceptionMessage = {
        en: 'An error occurred and processing could not be executed.\nError Message:',
        ja: 'エラーが発生して処理を実行できませんでした\nエラー内容:',
    };
    const ArtboardLimit = {
        en: 'It exceeds the maximum creable number of artboard',
        ja: 'アートボードの最大作成可能数を超えています',
    };
    const ArtboardNoEtnoughSpace = {
        en: 'There is not enough space to create the artboard',
        ja: 'アートボードを作成する十分なスペースがありません',
    };

    if(app.documents.length == 0) {
		alert(DocumentNotExist);
    } else {
        try {
            var doc = app.activeDocument;
            var pref = app.preferences;
            mainProcess();
        } catch(e) {
            alert(ExceptionMessage + e);
        }
    }

    // This function was Written by OMOTI
    // https://forums.adobe.com/thread/2459293
    function getLargestBounds() {  
        var tempLayer,  
            tempText,  
            left,  
            top,  
            LARGEST_SIZE = 16383;  
        if (!app.documents.length) {  
            return;  
        }  
        tempLayer = app.activeDocument.layers.add();  
        tempText = tempLayer.textFrames.add();  
        left = tempText.matrix.mValueTX;  
        top = tempText.matrix.mValueTY;  
        tempLayer.remove();
        return new Rect(  
            left,  
            top,
            left + LARGEST_SIZE,  
            top - LARGEST_SIZE,
        );

    }  

    function mainProcess() {
        var artboards = doc.artboards;
        var artboards_len = artboards.length;
        var artboard_limit = (parseFloat(app.version) >= 22) ? 1000 : 100;
        var num = 1;

        if(artboards_len + num > artboard_limit) {
            alert(ArtboardLimit);
            return;
        }

        var rect_0 = artboards[0].artboardRect;

        // var spacing = pref.getRealPreference('artnewdialog/artboardSpacing'); // new dialog
        var spacing = pref.getRealPreference('plugin/ArtboardRearrange/ArtboardSpacing'); // rearrange
        var distance = [
            rect_0[2] - rect_0[0] + spacing,
            rect_0[3] - rect_0[1] - spacing
        ];
        var columns = 0;
        var rows = 0;
        var x = 0;
        var y = 1;

        if(artboards_len >= 2) {
            var rect_1 = artboards[1].artboardRect;
            x = +(rect_0[0] == rect_1[0]);
            y = 1 - x;
            distance[x] = rect_1[x]-rect_0[x];
            for(var i=2; i<artboards_len; i++) {
                var rect_i = artboards[i].artboardRect;
                if(rect_0[y] != rect_i[y]) {
                    distance[y] = rect_i[y] - rect_0[y];
                    columns = i;
                    break;
                }
            }
        }

        var canvas_rect = getLargestBounds();

        var unit_rect = [
            rect_0[0] + Math.abs(distance[0]),
            rect_0[1] - Math.abs(distance[1]),
            rect_0[0],
            rect_0[1],
        ];

        var xx = x ^ +(distance[x] < 0) ? x : x+2;
        var yy = y ^ +(distance[y] < 0) ? y : y+2;

        columns = columns || 
                  Math.abs(Math.floor((canvas_rect[xx] - unit_rect[xx]) / distance[x]));
        rows    = Math.abs(Math.floor((canvas_rect[yy] - unit_rect[yy]) / distance[y]));

        if(artboards_len + num > columns * rows) {
            alert(ArtboardNoEtnoughSpace);
            return;
        }

        for(var index=artboards_len; num>0; num--, index++) {
            var pos = [];
            pos[x] =            index % columns  * distance[x];
            pos[y] = Math.floor(index / columns) * distance[y];

            artboards.add([
                rect_0[0] + pos[0],
                rect_0[1] + pos[1],
                rect_0[2] + pos[0],
                rect_0[3] + pos[1],
            ]);
        }

    }
}());
「いいね!」 1