スポンサーサイト

Tags :
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

画像の色の分布を『xy色度図』にプロットしてみる(あと、CMYKプロファイルの事も少し)

MacOSX付属の『Grapher』を使った画像の色の分布図の作成その2。

今回は、カラーマネジメント関係の書籍等には必ず出てくる、馬蹄形の『xy色度図』上の座標に、画像の色の分布をプロットしてみます。

前のエントリではPhotoshopで画像を開き、JavaScriptを使ってサンプリングしたピクセルの『L*a*b*値』をファイルに書き出して、そのファイルをGrapherに読み込ませて表示させましたが、今回はピクセルの色を『xyY』の値で書き出すので、『L*a*b*』から『xyY』の値に変換する部分をJavaScriptに新たに書き加えました。

今回は色度を表す『xy』の二次元のグラフなので、明度を示す『Y』の値は使いません。

『L*a*b*』から『xyY』ヘの変換式は、
Color Conversion Algorithms 』(http://www.cs.rit.edu/~ncs/color/t_convert.html)や、
Color Conversion Library in ANSI C』 (http://www.tecgraf.puc-rio.br/~mgattass/color/ColorIndex.html)
あたりをを参考にしています。

PhotoshopのAdobeRGB環境で下のグラデーデョン画像を開き、JavaScriptを実行して書き出されたファイルをGrapherで読み込んで、色度図にプロットしてみます。


赤と緑の三角形の部分はそれぞれ『AdobeRGB』と『sRGB』の色域を表していますが、それらは色度図上の値をあらかじめ調べておいてグラフに数値を入力しました。また、グレーの馬蹄形の部分、360nm~830nmの各波長の単色光の色度を示す『スペクトル軌跡』も別途計算して求めた数値を読み込ませてプロットしてあります。


上のグラデーション画像を『JapanColor2001corted』のプロファイル、レンダリングインテントが『知覚的』の設定でCMYKに変換した場合の色の分布を見てみると、色域が以下の様に圧縮されているのが解ります。



次に、下の画像は始めからCMYKモードで作成した、CMYK各色100%と、その二次色のレッド、グリーン、ブルーをグラデーションにしたもので、


これを『JapanColor2001corted』で開いた状態でプロットしてみると、非常になめらかな色の分布を持つグラフがプロットされました。


同じ画像を、『某印刷所の本機(枚葉)の印刷物を測色して作成したプロファイル』を適用した状態でプロットすると、

ややいびつな輪郭でプロットされました。グリーン(上の頂点の部分)の色域がやや狭く、イエロー方向に転んでいるのが見て取れます。

ただ、これはいびつなプロファイルが悪いと言うのではなく、あくまで『プロファイル』として実際の印刷物の状態を表したものなので、特に、JapanColorをターゲットとした『印刷の標準化』が行われていない印刷会社では、おそらく色が合わない等の問題も出てくる筈なので、必ずしも『JapanColor2001corted』の方が良い結果になるとは言い切れないと思います。

今回プロットした画像を見て思ったんですが、『JapanColor2001corted』の不自然なほど整ったプロファイルは、『理想的なJapanColor』をターゲットにして最適化の処理がされた、『架空のプロファイル』に近いものの様な気がします。

カラーマネジメントの書籍等では『CMYKのカラー設定はJapanColor2001corted推奨』というのが殆どで、もちろん出鱈目なプロファイルで運用する事に比べればベストに近い選択という事で異論は無いんですが、画像をCMYK分解する時点ではトーンジャンプも無くキレイに分解されていても、後の工程でRIPにデバイスリンクプロファイルを噛ましたり、刷版や印刷で色を調整する必要が出るとすれば、『画像が劣化する要因が他の工程に移っただけ』とも考えられるので、その辺りもツッ込んで解説してあればなぁとか思った次第です。(画像の段階で劣化しないのが望ましいとは思いますが)

画像を『xyY』の数値で書き出すのに使ったJavaScriptは以下の通り。

■動作確認
MacOSX 10.5.7
Photoshop CS4
#target Photoshop

var samplingPixelsAsYxy = {
	
	'tristimulus_values': {
		/* 2 degrees */
		'ccTA_2': [109.850, 100.000, 35.585],
		'ccTC_2': [98.074,  100.000, 118.232],
		'D50_2': [96.422,  100.000, 82.521],
		'D55_2': [95.682,  100.000, 92.149],
		'D65_2': [95.047,  100.000, 108.883],
		'D75_2': [94.972,  100.000, 122.638],
		'F2_2': [99.187,  100.000, 67.395],
		'F7_2': [95.044,  100.000, 108.755],
		'F11_2': [100.966, 100.000, 64.370],

		/* 10 degrees */
		'A_10': [111.144, 100.000, 35.200],
		'C_10': [97.285,  100.000, 116.145],
		'D50_10': [96.720,  100.000, 81.427],
		'D55_10': [95.799,  100.000, 90.926],
		'D65_10': [94.811,  100.000, 107.304],
		'D75_10': [94.416,  100.000, 120.641],
		'F2_10': [103.280, 100.000, 69.026],
		'F7_10': [95.792,  100.000, 107.687],
		'F11_10': [103.866, 100.000, 65.627],
	
		/* PCS illuminant of AdobeRGB & sRGB profiles */
		'PCS_illuminant': [96.420, 100.000, 82.491],
		
		/* reference white in xyY coordinates */
		'chromaD65': [0.3127, 0.3290, 100.0]
	},


	'convertCIELabToXYZ': function(L, a, b) {
		var ref = this.tristimulus_values['PCS_illuminant']; //tristimulus of reference white
		var X, Y, Z;
		
		/* via http://www.cs.rit.edu/~ncs/color/API_JAVA/XYZSet.java
		var frac = (L + 16) / 116;
		if ( L < 7.9996 ) {
			Y = L / 903.3;
			X = a / 3893.5 + Y;
			Z = Y - b / 1557.4;
		} else {
			var tmp = frac + a / 500;
			X = tmp * tmp * tmp * ref[0];
			Y = frac * frac * frac * ref[1];
			tmp = frac - b / 200;
			Z = tmp * tmp * tmp * ref[2];
		}
		*/
		
		/* via http://www.tecgraf.puc-rio.br/~mgattass/color/CIELabtoXYZ.htm */
		var var_Y = ( L + 16 ) / 116;
		var var_X = a / 500 + var_Y;
		var var_Z = var_Y - b / 200;
		var_Y = Math.pow(var_Y, 3) > 0.008856 ? Math.pow(var_Y, 3) : ( var_Y - 16 / 116 ) / 7.787;
		var_X = Math.pow(var_X, 3) > 0.008856 ? Math.pow(var_X, 3) : ( var_X - 16 / 116 ) / 7.787;
		var_Z = Math.pow(var_Z, 3) > 0.008856 ? Math.pow(var_Z, 3) : ( var_Z - 16 / 116 ) / 7.787;
		X = var_X * ref[0];
		Y = var_Y * ref[1];
		Z = var_Z * ref[2];
		//
		return [X, Y, Z];
	},

	'main': function() {
		var t = new Date();
		var outputFile = '~/Desktop/xy_colors_64x64.txt';
		var sampling_size = 64;
		//var threshold = 10;
		var sampling_data = '';
		var ru = app.preferences.rulerUnits;
		app.preferences.rulerUnits = Units.PIXELS;
		var doc = app.activeDocument;
		doc.flatten();
		doc.resizeImage(sampling_size, sampling_size, 72, ResampleMethod.BICUBIC);
		//doc.resizeImage(sampling_size*2, sampling_size*2, 72, ResampleMethod.NEARESTNEIGHBOR);
		
		var smpl = doc.colorSamplers.add([0, 0]);
		var col = new SolidColor();
		var Yxy_x, Yxy_y;
		var XYZ = [];
		var X, Y, Z;
		for (var i=0; i<sampling_size; i++) {
			for (var j=0; j<sampling_size; j++) {
				smpl.move([j+0.5, i+0.5]);
				col = smpl.color;
				XYZ = this.convertCIELabToXYZ(col.lab.l, col.lab.a, col.lab.b);
				X = XYZ[0]; Y = XYZ[1]; Z = XYZ[2];
				Yxy_x = X / ( X + Y + Z );
				Yxy_y = Y / ( X + Y + Z );
				if (Y > 1) { sampling_data += Yxy_x + '\t' + Yxy_y + '\r'; }
			}
		}
		
		var f = new File(outputFile);  
		if (f.open("w")) {  
			f.encoding = 'BINARY';  
			f.write(sampling_data);
			f.close();
		}
		app.preferences.rulerUnits = ru;
		var now = new Date();
		alert('Finished!   time: ' + (now - t));
	}
}

if (app.documents.length > 0) {
	samplingPixelsAsYxy.main();
}

画像の色の分布を3Dグラフにプロットしてみる

MacOSXに付属しているグラフ作成アプリ『Grapher』を使って、画像の色(L*a*b*値)の分布を3Dのグラフにプロットしてみました。

この手の情報の表示は、高価なカラーマネジメントツールを買うとか、年間18万9千円の会費を払って研究会に参加すれば実現できると思いますが、手持ちのツールを使えばまあそこそこ近い事は出来るのではないかと思いやってみました。先日のエントリ、『PhotoshopでのCMYK分解カーブをJavaScriptを使ってプロットしてみる』を書いたのも、そんなふうに思ったからです。

まず、JavaScriptを使ってPhotoshopで開いている画像を64 x 64ピクセルに縮小し、その4096のポイントをサンプリングしてそれぞれのL*a*b*値をタブ区切りのテキストでファイルに書き出します。そしてそれをGrapherで読み込んで、3Dのグラフにプロットする様にしました。

Photoshopのカラー設定でAdobeRGBが設定された状態で、下のグラデーション画像のL*a*b*値を書き出してプロットすると、



AdobeRGBの色域一杯に色が均等に分布したグラフが現れました。

このグラフは横軸にa*チャンネル(-128~128)、縦軸がb*チャンネル(-128~128)、垂直のZ軸がL*チャンネル(0~100)になっています。

同じ画像がsRGBの色空間だと、

こんな感じになります。(比較の為にAdobeRGBのプロットを表示しています)

そして下の画像はAdobeRGBのカラースペースで開いてプロットしましたが、色の分布はsRGBの空間に収まっているようです。画像を保存するまでの過程でプロファイル変換されているのかも知れません。




Photoshop&JavaScriptでピクセルの色を取得してファイルに書き出す所で、CMYK分解カーブのプロットの時と同じく、ピクセル単位での操作が今ひとつ解らず、色を取得するのに1ピクセルの選択範囲を作ってその中のヒストグラムが立った数値を調べるという回りくどい事をしています。(なので処理は劇遅。カラーサンプラーを置いて取得するのも試みましたが、さらに遅かったです)

あと、Photpshopで色を扱う、『SolidColor』オブジェクトは、RGBなど1つのカラーモードの値を与えてやれば、後はカラー設定の作業用スペースに設定されたプロファイルに応じて、CMYKやL*a*b*の値が一意に決まるので簡単に他のカラーモードでの値を取り出せるみたいです。ただ、ドキュメントのカラープロファイルは無視される様なので注意が必要です。

■2009.06.06追記
ちょっとやっつけだったコードを直しました。ピクセルの色の取得にカラーサンプラを使う様に変更してあります。ほんの少しだけですが速くなりました。


■2010.03.08追記
このエントリで使用している『Grapher』のファイルをアップロードしました。以下のリンクから落とせます。
http://dl.dropbox.com/u/271700/cielab.gcx.zip


■画像のL*a*b*値を書き出すJavaScriptのソース(遅いです)
#target Photoshop

/*
function getPixelColor(x, y) {
	var hg;
	doc.selection.select([[x, y], [x + 1, y], [x + 1, y + 1], [x, y + 1]], SelectionType.REPLACE, 0, false);
	hg = doc.channels[0].histogram;
	for (var i=0; i<256; i++) if (hg[i] != 0) { colObj.rgb.red = i; break; }
	hg = doc.channels[1].histogram;
	for (var i=0; i<256; i++) if (hg[i] != 0) { colObj.rgb.green = i; break; }
	hg = doc.channels[2].histogram;
	for (var i=0; i<256; i++) if (hg[i] != 0) { colObj.rgb.blue = i; break; }
}
*/

var t = new Date();
var sampling_size = 64;
var ru = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var doc = app.activeDocument;
doc.flatten();
doc.resizeImage(sampling_size, sampling_size, 72, ResampleMethod.BICUBIC);
doc.resizeImage(sampling_size*2, sampling_size*2, 72, ResampleMethod.NEARESTNEIGHBOR);

var smpl = doc.colorSamplers.add([0, 0]);
var sampling_data = '';

for (var i=0; i<sampling_size*2; i+=2) {
	for (var j=0; j<sampling_size*2; j+=2) {
		smpl.move([j+1, i+1]);
		sampling_data += smpl.color.lab.a + '\t' + smpl.color.lab.b + '\t' + smpl.color.lab.l + '\r';
	}
}

var f = new File('~/Desktop/clelab_colors_64x64.txt');  
if (f.open("w")) {  
	f.encoding = 'BINARY';  
	f.write(sampling_data);
	f.close();
}

app.preferences.rulerUnits = ru;
alert('Finished.   time: ' + (new Date() - t));

InDesignでSocketを使ってWeb上のファイルをローカルにダウンロードしてみる

やってみたら出来てしまったので。

InDesignのみでWebにある画像等のファイルをローカルに保存出来れば色々と出来る事が広がるんじゃないか、と思ったのでやってみました。業務等でもっとちゃんとした事やるにはWeb Access libraryに含まれるHttpConnectionオブジェクトを使って書いた方が良いと思いますが、セットアップする必要がある様だし、もっとお手軽にコピペで使えるようなもの、みたいな感じで。

今回のコードは、HTTPのリクエストを送ってレスポンスを受け取る部分と、その関数を呼び出して実際にファイルとして保存する部分とに分かれてます。

HTTPのリクエストを送って、レスポンスを受け取る部分は、関数getHttpResponse(requests)として書きましたが、これは先日のエントリのHTTPでのやり取りをするコードに、
・画像等のバイナリデータを受け取れるようにする
・Basic認証が必要なサイトに対してユーザ名とパスワードを送れるようにする
部分を新たに加えました(相変わらずOOPな書き方が全く出来てませんけど)。URLを処理する部分の正規表現はO'REILLYの『JavaScript: The Good Parts』から拝借しています。

この関数には引数を
{
	method: 'GET', 
	url: 'http://www.example.com/hogehoge.jpg',
	encoding: 'BINARY'
	basic_auth: 'ZHVtbXk6ZHVtbXk='
}
の様な連想配列で渡します。

引数の内容は以下の通り
・method リクエストのメソッド 'GET','HEAD','POST'等。省略可。デフォルトは'GET'。
・url リクエストのURL(クエリも全て含んだもの)
・encoding 受け取るデータのエンコーディング。省略可。デフォルトは'UTF-8'。
・basic_auth Basic認証に必要な、『ユーザ名:パスワード』の文字列をBase64でエンコーディングした文字列。Basic認証が必要な場合のみこの引数を与える。

この関数は戻り値として、サーバからのレスポンスをヘッダ付きのまま丸ごと返します。値のチェックは最低限の事しかやってないので変な引数を渡すと動作しません。

そして、上記の関数を呼び出してファイルに書き出し、保存する部分の関数、downloadFile(url, localFile)ですが、これの引数は、
・url ダウンロードしたいファイルのURL
・localfile ローカルでのファイル名を含めたファイルのパス('~/Desktop/hogehoge.jpg'等)
となっていて、戻り値として保存したファイルオブジェクトか返ります。

下のコードを実行すると、AdobeのサイトのCS4のパッケージ画像(http://tryit.adobe.com/jp/cs4/family/images/familyBox.jpg)がデスクトップに保存されます。(保存されるファイルのパスはMacOSX用の記述です)


■2009.3.19 追記
コードを一部修正。

■動作確認
MacOSX 10.5.6
InDesign CS4
#target InDesign

//HTTPレスポンスを得る
function getHttpResponse(requests) {
	var parseUrl = function(url) {
		var urlObj = {};
		//[url, scheme, slash, host, port, path, query, fragment] via O'REILLY JavaScript: The Good Parts
		var url_re = /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
		var m = url_re.exec(url);
		urlObj.host = m[3];
		urlObj.port = m[4] || '80';
		urlObj.path = m[5];
		urlObj.query = (m[6]) ? '?' +  m[6] : '';
		urlObj.frag = (m[7]) ? '#' + m[7] : '';
		return urlObj;
	}
	var urlObj = parseUrl(requests.url);
	var encoding = requests.encoding || 'UTF-8';
	var method = requests.method || 'GET';
	var auth = (requests.basic_auth != undefined) ? 'Authorization: Basic ' + requests.basic_auth + '\r\n' : '';
	var conn = new Socket;
	conn.timeout = 10;
	if (conn.open (urlObj.host + ':' + urlObj.port, encoding)) {
  	conn.write (method + ' /' + urlObj.path + urlObj.query + urlObj.frag + ' HTTP/1.0\r\n'
		+ 'Host: ' + urlObj.host + '\r\n'
		+ 'User-Agent: ' + 'InDesign/6.0' + '(Macintosh; U; Intel Mac OS X 10_5_6; ja-jp)' + '\r\n'
		+ auth
		+ '\r\n');
		var reply = conn.read(999999);
		conn.close();
		return reply; //ヘッダ込みで返す
	} else {
		return conn.error;
	}
}

//Webからファイルをダウンロードする
function downloadFile(url, localFile) {
	var rep = getHttpResponse({
		method: 'GET',
		url: url,
		encoding: 'BINARY',
	});
	if (rep.match(/HTTP.*\d{3}/).toString().indexOf('200') != -1) {
		//レスポンスのヘッダを除去 
		var body = rep.slice(rep.indexOf('\r\n\r\n') + 4);
		//ファイルに書き出し
		var f = new File(localFile);
		if (f.open("w")) {
			f.encoding = 'BINARY';
			f.write(body);
		}
		f.close();
		return f;
	} else {
		return false;	
	}
}

var f = downloadFile('http://tryit.adobe.com/jp/cs4/family/images/familyBox.jpg', '~/Desktop/familyBox.jpg');
if (f) {
	alert(f.name + ' を保存しました。');
}

InDesignドキュメントのテキストをGoogleの翻訳APIを使って翻訳・置換してみる

『Google AJAX Language API』
http://code.google.com/apis/ajaxlanguage/documentation/
これと、InDesignのSocketオブジェクト使ってドキュメントのテキストを翻訳してみます。

■参考URL
http://d.hatena.ne.jp/C_L/20081012/indesign_socket_http

例えば、InDesignのドキュメントにこんな感じのテキストを用意して、


下にあるJavaScriptを実行すると、

こんな感じで翻訳されたテキストに置換します。

レスポンスは、ヘッダ部分を除くと
{"responseData": {"translatedText":"Ghost in the Shell"}, "responseDetails": null, "responseStatus": 200}
の様なJSONで返って来るので簡単に翻訳結果を取り出せます。一部の記号類は『&#39;』等の文字参照で返ってくるみたいです。
あと、今回のやり方だとテキストフレームの文字数が220文字前後(InDesignの情報パレットで)を境に400 Bad Requestが返って来るようになりました。

何らかの業務で使えるかどうかは非常に怪しいですが、単語レベルなら意外な使い道があるかも知れません。

で、これやってて思ったんですが、InDesignでSocketが使えるって事は、将来InDesignのドキュメントをインターネット越しに何らかの処理をするサービスなんかもあり得るわけですが、例えば第三者から渡されたドキュメントを処理する時、処理結果が悪意のあるスクリプトになるように仕組まれていた場合(今回試した翻訳の場合だと、翻訳結果がスクリプトとして意味のある文字列になる等。これだと環境設定の「添付スクリプトを有効にする」オプションは関係無いので)、取り出した値をeval()関数で評価するような書き方をしていてチェックが甘いとセキュリティの穴にもなり得る訳で、特にInDesignのスクリプトを書いたりするのは自分の様にWeb屋でない人も多いと思うので、その辺気を付ける必要も出てくるのかなぁと思った次第です。

まあこのあたりはインターネットかローカルかに関わらないですが、Webブラウザで実行されるJavaScriptと違って、ファイルシステムにもアクセス出来る訳だし、『inddスクリプトインジェクション』なんて攻撃法なんかが出て来たり…なんてのは夢が広がり過ぎですかね。

#target InDesign 

const HOST = 'ajax.googleapis.com';
const PATH = '/ajax/services/language/translate';
	
//google翻訳APIでテキストを翻訳
function getTranslation(str) {
	var src = 'ja';
	var dest = 'en';
	var query = '?v=1.0&q=' + encodeURI(str) + '&langpair=' + src + '%7C' + dest;
	var rep = "";
	var conn = new Socket;
	if (conn.open(HOST + ':80', 'UTF-8')) {
		conn.write ('GET ' + PATH + query + " HTTP/1.0\n"
			+ 'Host: ' + HOST + "\n"
			+ 'User-Agent: ' + 'InDesign/6.0 ' +'(Macintosh; U; Intel Mac OS X 10_5_6; ja-jp)' + "\n"
			+ "\n");
		rep = conn.read(99999);
		conn.close();
	} else {
		return false;
	}
	var rep_json = eval('(' + rep.match(/\{"responseData".*\}?/) + ')');
	return rep_json.responseData.translatedText;
}

var T = app.activeDocument.textFrames;
for (var i=0; i<T.length; i++) {
	T[i].contents = getTranslation(T[i].contents);
}

配置されている画像を指定したサイズの矩形でマスクし、サイズと位置をフィットさせるIllustrator用JavaScript

Illustratorのドキュメントに配置されている画像を指定したサイズの矩形でマスクして、そのマスクに合うように画像をリサイズし、指定した間隔でファイル名順に並べて行くJavaScript。

例えば、こんな感じでドキュメントにフォルダからドラッグ&ドロップするなどして、無造作に画像を配置しておいて(分かりやすくする為にわざとバラバラに置いてますけど)、


このスクリプトを実行すると、マスクに使う矩形のサイズ、間隔、何列で並べるか等を入力するダイアログを表示するので、それらの数値を入力すると、


画像はドキュメントの左上を起点に、ファイル名順に並んでいきます。


画像は、マスクの矩形のセンターに来るように配置され、サイズはマスクよりほんのちょっとだけ大きくなる様リサイズされます。


■注意点
既にマスクされている画像、グループ化されている画像は処理されません。
ブラウザの環境(Safari等)でスクリプト中に『円マーク』が見えている場合は『バックスラッシュ』に置換する必要があります。
※表示されているコードの上の方にある『view plain』をクリックするとコードがプレーンテキストで表示される筈なんですが、Safari(3.2.1)だと動作しない様なので、対策考えておきます。対策済み。

■動作確認
MacOSX 10.5.6
Illustrator CS4
#target Illustrator

//マスクのサイズを入力するダイアログを表示
function askRectSettings() {
	var mes = 
		"dialog { alignChildren: 'center', \
			field1: Panel { orientation: 'column', alignChildren: 'right', \
				size: [180,72], text: 'マスクのサイズ', \
				size_w: Group { orientation: 'row', \
					s: StaticText { text: '幅:' }, \
					e: EditText { characters: 7, text: '50.0'}, \
					s2: StaticText { text: 'mm'} \
				}, \
				size_h: Group { orientation: 'row', \
					s: StaticText { text: '高さ:' }, \
					e: EditText { characters: 7, text: '50.0' } \
					s2: StaticText { text: 'mm' } \
				} \
			}, \
			field2: Panel { orientation: 'column', alignChildren: 'right', \
				size: [180,72], text: '画像間の余白', \
				margin_w: Group { orientation: 'row', \
					s: StaticText { text: '左右:' }, \
					e: EditText { characters: 7, text: '3.0'}, \
					s2: StaticText { text: 'mm'} \
				}, \
				margin_h: Group { orientation: 'row', \
					s: StaticText { text: '天地:' }, \
					e: EditText { characters: 7, text: '3.0' } \
					s2: StaticText { text: 'mm' } \
				} \
			}, \
			field3: Panel { orientation: 'column', \
				size: [180,40], text: '水平方向に並べる数', \
				column: Group { orientation: 'row', \
					e: EditText { characters: 3, text: '4' }, \
					s: StaticText { text: 'で折り返し' }, \
				} \
			}, \
			buttons: Group { orientation: 'row', \
				cancelBtn: Button { text:'Cancel', properties: { name: 'cancel'} }, \
				okBtn: Button { text: 'OK', properties: {name:'ok'} } \
			} \
		}";
	var dlg = new Window(mes);
	
	dlg.buttons.okBtn.onClick = function() {
		dlg.close(1);
	}

	dlg.center();
	var result = dlg.show();
	var w = dlg.field1.size_w.e.text;
	var h = dlg.field1.size_h.e.text;
	var mw = dlg.field2.margin_w.e.text;
	var mh = dlg.field2.margin_h.e.text;
	var co = dlg.field3.column.e.text;
	if (result == 1) {
		if (w != '' && h != '' && mw != '' && mh != '' && co !='') {
			try {
				return [eval(w), eval(h), eval(mw), eval(mh), eval(co)];
			} catch(e) {
				alert('数字を入力してください!');
				return false;
			}
		} else {
			alert('数値が入力されていません!');
			return false;
		}
	} else {
		return false;
	}
}

//PlacedItemsをファイル名でソートする
function sortPlacedItemsByName(plItems) {
	var retArr = [];
	var fNames = [];
	for (var i=0; i<plItems.length; i++) {
		var fn = plItems[i].file.name + plItems[i].file + i; //同名ファイルをユニークにするためパスと番号を追加
		plItems[i].name = fn
		fNames.push(fn);
	}
	fNames.sort();
	for (var i=0; i<fNames.length; i++) {
		retArr.push(plItems.getByName(fNames[i]));
	}
	return retArr;
}

//マスクされているかどうか
function isMasked(obj) {
	var p = obj.parent;
	while (p.constructor.name != 'Document') {
		if (p.clipped) {
			return true;
		} else {
			p = p.parent;
		}
	}
	return false;
}

//メイン
function clipAndFitImgs() {
	var doc = activeDocument;
	var P = sortPlacedItemsByName(doc.placedItems); //PlacedItemsをソートしておく
	
	var res = askRectSettings();
	if (!res) { return; }
	var ptm = 2.834645;
	var rect_w = res[0] * ptm; //mmに換算
	var rect_h = res[1] * ptm;
	var ofst_x = res[2] * ptm;
	var ofst_y = res[3] * ptm;
	var column = res[4];
	
	var sp = { //整列を開始する起点
		left: 0,
		top: doc.height
		}	
	var tgtImgs = [];		
	var rc = 0; //カウント用
	var cc = 0;
	
	var ro = doc.rulerOrigin;
	var ru = doc.rulerUnits;
	doc.rulerOrigin = [0, 0];
	doc.rulerUnits = 'Points';
	
	//マスク・グループ化されていないものを処理対象にする
	for (var i=0; i<P.length; i++) {
		if (!isMasked(P[i]) && P[i].parent.constructor.name != 'GroupItem') { tgtImgs.push(P[i]); } 
	}

	for (var i=0; i<tgtImgs.length; i++) {
		var ti = tgtImgs[i];
		var l = ti.parent;
		if ( l.constructor.name == 'Layer' ) { //不要?
			var g = l.groupItems.add();
			ti.moveToBeginning(g); //PathItemより先にPlacedItemをGroupItemに追加しないとマスクされない?
			var rect = g.pathItems.rectangle(sp.top - rect_h * rc - ofst_y * rc, sp.left + rect_w * cc + ofst_x * cc, rect_w, rect_h);
			cc++;
			if (cc == column) { 
				cc = 0;
				rc++;
			}
			ti.parent.clipped = true;
			var enl = Math.max((rect_w + 4) / ti.width, (rect_h + 4) / ti.height) * 100;
			ti.resize(enl, enl);
			//マスクに画像をフィットさせる
			//ti.move(rect, ElementPlacement.INSIDE);
			ti.top = (rect.top - rect.height / 2) + ti.height / 2;
			ti.left = (rect.left + rect.width / 2) - ti.width / 2;
		}
	}

	doc.rulerOrigin = ro;
	doc.rulerUnits = ru;
}


if (app.documents.length == 0) {
	alert('ドキュメントが開かれていません。');
} else {
	clipAndFitImgs();
}
Profile
choco
Author : choco

印刷・製版の現場を経て、広告制作会社でPhotoshopを使ったビジュアル制作を担当。

→現在は車載機器開発ベンダにて、組み込み3Dデータ作成やUIデザインなどを行っています。

Categories
Favorites


Search
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。