#はじめに
この記事は FORK Advent Calendar 2019 19日目の記事です。
Advent Calendar といえばクリスマスに向けて1日ずつ数える習慣で、毎日1つお菓子を食べるなんて楽しみもありますよね!(以下 wikipedia より)
アドベントカレンダー (Advent calendar) は、クリスマスまでの期間に日数を数えるために使用されるカレンダーである。待降節の期間(イエス・キリストの降誕を待ち望む期間)に窓を毎日ひとつずつ開けていくカレンダーである。すべての窓を開け終わるとクリスマスを迎えたことになる。
ということで、大好きな Adobe Illustrator でお菓子を作ります!
ただしここはQiita、プログラムの記事を書かかねばなりません。Illustratorは譲れないので今回はJavaScriptで作ることにします。コードの質も甘めですがそこはご容赦ください。
やりたいこと
- Adobe IllustratorにJavaScriptでお菓子の絵を描く
IllustratorでJavaScriptを実行する方法は、
Illustratorの ファイル > スクリプト > その他のスクリプト
で読み込むか、
IllustratorのアートボードにJavaScriptのファイルをドラッグ&ドロップするかになります。その為、
- Adobe IllustratorのアートボードにJavaScriptのファイルをドラッグ&ドロップするとお菓子が出てくる
といった感じになります。
用意するもの
材料
- Adobe Illustrator
- JavaScript
本記事ではAdobe Illustrator CCを使用しております。
レシピ
英語というだけでアレルギーが出る方も多いかもしれませんが、Illustratorが使えれば割と読めます。
実装
どんなお菓子を作ろうか考えた結果、クッキーを作ることにしました!
安っぽい定番ですね。
生地作り
まずは基礎となる生地を作ります。
Illustratorのアートボードに長方形ツールで正方形を描いてみましょう。
var doc = app.activeDocument;
var dough = doc.pathItems.rectangle(-5, 5, 90, 90);
ドキュメントの指定
1行目の app.activeDocument
について
app
は対象のアプリケーションすなわちIllustrator、
activeDocument
は使用中のドキュメントになります。
正方形の描画
2行目の doc.pathItems.rectangle()
について
doc.pathItems
は1行目のドキュメントでパスオブジェクトを取り扱おうとしています。
続いて rectangle()
でパスオブジェクトの長方形ツールを使用すると書いています。
rectangle()
は rectangle(上のY座標, 左のX座標, 横幅, 高さ)
のように数字を指定し、
ここではY座標-5、X座標5の位置に横幅90×高さ90の長方形を描画すると書いています。
これで正方形ができました!
※ 画像では黒枠の正方形ですが、実際の色は選択中の色に準じます。
色づけ
続いて正方形に色をつけて美味しそうにしていきましょう。
RGBによる色指定
色を指定する場合、RGBで指定する方法とCMYKで指定する方法があります。
今回はRGBで色を指定し、RGBColor()
を使います。
var color = new RGBColor();
color.red = 255;
color.green = 0;
color.blue = 0;
このように red
green
blue
の数値を指定すると color
は rgb(255, 0, 0)
となります。
なお、CMYKで色を指定する場合は CMYKColor
で cyan
magenta
yellow
black
を指定します。
色の適応
好きな色を指定できたら、その色をつけてみましょう!
Illsutratorには塗りと線があります。
塗りはパスの内側の色を指し fillColor
、線はパスの色を指し strokeColor
で指定します。
var doc = app.activeDocument;
var dough = doc.pathItems.rectangle(-5, 5, 90, 90);
dough.fillColor = getRGB(255, 225, 150);
dough.stroked = false;
function getRGB(r, g, b) {
var color = new RGBColor();
color.red = r;
color.green = g;
color.blue = b;
return color;
}
生地の塗りに色をつけたいので dough.fillColor
に色を指定します!
ただ色を指定する度に先程のように4行書くのは手間になるので、ここでは getRGB()
という関数にしています。getRGB(255, 225, 150)
と書くと rgb(255, 225, 150)
の色が指定できます。
逆に線には色をつけないことにします。
線を使わない場合は dough.stroked = false;
と書きます。
塗りの場合は dough.filled = false;
です。
ちょっとクッキーっぽくなりましたね!
模様づけ
このクッキーのメイン、チェック柄をつけましょう。
小さいチョコレート色の正方形を追加します。
パスオブジェクト追加
doc
に新しく pathItems.rectangle()
を書くとパスオブジェクトの長方形を追加できます。
var doc = app.activeDocument;
var dough = doc.pathItems.rectangle(-5, 5, 90, 90);
dough.fillColor = getRGB(255, 225, 150);
dough.stroked = false;
var choco1 = doc.pathItems.rectangle(-5, 5, 45, 45);
choco1.fillColor = getRGB(150, 100, 50);
choco1.stroked = false;
function getRGB(r, g, b) {
var color = new RGBColor();
color.red = r;
color.green = g;
color.blue = b;
return color;
}
左上に正方形が追加されました。
コピー
同じく右下にも正方形を追加するわけですが、今度はちょっと違う方法を試してみましょう!
左上の正方形をコピーして右下に移動させます。
var doc = app.activeDocument;
var dough = doc.pathItems.rectangle(-5, 5, 90, 90);
dough.fillColor = getRGB(255, 225, 150);
dough.stroked = false;
var choco1 = doc.pathItems.rectangle(-5, 5, 45, 45);
choco1.fillColor = getRGB(150, 100, 50);
choco1.stroked = false;
var choco2 = choco1.duplicate();
choco2.position = Array(50, -50);
function getRGB(r, g, b) {
var color = new RGBColor();
color.red = r;
color.green = g;
color.blue = b;
return color;
}
choco1.duplicate()
と書くと左上の正方形 choco1
をコピーできます!
var choco2 = choco1.duplicate();
でコピーした正方形に choco2
と名前をつけ、
choco2.position = Array(50, -50);
で choco2
の位置をX座標50、Y座標-50と指定します。
これはほぼほぼクッキーといっても良いのではないでしょうか。
角丸
最後の仕上げにクッキーの角を丸くしましょう!可愛くなります。
ここであのクリッピングマスクの登場です。
グループ化
JavaScriptでクリッピングマスクを使用する場合は予めグループ化をする必要があります。
まず、先程までのクッキーをグループ化してみましょう。
var doc = app.activeDocument;
var cookie = doc.groupItems.add();
var dough = cookie.pathItems.rectangle(-5, 5, 90, 90);
dough.fillColor = getRGB(255, 225, 150);
dough.stroked = false;
var choco1 = cookie.pathItems.rectangle(-5, 5, 45, 45);
choco1.fillColor = getRGB(150, 100, 50);
choco1.stroked = false;
var choco2 = choco1.duplicate();
choco2.position = Array(50, -50);
function getRGB(r, g, b) {
var color = new RGBColor();
color.red = r;
color.green = g;
color.blue = b;
return color;
}
doc.groupItems.add()
で新しいグループを作成することが可能です。
ここでは cookie
というグループを作成し、今までの正方形を cookie.pathItems.rectangle()
とすることで cookie
というグループの中に正方形を作るように変えています。
Illustrator上で選択するとグループ化されていることを確認できます。
角丸長方形の枠を描画
マスクする為の角丸長方形を描画します。
こちらは今まで何度か出てきた pathItems
の roundedRectangle()
を使います。
var doc = app.activeDocument;
var cookie = doc.groupItems.add();
var dough = cookie.pathItems.rectangle(-5, 5, 90, 90);
dough.fillColor = getRGB(255, 225, 150);
dough.stroked = false;
var choco1 = cookie.pathItems.rectangle(-5, 5, 45, 45);
choco1.fillColor = getRGB(150, 100, 50);
choco1.stroked = false;
var choco2 = choco1.duplicate();
choco2.position = Array(50, -50);
var outline = cookie.pathItems.roundedRectangle(-5, 5, 90, 90, 10, 10);
function getRGB(r, g, b) {
var color = new RGBColor();
color.red = r;
color.green = g;
color.blue = b;
return color;
}
cookie.pathItems.roundedRectangle(-5, 5, 90, 90, 10, 10)
でグループの中に角丸長方形が追加できます。
rectangle()
の引数に続いて 角丸の水平(横)方向の半径
角丸の垂直(縦)方向の半径
を指定します。
roundedRectangle(上のY座標, 左のX座標, 横幅, 高さ, 角丸の水平方向の半径, 角丸の垂直方向の半径)
です。
クリッピングマスク
最後の最後、クリッピングマスクで角丸長方形にします!
クリッピングマスクは簡単、グループの clipped
を true
にします。
var doc = app.activeDocument;
var cookie = doc.groupItems.add();
var dough = cookie.pathItems.rectangle(-5, 5, 90, 90);
dough.fillColor = getRGB(255, 225, 150);
dough.stroked = false;
var choco1 = cookie.pathItems.rectangle(-5, 5, 45, 45);
choco1.fillColor = getRGB(150, 100, 50);
choco1.stroked = false;
var choco2 = choco1.duplicate();
choco2.position = Array(50, -50);
var outline = cookie.pathItems.roundedRectangle(-5, 5, 90, 90, 10, 10);
cookie.clipped = true;
function getRGB(r, g, b) {
var color = new RGBColor();
color.red = r;
color.green = g;
color.blue = b;
return color;
}
これでチェック柄の生地が角丸になりました!
完成
とても美味しそうなクッキーができましたね!
JavaScriptで絵を描くというと難しそうに聞こえるかもしれませんが、一つ一つの処理を追っていくと意外と簡単に描けると感じてもらえたのではないかと思います。
おまけ
1つだけだと寂しいので追加で2種類用意してみました!
コードはこちら
/**
* const
*
*/
const DOC = app.activeDocument;
const COLOR_DOUGH = getRGB(255, 225, 150);
if (app.documents.length > 0) {
rand = Math.floor(Math.random() * 4) + 1;
if (rand == 1) {
bakeCookie1();
} else if (rand == 2) {
bakeCookie2();
} else if (rand == 3) {
bakeCookie3();
}
}
/**
* bakeCookie1
*
*/
function bakeCookie1() {
var cookie = DOC.groupItems.add();
var dough = cookie.pathItems.rectangle(-5, 5, 90, 90);
dough.fillColor = COLOR_DOUGH;
dough.stroked = false;
var choco1 = cookie.pathItems.rectangle(-5, 5, 45, 45);
choco1.fillColor = getRGB(150, 100, 50);
choco1.stroked = false;
var choco2 = choco1.duplicate();
choco2.position = Array(50, -50);
var outline = cookie.pathItems.roundedRectangle(-5, 5, 90, 90, 10, 10);
cookie.clipped = true;
}
/**
* bakeCookie2
*
*/
function bakeCookie2() {
var cookie = DOC.groupItems.add();
var point = 24;
var dough = cookie.pathItems.star(50, -50, 50, 45, point);
dough.fillColor = COLOR_DOUGH;
dough.stroked = false;
for (i = 0; i < (point * 2); i++) {
var anchorLeft = (i == 0) ? dough.pathPoints[(point * 2) - 1].anchor : dough.pathPoints[i - 1].anchor;
var anchorRight = (i == (point * 2) - 1) ? dough.pathPoints[0].anchor : dough.pathPoints[i + 1].anchor;
dough.pathPoints[i].leftDirection = anchorLeft;
dough.pathPoints[i].rightDirection = anchorRight;
}
for (i = (point * 2 - 1); i >= 0; i--) {
if (i % 2 == 0) dough.pathPoints[i].remove();
}
var dot = cookie.groupItems.add();
var dotColor = getRGB(200, 150, 100);
var dotDiameter = 3;
var dotOut = dot.pathItems.ellipse(-25, 25, 50, 50);
dotOut.filled = false;
dotOut.strokeColor = dotColor;
dotOut.strokeDashes = [0, (50 * 3.14 * 2 / point)];
dotOut.strokeCap = StrokeCap.ROUNDENDCAP;
dotOut.strokeWidth = dotDiameter;
var dotIn = dot.pathItems.ellipse(-37.5, 37.5, 25, 25);
dotIn.filled = false;
dotIn.strokeColor = dotColor;
dotIn.strokeDashes = [0, (25 * 3.14 * 4 / point)];
dotIn.strokeCap = StrokeCap.ROUNDENDCAP;
dotIn.strokeWidth = dotDiameter;
dot.opacity = 25.0;
}
/**
* bakeCookie3
*
*/
function bakeCookie3() {
var cookie = DOC.groupItems.add();
var dough = cookie.pathItems.ellipse(-0, 0, 100, 100);
dough.fillColor = COLOR_DOUGH;
dough.stroked = false;
var almond = cookie.groupItems.add();
var body = almond.pathItems.ellipse(-35, 35, 30, 40);
var ld = body.pathPoints[1].leftDirection;
var rd = body.pathPoints[1].rightDirection;
body.pathPoints[1].anchor = Array(50, -25);
body.pathPoints[1].leftDirection = Array(ld[0] + 5, body.pathPoints[1].anchor[1]);
body.pathPoints[1].rightDirection = Array(rd[0] - 5, body.pathPoints[1].anchor[1]);
body.fillColor = getRGB(200, 150, 100);
body.stroked = false;
var lineColor = getRGB(175, 125, 100);
var line1 = body.duplicate();
line1.filled = false;
line1.strokeColor = lineColor;
line1.width = 20;
line1.position = Array(body.position[0] + 5, body.position[1]);
var line2 = body.duplicate();
line2.filled = false;
line2.strokeColor = lineColor;
line2.width = 10;
line2.position = Array(body.position[0] + 10, body.position[1]);
}
/**
* getRGB
*
*/
function getRGB(r, g, b) {
var color = new RGBColor();
color.red = r;
color.green = g;
color.blue = b;
return color;
}
このコードをIllusratorに持ってくるとランダムで1種類クッキーが出てきます。プログラムっぽい!
他2種類もどんなことをしているか簡単にご紹介します。
ギザギザクッキー
ギザギザのクッキーです!
コードでいうと bakeCookie2()
です。
最初のクッキーと違う点をピックアップすると
- スターツール
- 破線
このあたりが特徴的かと思います。
スターツール
ギザギザな図形を作るのにスターツールを使います。
var point = 24;
var dough = cookie.pathItems.star(50, -50, 50, 45, point);
スターツールは pathItems.star()
を使います。
中心のX座標
中心のY座標
外側の点の半径
内側の点の半径
点の数
を引数に指定します。
破線
真ん中の点々を描いていきます。
今回は点線の正円を大小2つ描いています。
Illustratorで点線を描く時は破線にして線端を丸型線端、線分を0にすると簡単にできちゃいます。
var dot = cookie.groupItems.add();
var dotColor = getRGB(200, 150, 100);
var dotDiameter = 3;
var dotOut = dot.pathItems.ellipse(-25, 25, 50, 50);
dotOut.filled = false;
dotOut.strokeColor = dotColor;
dotOut.strokeDashes = [0, (50 * 3.14 * 2 / point)];
dotOut.strokeCap = StrokeCap.ROUNDENDCAP;
dotOut.strokeWidth = dotDiameter;
var dotIn = dot.pathItems.ellipse(-37.5, 37.5, 25, 25);
dotIn.filled = false;
dotIn.strokeColor = dotColor;
dotIn.strokeDashes = [0, (25 * 3.14 * 4 / point)];
dotIn.strokeCap = StrokeCap.ROUNDENDCAP;
dotIn.strokeWidth = dotDiameter;
破線は strokeDashes
を使います。 破線の線分と間隔は [線分, 間隔]
と指定します。
線端は strokeCap
を使い、丸型線端は StrokeCap.ROUNDENDCAP
になります。
線幅は strokeWidth
で指定できます。
アーモンドクッキー
アーモンドをトッピングしてみました!
コードでいうと bakeCookie3()
で、アーモンドは
- アンカーの移動
- アンカーのハンドル操作
このあたりが特徴的かと思います。
アンカーの移動
アーモンドの形は楕円を描いた後に上のアンカーを移動して尖らせています。
var body = almond.pathItems.ellipse(-35, 35, 30, 40);
~ 略 ~
body.pathPoints[1].anchor = Array(50, -25);
パスオブジェクトの pathPoints
でアンカーを取り扱うことができます。
今回は楕円の上のアンカー body.pathPoints[1]
の位置を anchor
で指定します。
body.pathPoints[1].anchor = Array(50, -25);
でX座標50、Y座標-25とすることで元の位置しています。
アンカーのハンドル操作
アーモンドの上を尖らせる為にハンドルも操作して調整します。
var body = almond.pathItems.ellipse(-35, 35, 30, 40);
var ld = body.pathPoints[1].leftDirection;
var rd = body.pathPoints[1].rightDirection;
body.pathPoints[1].anchor = Array(50, -25);
body.pathPoints[1].leftDirection = Array(ld[0] + 5, body.pathPoints[1].anchor[1]);
body.pathPoints[1].rightDirection = Array(rd[0] - 5, body.pathPoints[1].anchor[1]);
body.pathPoints[1].anchor = Array(50, -25);
ハンドルは leftDirection
で左側のハンドル、rightDirection
で右側のハンドルの座標を指定できます。
anchor
でアンカーの座標を移動してもハンドルの座標は変わらない為、ハンドルの長さを変えない場合も移動させる必要があります。
今回は移動前に ld
rd
に元々のハンドルの座標を代入しておき、移動後に改めてその値を使っています。
ld[0] + 5
は移動前のハンドルのX座標を少しアンカー寄りに近づけた数値です。
body.pathPoints[1].anchor[1]
は移動後のアンカーのY座標です。
このようにアンカー、ハンドルも自由に操作できるので好きなカーブを描くことも可能です!
まとめ
普通にIllustratorで描いた方が圧倒的に速いです。が、JavaScriptで描くのも楽しかったです!
Illsutratorで作るものがあるけど今日はコード書きたいなって気分の時なんかにオススメします。
参考
Illustrator Scripting
Adobe Illustrator CC 2017 Reference: JavaScript
FORK Advent Calendar 2019
18日目 今年の正月はNuxtとFirebaseで作ったカードゲームで甥っ子に尊敬されたい @yoh_zzzz さん
20日目 日本語で書く言語 @re_sai さん