<?xml version="1.0" encoding="utf-8" ?><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/" 
			xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" 
			xmlns:cc="http://web.resource.org/cc/" xml:lang="ja">
<channel rdf:about="http://chocolife.blog80.fc2.com/?xml">
<title>chocolife</title>
<link>http://chocolife.blog80.fc2.com/</link>
<description>is provided &amp;quot;as is&amp;quot;, with all faults.</description>
<dc:language>ja</dc:language>
<items>
<rdf:Seq>
<rdf:li rdf:resource="http://chocolife.blog80.fc2.com/blog-entry-99.html" />
<rdf:li rdf:resource="http://chocolife.blog80.fc2.com/blog-entry-97.html" />
<rdf:li rdf:resource="http://chocolife.blog80.fc2.com/blog-entry-96.html" />
<rdf:li rdf:resource="http://chocolife.blog80.fc2.com/blog-entry-93.html" />
<rdf:li rdf:resource="http://chocolife.blog80.fc2.com/blog-entry-91.html" />
</rdf:Seq>
</items>
</channel>
<item rdf:about="http://chocolife.blog80.fc2.com/blog-entry-99.html">
<link>http://chocolife.blog80.fc2.com/blog-entry-99.html</link>
<title>画像のクリッピングパスをもう一方の同じファイル名の画像にコピーするAppleScript</title>
<description> 地味な実用系スクリプト。

時々、入稿されてきたRGB画像が数百点にのぼり、しかもその画像を結構な短納期でキリヌキと色調補正＆CMYK変換をしなければならない事があって、そんな場合はキリヌキを（海外の協力会社などに）外注し、同時進行で色調補正の作業をするんですが、後で仕上がってきたキリヌキ画像のクリッピングパスを、手元で色調補正していた画像に反映させてやる必要が出てきます。その作業を自動化するためのApple
 </description>
<content:encoded>
<![CDATA[ 地味な実用系スクリプト。<br>
<br>
時々、入稿されてきたRGB画像が数百点にのぼり、しかもその画像を結構な短納期でキリヌキと色調補正＆CMYK変換をしなければならない事があって、そんな場合はキリヌキを（海外の協力会社などに）外注し、同時進行で色調補正の作業をするんですが、後で仕上がってきたキリヌキ画像のクリッピングパスを、手元で色調補正していた画像に反映させてやる必要が出てきます。その作業を自動化するためのAppleScriptです。<br>
<br>
実は、<a href="http://www.ne.jp/asahi/tan/puku/note/ASPhotoshopCS2/index.html" target="_blank">たけうちとおるさんのサイトにそのまんまの機能のAppleScript</a>があったんですが、自分の作業環境だと意図しない動作をするようだったので、少しチェックをきつめにするようにして書きました。<br>
<br>
■使い方<br>
あらかじめ『キリヌキ済み（クリッピングパスがある）画像』と『キリヌキ前の画像』のフォルダを作り、その中に（対になる様）画像を整理して入れておきます。（必ずしも数が合っている必要はありませんが、後でチェックする事になるので始めのうちに揃えておいた方が良いでしょう。）<br>
<br>
スクリプトを実行し、『キリヌキ済み（コピー元）』と『キリヌキ前』のフォルダの場所を聞いて来るので、それぞれを選択してやるとPhotoshopでの処理が始まり、キリヌキ済み画像のクリッピングパスをキリヌキ前の同名の画像に適用して行きます。<br>
<br>
下記の様な、正しく処理出来なかったファイルは『赤ラベル』が付いて確認作業がしやすいようになっています。<br>
・双方のフォルダで一致するファイル名のものが無かった。<br>
・コピー元の画像にクリッピングパスが無かった。<br>
・コピー先の画像には既にクリッピングパスがあった。<br>
・Photoshopで開けなかった。<br>
・…etc.<br>
<br>
■動作確認<br>
MacOSX 10.5.8<br>
Photoshop CS4<br>
<pre class="applescript">
tell application "Adobe Photoshop CS4"
	set ru to ruler units of settings
	set ruler units of settings to cm units
end tell

tell application "Finder"
	set srcFold to (choose folder with prompt "クリッピングあり画像（コピー元）のフォルダを選択") as string
	set srcFold to srcFold as string
	set destFold to (choose folder with prompt "クリッピングなし画像（適用先）のフォルダを選択") as string
	repeat with theFile in list folder destFold without invisibles
		set theFile to (destFold & theFile) as alias
		if not class of ((properties of theFile) as record) is folder then my setLabel(theFile, 2)
	end repeat
	set destFold to destFold as string
	repeat with theFile in list folder srcFold without invisibles
		set srcFile to (srcFold & theFile) as alias
		if not class of ((properties of srcFile) as record) is folder then
			try
				set destFile to (destFold & theFile) as alias
				my mergePath(srcFile, destFile)
				
			on error
				--コピー先のファイルを開けない（存在しない）場合もコピー元に赤ラベルを付ける
				my setLabel(srcFile, 2)
			end try
		end if
	end repeat
end tell

tell application "Adobe Photoshop CS4"
	set ruler units of settings to ru
end tell

activate me
beep
if my chkLabel(srcFold) or my chkLabel(destFold) then
	display dialog "処理に問題のある画像があります。" & return & "双方のフォルダの『赤いラベル』のファイルをチェックして下さい。" with icon 0
else
	display dialog "終了しました。"
end if


on mergePath(srcFile, destFile)
	tell application "Adobe Photoshop CS4"
		activate
		open srcFile showing dialogs never
		set srcDoc to current document
		set pathItem to path items in srcDoc whose kind is clipping
		
		if (count pathItem) is 0 then
			my setLabel(srcFile, 2)
			close srcDoc
			return
		end if
		
		--クリッピングパスが存在せず下の行の処理に失敗すると以降の記述が実行されない場合がある？（エラーは出ず再現条件不明）
		set cp to entire path of path items in srcDoc whose kind is clipping
		close srcDoc
		my setLabel(srcFile, 4)
		
		open destFile showing dialogs never
		set destDoc to current document
		if (count (path items in destDoc whose kind is clipping)) is 0 then
			make new path item in destDoc with properties {entire path:cp, name:"Clipping", kind:clipping}
			my setLabel(destFile, 4)
			close destDoc saving yes
		else
			close destDoc
		end if
		
	end tell
end mergePath


on setLabel(theFile, col)
	tell application "Finder"
		set label index of theFile to col
	end tell
end setLabel


on chkLabel(theFolder)
	tell application "Finder"
		repeat with theFile in list folder theFolder without invisibles
			set theFile to (theFolder & theFile) as alias
			if label index of theFile is 2 then return true
		end repeat
		return false
	end tell
end chkLabel
</pre> ]]>
</content:encoded>
<dc:subject>DTP &amp; Graphics</dc:subject>
<dc:date>2009-09-30T23:59:14+09:00</dc:date>
<dc:creator>choco</dc:creator>
<dc:publisher>FC2-BLOG</dc:publisher>
</item>
<item rdf:about="http://chocolife.blog80.fc2.com/blog-entry-97.html">
<link>http://chocolife.blog80.fc2.com/blog-entry-97.html</link>
<title>Twitterで『あの人』が自分をfollowしているかどうかを調べるAppleScript</title>
<description> ここんとこ仕事が立て込んでたので放置してしまいました。ちょっと軽めのネタを。

Twitterやってると突然、『follow整理します！』みたいな感じのPOSTが流れて来て、そんな時に自分のfollowerが減ってたりすると、『えっ？…オレ？』とか思ったりして、特に相手がお気に入りの人だったりするとちょっと気になったりするもんです。また、結構前にfollowしたけどfollow返されてたっけ？みたいに思ってもtwitterからの『followされ
 </description>
<content:encoded>
<![CDATA[ ここんとこ仕事が立て込んでたので放置してしまいました。ちょっと軽めのネタを。<br>
<br>
Twitterやってると突然、『follow整理します！』みたいな感じのPOSTが流れて来て、そんな時に自分のfollowerが減ってたりすると、『えっ？…オレ？』とか思ったりして、特に相手がお気に入りの人だったりするとちょっと気になったりするもんです。また、結構前にfollowしたけどfollow返されてたっけ？みたいに思ってもtwitterからの『followされました』メールをいちいちチェックするのも面倒です。<br>
<br>
相手にremoveされたかを知るには、『<a href="http://twitter.com/remtter" target="_blank">りむったー</a>』とか『<a href="http://useqwitter.com/" target="_blank">Qwitter</a>』等のサービスを利用すればremoveされた際に通知を受け取る事が出来ますが、そもそも一度もfollowされてない相手には関係がありません。<br>
<br>
そこで、Twitter APIに用意されている『ユーザ間のfriend関係』を調べる機能を利用して『相手にfollowされてるかどうかを調べる』AppleScriptを書きました。この手のサービスやuser.jsも有りそうですが、探すヒマがあったら自分で書く、みたいな感じで。あと、高機能なTwitterクライアント使ってる人には必要無いかも知れません。<br>
<br>
スクリプト中の『あなたのユーザ名』『パスワード』の部分を書き換えて実行し、気になる『あの人』のユーザ名を入力するとfollowされてるかどうかを表示します。<br>
<br>
<img src="http://blog-imgs-19-origin.fc2.com/c/h/o/chocolife/BarackObama1.png"><br>
<br>
<img src="http://blog-imgs-19-origin.fc2.com/c/h/o/chocolife/BarackObama2.png"><br>
<br>
■動作確認<br>
MacOSX 10.5.8<br>
<pre class="applescript">
property user : "あなたのユーザ名"
property pass : "パスワード"

tell application "Finder"
	set friend to text returned of (display dialog "『あの人』のユーザ名を入力してください。" default answer "") as string
	try
		set scpt to "curl --user \"" & user & ":" & pass & "\" -L \"http://twitter.com/friendships/exists.json?user_a=" & friend & "&user_b=" & user & "\""
		set ret to do shell script scpt
	on error
		my myError()
	end try
	
	set mes to "『" & friend & "』さんは、あなたをfollowして"
	if ret is "true" then
		display dialog mes & "います。" buttons "OK" default button 1
	else if ret is "false" then
		display dialog mes & "いません。" buttons "OK" default button 1 with icon 2
	else
		my myError()
	end if
end tell

on myError()
	activate me
	display dialog "ユーザ名を正しく入力してください。" buttons "OK" default button 1
	error number -128
end myError
</pre> ]]>
</content:encoded>
<dc:subject>Computer-General</dc:subject>
<dc:date>2009-09-13T17:55:46+09:00</dc:date>
<dc:creator>choco</dc:creator>
<dc:publisher>FC2-BLOG</dc:publisher>
</item>
<item rdf:about="http://chocolife.blog80.fc2.com/blog-entry-96.html">
<link>http://chocolife.blog80.fc2.com/blog-entry-96.html</link>
<title>3DCGソフト『Blender』のDTPer的な利用法</title>
<description> DTPの制作現場に携わってると時々「この文字を立体的に表現できる？」なんてリクエストを受ける事がありますが、最近ではAdobeのアプリに3D表現の機能が充実してきたので、昔みたいにサードパーティーのプラグインを使ったりしなくてもお手軽に立体表現ができる様になってきました。ただ、どうしても「いかにも」な感じになったり、質感が乏しかったりで、先方が首を縦に振ってくれる物を作るのが難しい場合も有ります。そこで、フ
 </description>
<content:encoded>
<![CDATA[ <a href="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/chocolife_domino_ret.png" target="_blank" rel="lightbox"><img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/chocolife_domino_ret.png" alt="" border="0"></a><br /><br />DTPの制作現場に携わってると時々「この文字を立体的に表現できる？」なんてリクエストを受ける事がありますが、最近ではAdobeのアプリに3D表現の機能が充実してきたので、昔みたいにサードパーティーのプラグインを使ったりしなくてもお手軽に立体表現ができる様になってきました。ただ、どうしても「いかにも」な感じになったり、質感が乏しかったりで、先方が首を縦に振ってくれる物を作るのが難しい場合も有ります。<br /><br />そこで、フリーの3DCGソフトを使ってIllustrator等で表現するよりもリアルに文字や図形を立体化する方法を紹介したいと思います。3DCGを制作する際にスキルを要する「モデリング」の部分はIllustratorで作ったパスを使うので、あとは表面の質感（マテリアルやテクスチャ）、光源を設定してやる部分さえ何とか出来れば形になると思います。<br /><br />フリーで使える3DCGソフトとして、自分はいつも『<a href="http://www.blender.org/">Blender</a>』を使用しています。このソフトはその気になれば本格的な3DCGアニメーションが作れるくらい多機能なんですが、始めは独特なUIに面食らってしまって使い方を覚えるのにかなり苦労しました（慣れると手が勝手に動く様になるんですが）。今回の例では一部の基本的な機能だけを使っているので、『使い方さえ解れば』それほど難しくはないと思います。<br /><br />BlenderはMac、Windows、Linux等各OS用が用意されていて、UIも全く同じなので違うプラットフォームでも違和感無く使う事が出来ますが、操作は3ボタンマウス必須なのでMacの場合は用意する必要が有るかも知れません。<br /><br />Blenderの基本的な操作については以下のリンク先が参考になります。<br />『<a href="http://f11.aaa.livedoor.jp/~hige/index.php?%5B%5B%CC%DC%BC%A1%5D%5D">JBDP Blender Documentation 日本語版</a>』<br />『<a href="http://wbs.nsf.tc/tutorial/tutorial_blender.html">チュートリアル(本当に初めての方のために作成したBlenderチュートリアル) - WBS+(Web/Blender Studio+)</a>』<br />『<a href="http://wiki.blender.org/index.php/Main_Page">BlenderWiki</a>』<br /><br />作業の流れとしては、<br />・立体化したい文字や図形などをIllustratorで作成し、アウトライン化したパスをファイルとして保存する。<br />・Illustratorで保存したファイル（パス）をBlenderでインポートする。<br />・Blender上で、パスの図形に厚みを与え、表面の材質（マテリアルやテクスチャ）を設定する。<br />・実際に出力するイメージに合わせたカメラアングルや光源の設定をする。<br />・必要な解像度でレンダリングし、画像ファイルとして出力する。<br />といった感じになります。ただBlender上での作業は狙った通りのイメージになるまでパラメータを弄りながらある程度試行錯誤する事になると思います。<br /><br />今回はあくまで「こんな方法もある」といった事を紹介するのが主目的なので具体的な操作については割愛しますが、興味のある方は上記のリンク先等を参照してみてください。作業する上でハマりそうな部分や数値などが参考になりそうな部分はスクリーンショットを載せておきます。<br /><br />では実際にウチのBlogのタイトル文字を立体化してみます。<br /><br />まず、立体化したい文字等のアウトラインデータをIllustratorで作成し、『SVG形式』で保存します。A3のアートボード一杯くらいの大きめのサイズで作った方がBlenderでの作業が楽になります。<br /><a href="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/chocolife_outline.jpg" target="_blank" rel="lightbox"><img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/chocolife_outline.jpg" alt="" border="0"></a><br /><br />BlenderにはEPSやAIフォーマットのデータをインポートする機能も用意されてるんですが、いろいろ試した結果SVGで保存したものが一番安定してインポート出来る様でした。<br /><a href="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/chocolife_svg.jpg" target="_blank" rel="lightbox"><img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/chocolife_svg.jpg" alt="" border="0"></a><br /><br />Blenderで、保存したIllustratorのファイルをインポートします。<br /><a href="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/blender_import01.png" target="_blank" rel="lightbox"><img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/blender_import01s.png" alt="" border="0"></a><br /><br />次に表示されるメニューではInkSpace(.svg）を選択、『Inport Options』は何も選択しない状態でOKすれば問題無くインポート出来ました。<br /><a href="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/blender_import02.png" target="_blank" rel="lightbox"><img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/blender_import02s.png" alt="" border="0"></a><br /><br /><a href="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/blender_import03.png" target="_blank" rel="lightbox"><img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/blender_import03s.png" alt="" border="0"></a><br /><br />で、インポートされたパスに厚みを付けるんですが、『Curve and Surface』パネル中の『Extrude』で文字の厚み（奥行き）、『Bevel Depth』で角を落とすサイズの値を設定します。Illustratorで作成したパスのサイズが小さいとBlender上で拡大しても小さな数値（0.001とか）で大きく変化するので注意が必要です。<br /><a href="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/blender_edit01.png" target="_blank" rel="lightbox"><img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/blender_edit01s.png" alt="" border="0"></a><br /><br />文字のオブジェクトにマテリアルを設定し、光源やカメラを配置してレンダリングします。マテリアルは鏡面加工の金属ぽい質感になるよう設定しました。光源の配置が結構キモになったりするので、いろいろ試行錯誤していきます。<br /><a href="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/blender_edit02.png" target="_blank" rel="lightbox"><img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/blender_edit02s.png" alt="" border="0"></a><br /><br />レンダリング結果。ターミネーター風。<br /><a href="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/chocolife_t2.jpg" target="_blank" rel="lightbox"><img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/chocolife_t2s.jpg" alt="" border="0"></a><br /><br />今度は別のパスをインポートして下の様な画像をテクスチャとして設定し、レンダリングしてみます。<br /><a href="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/blender_edit03.jpg" target="_blank" rel="lightbox"><img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/blender_edit03.jpg" alt="" border="0"></a><br /><br /><a href="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/blender_edit04.png" target="_blank" rel="lightbox"><img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/blender_edit04s.png" alt="" border="0"></a><br /><br />トランスフォーマー風になりました。<br /><a href="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/chocolife_tfm01.jpg" target="_blank" rel="lightbox"><img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/chocolife_tfm01s.jpg" alt="" border="0"></a><br /><br />もちろんアングルを自由に変えられますし、このデータをそのまま使ってアニメーションにする事もできます。<br /><a href="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/chocolife_tfm02.jpg" target="_blank" rel="lightbox"><img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/chocolife_tfm02s.jpg" alt="" border="0"></a><br /><br />実際の制作物ではレンダリングした画像だけで完結するのではなく、別の画像と合成して使う事になる場合もあると思いますが、そんな時は後々作業がやり易い様に、文字のマテリアルを完全に白く飛んでしまう設定にしてレンダリングし、文字部分のマスクとして使える物も作っておきます。<br /><a href="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/chocolife_tfm_mask.jpg" target="_blank" rel="lightbox"><img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/chocolife_tfm_masks.jpg" alt="" border="0"></a><br />■2009.7.21追記　コメントにて教えていただきましたが、レンダリングの設定でFormatパネルのRGBAをオンにしてPNGで書き出せば、背景が透明に抜けた状態の画像が得られます。<br /><br />レンダリングした画像を印刷物に使う場合、そのままではネムい仕上がりになってしまう事があるので（テクスチャの解像度が低い場合は特に）、適切なシャープネス処理が必要になります。<br /><a href="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/chocolife_sharp.jpg" target="_blank" rel="lightbox"><img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/chocolife_sharp.jpg" alt="" border="0"></a><br /><br />以上、非常に大雑把な説明でしたが、スキルを要するモデリングの部分をIllustratorのパスを使う事によって簡略化できるので、3DCGに興味はあるけど敷居が高いと感じてる人もこの辺りから手を付けると良いんではないでしょうか。画像を見ても分かる通りBlender標準のレンダラでも品質の高いレンダリングを行う事が出来ます。自分もほんのさわりの部分しか使ってませんが、Photoshopでのちょっとした合成用素材なんかを作るのにも重宝しています。 ]]>
</content:encoded>
<dc:subject>DTP &amp; Graphics</dc:subject>
<dc:date>2009-07-19T21:20:06+09:00</dc:date>
<dc:creator>choco</dc:creator>
<dc:publisher>FC2-BLOG</dc:publisher>
</item>
<item rdf:about="http://chocolife.blog80.fc2.com/blog-entry-93.html">
<link>http://chocolife.blog80.fc2.com/blog-entry-93.html</link>
<title>Flashで画像の色の分布を3Dグラフにプロットしてみる</title>
<description> 同じネタで引っ張ります。

以前のエントリで、画像の色（『L*a*b*』値）の分布をPhotoshop&amp;JavaScriptで書き出して、それをMacOSX付属の『Grapher』に読み込ませて3D空間にプロットするってのをやりましたが、今回はActionScriptの勉強も兼ねて、Flashで3Dの分布図を作成してみました。3Dの表示には定番のライブラリ『Papervision3D』を利用しています。

PV3Dのコードを書くに当たり、『ClockMaker』さんの一連のエントリ、
 </description>
<content:encoded>
<![CDATA[ 同じネタで引っ張ります。<br>
<br>
<a href="http://chocolife.blog80.fc2.com/blog-entry-90.html">以前のエントリ</a>で、画像の色（『L*a*b*』値）の分布をPhotoshop&JavaScriptで書き出して、それをMacOSX付属の『Grapher』に読み込ませて3D空間にプロットするってのをやりましたが、今回はActionScriptの勉強も兼ねて、Flashで3Dの分布図を作成してみました。3Dの表示には定番のライブラリ『<a href="http://code.google.com/p/papervision3d/">Papervision3D</a>』を利用しています。<br>
<br>
PV3Dのコードを書くに当たり、『<a href="http://clockmaker.jp/blog/" target="_blank">ClockMaker</a>』さんの一連のエントリ、『<a href="http://clockmaker.jp/blog/2009/02/pv3d_frame_action_01/">フレームアクションで覚える Papervision3D チュートリアル</a>』が非常に参考になりました。<br>
<br>
以下が今回作ったFlash。マウスでぐりぐり動かせます。（ホントは『<a href="http://wonderfl.net/user/chocolife" target="_blank">wonderfl</a>』のアカウント取ったんでそっちを貼りたかったんですが、現在ログイン出来なくなってる様なので生のswf貼ります。）<br>
<embed src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/PlotLab.swf"
type="application/x-shockwave-flash"
width="500" height="400" bgcolor="#000000"
pluginspage="http://www.adobe.com/go/getflashplayer_jp" /><br>
<br>
画像の『L*a*b*値』のデータは、<a href="http://chocolife.blog80.fc2.com/blog-entry-90.html">以前のエントリ</a>のJavaScriptで書き出したものを外部ファイルとしてFlashから読み込んで表示する様になっているので、それを変える事によって色々な画像の色の分布が表示出来ます。<br>
<br>
例えば、デフォルトで読み込まれるデータは、AbobeRGBの色域のグラデーションの『L*a*b*』値なんですが、実際に読み込んでるデータは<a href="http://files.getdropbox.com/u/271700/gamut_AdobeRGB.txt" target="_blank">これ</a>になります。<br>
<br>
次の画像の『L*a*b*値』を書き出したファイルは<a href="http://files.getdropbox.com/u/271700/sample.txt"　target="_blank">これ</a>なんですが、このファイルをダウンロードして、『Load L*a*b* coordinates』ボタンで読み込ませると下の画像の様な表示になります。<br>
<img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/colorful.png" border="0"><br>
<img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/flash_plotlab.png" border="0"><br>
<br>
一連のエントリの出発点が、『Photoshopでのカラーマネジメントが効いた状態の色をプロットする』という所から始まっているので、画像を直接読み込むのではなく（Flashでカラープロファイルが扱えれば良いんですが）わざわざ座標を書き出してから読み込んで、それを元のRGBに戻すなんて事をしています。他のエントリのJavaScript等もそうなんですが、実用というよりは、『思い付いたものを形に出来るか？』といったアプローチで、訓練としてやってる様なものが多いですね。<br>
<!--
<div style="text-align:center;width:465px;"><iframe title="forked from: flash on 2009-6-17 - wonderfl build flash online" src="http://wonderfl.kayac.com/blogparts/c90bbb8a21c8dd0b9f282d248dcf7fe8f2d0489b" width="465" height="490" style="border:1px black solid;"></iframe><a href="http://wonderfl.kayac.com/code/c90bbb8a21c8dd0b9f282d248dcf7fe8f2d0489b" title="forked from: flash on 2009-6-17 - wonderfl build flash online">forked from: flash on 2009-6-17 - wonderfl build flash online</a></div>
-->
<br>
今回のActionScriptのソースは以下の通りです。FlashPlayer10で動作確認しています。<br>
<pre name="code" class="actionscript">
package
{	
	import flash.net.*;
	import flash.events.*;
	import flash.text.*;
	import flash.ui.Mouse;
	import flash.system.Security;
	import org.papervision3d.view.*
	import org.papervision3d.objects.*;
	import org.papervision3d.materials.*
	import org.papervision3d.objects.primitives.*
	import org.papervision3d.core.geom.*;
	import org.papervision3d.core.geom.renderables.*;
	import org.papervision3d.materials.special.ParticleMaterial;
	import org.papervision3d.objects.special.ParticleField;
	import org.papervision3d.materials.utils.MaterialsList;
	import net.hires.debug.Stats;
	
	
	[SWF(width = "500", height = "400", frameRate = "30", backgroundColor = "0x000000")]
	
	public class PlotLab extends BasicView
	{

		private var world:BasicView = new BasicView();
		private var file:FileReference = new FileReference();
		private var pChips:Particles = new Particles("pChips");
		private var isMouseDown:Boolean = false;
		private var oldX:Number = 0;
		private var oldY:Number = 0;
		private var nowX:Number = 0;
		private var nowY:Number = 0;
		private var targetRot:Number = 180;
		private var targetPitch:Number = 0;	
		private var rot:Number = 0;
		private var pitch:Number = 0;
		private var text1:TextField = new TextField();
		private var lab_colors:Array = [];
		private var mes1:String = 'Load L*a*b* coordinates';
		private var mes2:String = '...Loading';
		
		public function PlotLab():void {
			
			// via http://5ivestar.org/blog/2008/12/wonderfl-webproxy/ 
			// Thanks!!
			Security.loadPolicyFile("http://5ivestar.org/proxy/crossdomain.xml");
			
			addChild(new Stats({bg: 0x000000, fps: 0xC0C0C0, ms: 0x505050, mem: 0x707070, memmax: 0xA0A0A0}));
			world.startRendering();
			addChild(world);
		
			var loader:URLLoader = new URLLoader();
			loader.addEventListener(Event.COMPLETE, completeHandler);
			
			//by default, loading the coordinates of a fullcolor image on AdobeRGB   
			loader.load(new URLRequest("http://5ivestar.org/proxy/http://files.getdropbox.com/u/271700/gamut_AdobeRGB.txt"));	
			
			file.addEventListener(Event.SELECT, selectHandler);
			file.addEventListener(Event.COMPLETE, onFileLoad);
			
			stage.addEventListener(Event.ENTER_FRAME, enterFarme);
			stage.addEventListener(MouseEvent.MOUSE_DOWN, downHandler);
			stage.addEventListener(MouseEvent.MOUSE_UP, upHandler);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, moveHandler);
			
			makeWorld();
		}
		
		
		private function completeHandler(event:Event):void {
			lab_colors = event.target.data.split('\r');
			makeParticles();
		}
		
		
		private function makeParticles():void {
			
			pChips.removeAllParticles();
			
			text1.text = mes1;
			var coordinates:Array = [];
			var rgb:Object = {};
			var xyz:Object = {};
			var plot_color:String;
			
			for (var i:Number = 0; i &lt; lab_colors.length-1; i++) {
				coordinates = lab_colors[i].split('\t');
				xyz = lab2xyz(coordinates[2], coordinates[0], coordinates[1]);
				rgb = xyz2rgb(xyz.x, xyz.y, xyz.z);
				plot_color = toHexRgb(rgb);
				var particleMat:ParticleMaterial = new ParticleMaterial(parseInt(plot_color), 1)
				var pt:Particle = new Particle(particleMat, 5, coordinates[0]*5, (coordinates[2]-50)*5, coordinates[1]*5);
				pChips.addParticle(pt);
			}
			
		}
		
		
		private function enterFarme(e:Event):void {						  
				// easing: (target - current) * deceleration
				rot += (targetRot - rot) * 0.05;
				pitch += (targetPitch - pitch) * 0.05;
				
				pitch = Math.max(pitch, -90);
				pitch = Math.min(pitch, 90);
				
				world.camera.x = 1000 * Math.sin(rot * Math.PI / 180);
				world.camera.z = 1000 * Math.cos(rot * Math.PI / 180);
				world.camera.y = 1000 * Math.sin(pitch * Math.PI / 180);
				//rot += 1.5;
			}
	
	
		private function downHandler(e:MouseEvent):void {
			isMouseDown = true;
			oldX = mouseX;
			oldY = mouseY;
		}
		
	
		private function upHandler(e:MouseEvent):void {
			isMouseDown = false;
		}
		
	
		private function moveHandler(e:MouseEvent):void {
			if(isMouseDown){
				var dx:Number = e.stageX - oldX;
				var dy:Number = e.stageY - oldY;
				
				targetRot += dx * 0.5;
				targetPitch += dy * 0.5;
				
				oldX = e.stageX;
				oldY = e.stageY;
			}
		}
		
		
		private function makeWorld():void {
			
			text1.addEventListener(MouseEvent.CLICK, onClickLoadButton);
			text1.addEventListener(MouseEvent.MOUSE_OVER, onOverLoadButton);
			text1.addEventListener(MouseEvent.MOUSE_OUT, onOutLoadButton);
			text1.type = TextFieldType.DYNAMIC;
			text1.width = 150;
			text1.height = 30;
			text1.x = 350;
			text1.y = 350;
			text1.textColor = 0xFFFFFF;
			text1.autoSize = TextFieldAutoSize.CENTER;
			text1.border = true;
			text1.borderColor = 0xFFFFFF;
			text1.text = mes2;
			addChild(text1);
		
			var line_mat = new WireframeMaterial(0xAAAAAA);
			line_mat.doubleSided = true;	
			var line_a = new Plane(line_mat, 1, 1000, 1, 1);
			world.scene.addChild(line_a);
			line_a.y = -250;
			line_a.rotationZ = 90;
			var line_b = new Plane(line_mat, 1, 1000, 1, 1);
			world.scene.addChild(line_b);
			line_b.y = -250;
			line_b.rotationX = 90;
			world.scene.addChild(pChips);
		
		}
		
		
		private function onOverLoadButton(e:Event):void {
			Mouse.cursor = flash.ui.MouseCursor.BUTTON;
		}
		
		private function onOutLoadButton(e:Event):void {
			Mouse.cursor = flash.ui.MouseCursor.ARROW;
		}
		
		
		private function onClickLoadButton(e:Event):void {
			file.browse();
		}
		
		
		private function selectHandler(e:Event):void {
			file.load();
			text1.text = mes2;
		}
		
		private function onFileLoad(e:Event):void {
			targetRot = 180;
			targetPitch = 0;
			lab_colors = file.data.toString().split('\r');
			text1.text = mes1;
			makeParticles();
		}
		
		private function toHexRgb(rgb:Object):String {
			var r:String = rgb.r.toString(16);
			var g:String = rgb.g.toString(16);
			var b:String = rgb.b.toString(16);
			if (r.length == 1) r = '0' + r;
			if (g.length == 1) g = '0' + g;
			if (b.length == 1) b = '0' + b;
			var ret:String = '0x' + r + g + b;
			return ret;
		}
		
		
		private function lab2xyz( l:Number, a:Number, b:Number ):Object {
			const REF_X:Number = 95.047; // Observer= 2digrees Illuminant= D65
			const REF_Y:Number = 100.000; 
			const REF_Z:Number = 108.883; 
			var y:Number = (l + 16) / 116;
			var x:Number = a / 500 + y;
			var z:Number = y - b / 200;
			if ( Math.pow( y , 3 ) &gt; 0.008856 ) { y = Math.pow( y , 3 ); }
			else { y = ( y - 16 / 116 ) / 7.787; }
			if ( Math.pow( x , 3 ) &gt; 0.008856 ) { x = Math.pow( x , 3 ); }
			else { x = ( x - 16 / 116 ) / 7.787; }
			if ( Math.pow( z , 3 ) &gt; 0.008856 ) { z = Math.pow( z , 3 ); }
			else { z = ( z - 16 / 116 ) / 7.787; }
			var xyz:Object = {x:0, y:0, z:0};
			xyz.x = REF_X * x;  
			xyz.y = REF_Y * y;
			xyz.z = REF_Z * z;
		 
			return xyz;
		}
		
		
		private function xyz2rgb(X:Number, Y:Number, Z:Number):Object {
			var x:Number = X / 100;        
			var y:Number = Y / 100;        
			var z:Number = Z / 100;        
			var r:Number = x * 3.2406 + y * -1.5372 + z * -0.4986;
			var g:Number = x * -0.9689 + y * 1.8758 + z * 0.0415;
			var b:Number = x * 0.0557 + y * -0.2040 + z * 1.0570;
		 
			if ( r &gt; 0.0031308 ) { r = 1.055 * Math.pow( r , ( 1 / 2.4 ) ) - 0.055; }
			else { r = 12.92 * r; }
			if ( g &gt; 0.0031308 ) { g = 1.055 * Math.pow( g , ( 1 / 2.4 ) ) - 0.055; }
			else { g = 12.92 * g; }
			if ( b &gt; 0.0031308 ) { b = 1.055 * Math.pow( b , ( 1 / 2.4 ) ) - 0.055; }
			else { b = 12.92 * b; }
			var rgb:Object = {r:0, g:0, b:0}
			var tmp_r = Math.min(r*255, 255);
			var tmp_g = Math.min(g*255, 255);
			var tmp_b = Math.min(b*255, 255);
			rgb.r = Math.max(tmp_r, 0);
			rgb.g = Math.max(tmp_g, 0);
			rgb.b = Math.max(tmp_b, 0);
			return rgb;
		}
	
	}
}
</pre> ]]>
</content:encoded>
<dc:subject>DTP &amp; Graphics</dc:subject>
<dc:date>2009-06-22T22:22:02+09:00</dc:date>
<dc:creator>choco</dc:creator>
<dc:publisher>FC2-BLOG</dc:publisher>
</item>
<item rdf:about="http://chocolife.blog80.fc2.com/blog-entry-91.html">
<link>http://chocolife.blog80.fc2.com/blog-entry-91.html</link>
<title>画像の色の分布を『xy色度図』にプロットしてみる（あと、CMYKプロファイルの事も少し）</title>
<description> MacOSX付属の『Grapher』を使った画像の色の分布図の作成その2。

今回は、カラーマネジメント関係の書籍等には必ず出てくる、馬蹄形の『xy色度図』上の座標に、画像の色の分布をプロットしてみます。

前のエントリではPhotoshopで画像を開き、JavaScriptを使ってサンプリングしたピクセルの『L*a*b*値』をファイルに書き出して、そのファイルをGrapherに読み込ませて表示させましたが、今回はピクセルの色を『xyY』の値で書
 </description>
<content:encoded>
<![CDATA[ MacOSX付属の『Grapher』を使った画像の色の分布図の作成その2。<br>
<br>
今回は、カラーマネジメント関係の書籍等には必ず出てくる、馬蹄形の『<a href="http://ja.wikipedia.org/wiki/%E8%89%B2%E7%A9%BA%E9%96%93#XYZ.E8.A1.A8.E8.89.B2.E7.B3.BB" target="_blank">xy色度図</a>』上の座標に、画像の色の分布をプロットしてみます。<br>
<br>
<a href="http://chocolife.blog80.fc2.com/blog-entry-90.html">前のエントリ</a>ではPhotoshopで画像を開き、JavaScriptを使ってサンプリングしたピクセルの『L*a*b*値』をファイルに書き出して、そのファイルをGrapherに読み込ませて表示させましたが、今回はピクセルの色を『xyY』の値で書き出すので、『L*a*b*』から『xyY』の値に変換する部分をJavaScriptに新たに書き加えました。<br>
<br>
今回は色度を表す『xy』の二次元のグラフなので、明度を示す『Y』の値は使いません。<br>
<br>
『L*a*b*』から『xyY』ヘの変換式は、<br>
『<a href="http://www.cs.rit.edu/~ncs/color/t_convert.html"  target="_blank">Color Conversion Algorithms</a> 』(http://www.cs.rit.edu/~ncs/color/t_convert.html)や、<br>
『<a href="http://www.tecgraf.puc-rio.br/~mgattass/color/ColorIndex.html"  target="_blank">Color Conversion Library in ANSI C</a>』 (http://www.tecgraf.puc-rio.br/~mgattass/color/ColorIndex.html)<br>
あたりをを参考にしています。<br>
<br>
PhotoshopのAdobeRGB環境で下のグラデーデョン画像を開き、JavaScriptを実行して書き出されたファイルをGrapherで読み込んで、色度図にプロットしてみます。<br>
<img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/plot_CIELAB_01.png" border="0"><br>
<br>
赤と緑の三角形の部分はそれぞれ『AdobeRGB』と『sRGB』の色域を表していますが、それらは色度図上の値をあらかじめ調べておいてグラフに数値を入力しました。また、グレーの馬蹄形の部分、360nm～830nmの各波長の単色光の色度を示す『スペクトル軌跡』も別途計算して求めた数値を読み込ませてプロットしてあります。<br>
<img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/rainbow_xy01.png" border="0"><br>
<br>
上のグラデーション画像を『JapanColor2001corted』のプロファイル、レンダリングインテントが『知覚的』の設定でCMYKに変換した場合の色の分布を見てみると、色域が以下の様に圧縮されているのが解ります。<br>
<img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/rainbow_xy02_perceptual.png" border="0"><br>
<br>
<br>
次に、下の画像は始めからCMYKモードで作成した、CMYK各色100%と、その二次色のレッド、グリーン、ブルーをグラデーションにしたもので、<br>
<img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/cmyk_rainbow.png" border="0"><br>
<br>
これを『JapanColor2001corted』で開いた状態でプロットしてみると、非常になめらかな色の分布を持つグラフがプロットされました。<br>
<img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/cmyk_japancolor.png" border="0"><br>
<br>
同じ画像を、『某印刷所の本機（枚葉）の印刷物を測色して作成したプロファイル』を適用した状態でプロットすると、<br>
<img src="http://blog-imgs-26-origin.fc2.com/c/h/o/chocolife/cmyk_honki.png" border="0"><br>
ややいびつな輪郭でプロットされました。グリーン（上の頂点の部分）の色域がやや狭く、イエロー方向に転んでいるのが見て取れます。<br>
<br>
ただ、これはいびつなプロファイルが悪いと言うのではなく、あくまで『プロファイル』として実際の印刷物の状態を表したものなので、特に、JapanColorをターゲットとした『印刷の標準化』が行われていない印刷会社では、おそらく色が合わない等の問題も出てくる筈なので、必ずしも『JapanColor2001corted』の方が良い結果になるとは言い切れないと思います。<br>
<br>
今回プロットした画像を見て思ったんですが、『JapanColor2001corted』の不自然なほど整ったプロファイルは、『理想的なJapanColor』をターゲットにして最適化の処理がされた、『架空のプロファイル』に近いものの様な気がします。<br>
<br>
カラーマネジメントの書籍等では『CMYKのカラー設定はJapanColor2001corted推奨』というのが殆どで、もちろん出鱈目なプロファイルで運用する事に比べればベストに近い選択という事で異論は無いんですが、画像をCMYK分解する時点ではトーンジャンプも無くキレイに分解されていても、後の工程でRIPにデバイスリンクプロファイルを噛ましたり、刷版や印刷で色を調整する必要が出るとすれば、『画像が劣化する要因が他の工程に移っただけ』とも考えられるので、その辺りもツッ込んで解説してあればなぁとか思った次第です。（画像の段階で劣化しないのが望ましいとは思いますが）<br>
<br>
画像を『xyY』の数値で書き出すのに使ったJavaScriptは以下の通り。<br>
<br>
■動作確認<br>
MacOSX 10.5.7<br>
Photoshop CS4<br>
<pre name="code" class="javascript">
#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 &lt; 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) &gt; 0.008856 ? Math.pow(var_Y, 3) : ( var_Y - 16 / 116 ) / 7.787;
		var_X = Math.pow(var_X, 3) &gt; 0.008856 ? Math.pow(var_X, 3) : ( var_X - 16 / 116 ) / 7.787;
		var_Z = Math.pow(var_Z, 3) &gt; 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&lt;sampling_size; i++) {
			for (var j=0; j&lt;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 &gt; 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 &gt; 0) {
	samplingPixelsAsYxy.main();
}
</pre> ]]>
</content:encoded>
<dc:subject>DTP &amp; Graphics</dc:subject>
<dc:date>2009-06-17T01:37:50+09:00</dc:date>
<dc:creator>choco</dc:creator>
<dc:publisher>FC2-BLOG</dc:publisher>
</item>
</rdf:RDF>