CS5の埋め込み文字
2010 年 8月 30 日 月曜日 kosuke埋め込みフォントをSWCに書き出して利用すれば、高速なパブリッシュが出来んだが、Flashで利用する際、アウトラインフォーマットがクラシック(DF3)で、SWCに書き出したフォントと同じフォントを指定したテキストフィールドがあるとうまくSWCのフォントを利用できなかったのでメモしておく。
SWCに書き出すほうのflaファイルでは以下のように日本語フォントを埋め込んでSWCに書き出します。パブリッシュのSWF設定、SWC書き出しにチェックでSWCに書き出せる。
SWCを利用するほうのflaファイルで、SWCにパスを通し書き出したクラス名のインスタンスを宣言すると埋め込みフォントとして利用できるようになる。しかもパブリッシュは軽い。
package{ import flash.display.Sprite; import flash.text.*; public class EmbedDF3 extends Sprite{ public function EmbedDF3(){ //SWCに埋め込んだフォントを利用 var embedFont:Font = new HiraginoKakuGoProW3DF3(); //利用できる埋め込みフォントを確認 var arr:Array = Font.enumerateFonts(); for each( var i:Font in arr ){ trace( i.fontName ); //出力:Hiragino Kaku Gothic Pro W3 } var str:String = "SWCの埋め込みフォントを利用" + "\n"; str += "Hiragino Kaku Gothic Pro W3"; var format:TextFormat = new TextFormat(); format.font = embedFont.fontName; format.color= 0x999999; var field:TextField = new TextField(); field.defaultTextFormat = format; field.x = 25; field.y = 25; field.width = 200; field.height= 100; field.borderColor = 0x999999; field.border = true; field.multiline = true; field.wordWrap = true; field.embedFonts= true; field.text = str; addChild( field ); } } } |
ここまではいいんです。とっても便利。
しかし、flaに同じフォントを指定したテキストフィールドがあったとします。
ここではステージにテキストフィールドを配置していますがどこにあっても同じ。
このテキストフィールドのアンチエイリアスはデバイスフォントとしています。
これで書き出すと、
埋め込みフォントが利用できません。
どうも同名のフォントがあるとそちらが優先される模様。
この時は、
//利用できる埋め込みフォントを確認 var arr:Array = Font.enumerateFonts(); for each( var i:Font in arr ){ trace( i.fontName ); //出力:無し(arr.length = 0) } |
も出力されないので、埋め込みでない同名フォントが優先されているのかなと。
試しにステージに配置したテキストフィールドのアンチエイリアスを「アンチエイリアス(アニメーション優先)」とした場合、テキストフィールドに入っている文字だけが表示される。
traceの部分では、Hiragino Kaku Gothic Pro W3が出力されているんだけど、Flashが自動的に埋め込む、ステージに配置したテキストフィールドのフォントになっているんだと思う。
Safari 5とSWFAddressの不具合の件
2010 年 8月 25 日 水曜日 kosuke前にエントリーした不具合の件、公式に載っていました。
SWFAddress.back() doesn’t work in Safari 5
Safari 5とDebugger バージョンのFlash PlayerだとNGらしい。試しに通常バージョンのFlash Playerにしたらちゃんと動いていた。作る人はDebuggerのほう使うだろうに。めんどくさい話だなぁ…。
ちなみにSWFAddress 2.1まで落とすとDebuggerでも動く。なんでって話だけど調べる気にはなれん…。一概にSafari 5のせいとも言えない話でした。
選択範囲の境界線を描くまで
2010 年 8月 12 日 木曜日 kosukePhotoshopで選択範囲を取ったときの点線の輪郭線を描きたくて試した方法。
輪郭線を描きたい対象を透明なBitmapDataにdrawする。
輪郭を得るために一旦このBitmapDataを透明と黒100%で二値化する。
var rect:Rectangle = new Rectangle( 0, 0, 200, 200 ); var master:BitmapData = new BitmapData( rect.width, rect.height, true, 0x00000000 ); var pt:Point = new Point(); master.draw( container ); master.threshold( master, rect, pt,">",0x00000000, 0xFF000000, 0xFFFFFFFF, false ); |
エッジ部分のアンチエイリアスも含めて輪郭としたかったんで、ここでは透明以外のピクセルはすべて黒100%にしているけど0x00000000を変更すれば、輪郭に含むアンチエイリアスの許容値を調整できる。
元の文字と二値化した文字。
二値化したBitmapDataを複製しておく。元のBitmapDataにConvolutionFilterを適用。
以下のマトリックスで適用すると境界の内側、外側に1ピクセルずつ不透明ピクセルが出来て滲んだ画像になる。ConvolutionFilterって前にエントリー書いたけど、なるほどこんなケースで使えるんだなぁと思いました。
var convolution:ConvolutionFilter = new ConvolutionFilter( 3,3, [ 1, 1, 1, 1, 1, 1, 1, 1, 1 ], 9, 0, false ); var clone:BitmapData = master.clone(); master.applyFilter( master, rect, pt, convolution ); master.draw( clone ); |
次に滲んだBitmapDataに複製しておいたBitmapDataをdrawする。これで輪郭の外側1ピクセルが滲んだ状態になる。
輪郭の内側・外側が滲んだ文字と、輪郭の外側が滲んだ文字。
輪郭の外側の滲んだ部分が選択範囲の境界線として使いたい部分なのでこれを取り出す。
BitmapDataに対し今度は黒100%の部分を透明に置き換えた後、再度、透明と黒100%で二値化する。
master.threshold( master, rect, pt,"==",0xFF000000, 0x00000000, 0xFFFFFFFF, false ); master.threshold( master, rect, pt,">" ,0x00000000, 0xFF000000, 0xFFFFFFFF, false ); |
これで選択範囲の境界線が出来た。
続いてチカチカ流れる部分。これ一時悩んだのですが(輪郭を時計回りに回っているものだと思った)よく見ると水平線は左から右へ、垂直線は上から下へ流れているだけ。難しく考え過ぎてた。斜めの線動かせばいんじゃない?ってYさんの一言で気づいた。
斜め線のパターンを作ってBitmapDataのサイズ同じサイズでShapeを塗りつぶす。
var b:uint = 0xFF000000; var pattern:BitmapData = new BitmapData( 6,6, true, 0x00000000 ); pattern.setVector( new Rectangle( 0,0,6,6 ), Vector.<uint>([ 0,0,0,b,b,b, 0,0,b,b,b,0, 0,b,b,b,0,0, b,b,b,0,0,0, b,b,0,0,0,b, b,0,0,0,b,b ]) ); var shape:Shape = new Shape(); var g:Graphics = shape.graphics; g.beginBitmapFill( pattern ); g.drawRect( 0,0, rect.width, rect.height ); |
選択範囲の境界線と斜め線のパターン。
あとは斜め線のパターンを1ピクセルずつ動かしながら選択範囲の境界線に合成すれば、Photoshop風の点線境界線の完成です。
var matrix:Matrix = new Matrix(); addEventListener( Event.ENTER_FRAME, function(e:Event):void{ matrix.tx = ( matrix.tx + 1 ) % 6; g.clear(); g.beginBitmapFill( pattern, matrix ); g.drawRect( 0,0, rect.width, rect.height ); outline.fillRect( rect, 0 ); outline.draw( master ); outline.draw( shape, null, null, BlendMode.ALPHA ); }); |
Safari…
2010 年 8月 10 日 火曜日 kosuke5.0.1になって、この間の画面が溶ける現象がなおったと思ったら、こんどはSWFAddressが効かなくなったような気が…。いい加減にしてほしい。
直リンクはOKですけど、ブラウザの戻る進むの時反応しなくないですか?俺だけ?
http://www.asual.com/swfaddress/samples/flash/
バージョン 5.0.1 (6533.17.8)
Flashだけでファイルをダウンロードさせる
2010 年 7月 23 日 金曜日 kosukeTLFTextField独習 その2
2010 年 7月 8 日 木曜日 kosukePhotoshopで文字組したPSDファイルをFlashに読み込んだ時の再現性を確認してみた。
TextFieldでインポートされていた前バージョンと比べれば良くなっているんだけど、まだ調整無しで使うのは厳しいっぽいなぁと。
確認してみたのは以下のパターン。
Photoshopで2書体混在、カーニングをメトリックス、左揃え、赤字の箇所を字詰めしたポイントテキスト。
・元のPSD
このPSDをFlashにインポートしてみる。書き出したSWFのスクリーンショットを元のPSDに重ねてみたのがこれ。
「TLFTextFieldで美しい日本語。」以外はビットマップになっているのでズレない。
TLFTextFieldには文字を埋め込んだ以外(自動カーニングがあるので)は、インポートした状態からいじっていない。
淡い方が元のPSDの位置。全体的に下に移動している。
字詰め自体はほぼ正しく反映されているように見えるんだけど、字詰め前の段階からして文字間隔が変わっちゃってるところもある。PSD側の自動カーニング(メトリックスなど)を使わない場合はもう少しズレが減る感じでした。
試しに同じPSDをCS5でPlayer9ターゲットのflaにしてTextFieldでインポートしたのがこちら。
こちらはぜんぜん字詰めが生きていない。上下位置はズレなかったりするんだけども。
この後、ブロックテキストで均等配置にしたPSDなども試したんですけど、再現性はさらに悪くなる感じでしたので、このあたりであきらめ…。レイアウトの再現性は微妙な感じがしますがTLFTextFieldでインポートした場合、字詰めなど書式を変更した箇所はTextFlowの構造に反映されます。この点は凄いんじゃないかと思う。
<TextFlow alignmentBaseline="useDominantBaseline" blockProgression="tb" columnCount="inherit" columnGap="inherit" columnWidth="inherit" direction="ltr" dominantBaseline="auto" fontLookup="embeddedCFF" lineBreak="explicit" paddingBottom="inherit" paddingLeft="inherit" paddingRight="inherit" paddingTop="inherit" paragraphEndIndent="0" paragraphSpaceAfter="0" paragraphSpaceBefore="0" paragraphStartIndent="0" textAlign="start" textIndent="0" verticalAlign="inherit" whiteSpaceCollapse="preserve" xmlns="http://ns.adobe.com/textLayout/2008"> <p baselineShift="0" breakOpportunity="auto" color="#000000" digitCase="default" digitWidth="default" direction="ltr" fontFamily="小塚ゴシック Pro R" fontSize="60" fontStyle="normal" fontWeight="normal" ligatureLevel="common" lineHeight="72" lineThrough="false" locale="en" textAlpha="1" textDecoration="none" textRotation="auto" trackingRight="0%" typographicCase="default"> <span fontLookup="inherit">TLF</span> <span fontLookup="inherit" trackingRight="-10%">T</span> <span fontLookup="inherit">ext</span> <span fontLookup="inherit" trackingRight="-2%">F</span> <span fontLookup="inherit">ield</span> <span fontFamily="小塚明朝 Pro M" fontLookup="inherit">で</span> </p> <p baselineShift="0" breakOpportunity="auto" color="#000000" digitCase="default" digitWidth="default" direction="ltr" fontFamily="小塚明朝 Pro M" fontSize="60" fontStyle="normal" fontWeight="normal" ligatureLevel="common" lineHeight="72" lineThrough="false" locale="en" textAlpha="1" textDecoration="none" textRotation="auto" trackingRight="0%" typographicCase="default"> <span fontLookup="inherit">美し</span> <span fontLookup="inherit" trackingRight="-4%">い</span> <span fontLookup="inherit" trackingRight="-6%">日</span> <span fontLookup="inherit" trackingRight="2%">本</span> <span fontLookup="inherit">語。</span> </p> </TextFlow> |
ちなみに、PSDで文字間の字詰めをする時はカーニング(普通こっちを使うと思うけど)ではなくトラッキングを使って字詰めをしたほうがインポートの結果はよさそうです。
カーニングだとなんかむちゃくちゃ。
TLFTextField独習
2010 年 7月 7 日 水曜日 kosukeご存知の通り、Flash CS5からテキストフィールドは従来のTextFieldと、Text Layout Frameworkを実装したTLFTextFieldが扱えるようになりました。
Text Layout Frameworkは、Flash Player 10から実装されているFlash Text Engineを扱いやすいようにコンポーネント化したフレームワークなんだけど、Flash Text Engineはもとい、Text Layout Frameworkすらも、もうわけわからないってくらい、プロパティ、メソッドが多すぎて痺れます。
しかし、強力なテキスト管理機能を有した新しいテキストエンジンが今後の主流になっていくだろうし、テキストの扱いは地味ながら間違いなく多用するものなので習得せにゃならんだろうと思います。
という訳で、使える機会があれば少しづつ移行しているのだけれど、新しいものってことで実際にコケたところや試したことをエントリーしていこうかと。
とりあえず、先日転んだところで、TLFTextFieldのこと。
TLFTextFieldに関しては、正直今までのTextFieldと変わらないじゃん!わけないよ!くらいに思っていたら、小一時間悩み続けていたという話。
TextFieldでは、一部HTMLのタグが使えました。さらにスタイルシートによる、一部スタイルの指定ができました。
たとえばこんな感じ。aタグにスタイルを指定して、linkとlink:hoverにカラーを適用できます。Flashで外部更新可能なニュースを作ったりする時に使いますよね。
package{ import flash.display.Sprite; import flash.text.*; public class TextFieldStyle extends Sprite{ public function TextFieldStyle(){ XML.ignoreComments = true; XML.ignoreProcessingInstructions= true; XML.ignoreWhitespace = true; XML.prettyIndent = 0; XML.prettyPrinting = false; var doc:XML = <div>これはTextFieldです。ここを押すと<a href="http://blog.nipx.jp" target="_blank">リンク</a>します。</div>; var style:StyleSheet = new StyleSheet(); style.setStyle( "a",{ color:"#4371A0" } ); style.setStyle( "a:hover",{ color:"#6F8F0F" } ); var field:TextField = new TextField(); field.x = 250; field.y = 10; field.width = 0; field.height = 0; field.autoSize = TextFieldAutoSize.CENTER; field.wordWrap = false; field.condenseWhite = true; field.styleSheet = style; field.htmlText = doc.toString(); addChild( field ); } } } |
TLFTextFieldでも同じようにHTMLタグが利用できます。
package{ import fl.text.TLFTextField; import flash.display.Sprite; import flash.text.*; public class TLFTextFieldStyle extends Sprite{ public function TLFTextFieldStyle(){ XML.ignoreComments = true; XML.ignoreProcessingInstructions= true; XML.ignoreWhitespace = true; XML.prettyIndent = 0; XML.prettyPrinting = false; var doc:XML = <div>これはTLFTextFieldです。ここを押すと<a href="http://blog.nipx.jp" target="_blank">リンク</a>します。</div>; var style:StyleSheet = new StyleSheet(); style.setStyle( "a",{ color:"#4371A0" } ); style.setStyle( "a:hover",{ color:"#6F8F0F" } ); var field:TLFTextField = new TLFTextField(); field.x = 250; field.y = 10; field.width = 0; field.height = 0; field.autoSize = TextFieldAutoSize.CENTER; field.wordWrap = false; field.condenseWhite = true; field.styleSheet = style; field.htmlText = doc.toXMLString(); addChild( field ); } } } |
しかし、aタグのスタイル指定が適用されていません。そうTLFTextFieldは、TextFieldと共通の使い勝手の同じプロパティが多数あるけど、中身は別物。styleSheetプロパティについては、
ってことで、styleSheetのプロパティはあるけれど常に無意味。スタイルシートはサポートされない。
そもそも、HTMLタグはサポートされるものの、TLFTextFieldのhtmlTextでは、
aタグの疑似クラスからしてサポートされていないみたい。
ええ!?それじゃあ劣化してんじゃん?って思うのは浅はかだったというもの。そこはしっかりText Layout Frameworkでサポートされています。魔のText Layout Frameworkで。
TLFTextField.textFlowのプロパティにそれらしきものを見つけたところから迷走しだす。
一連のヘルプを読み、
Text Layout Framework の使用
野中先生の解説を読み、
ActionScript 3.0でFlash Professional CS5の Text Layout Frameworkを使う
TLFTextField.textFlowのTextFlowを直接定義したり入れ替えたりと散々まさぐって、それで今回の指定はできたんですけど、なんともまどろっこしい。TLFTextField使う意味ないじゃん!
後にそんなことをせずとも出来ることに気づいた。
TLFTextField.tlfMarkupプロパティ。あるじゃん!これに記述を入れれば出来ました。
package{ import fl.text.TLFTextField; import flash.display.Sprite; import flash.text.*; import flashx.textLayout.conversion.*; import flashx.textLayout.elements.TextFlow; import flashx.textLayout.formats.TextLayoutFormat; public class TLFTextFieldStyle1 extends Sprite{ public function TLFTextFieldStyle1(){ XML.ignoreComments = true; XML.ignoreProcessingInstructions= true; XML.ignoreWhitespace = true; XML.prettyIndent = 0; XML.prettyPrinting = false; var doc:XML = <div>これはTLFTextFieldです。ここを押すと<a href="http://blog.nipx.jp" target="_blank">リンク</a>します。</div>; var field:TLFTextField = new TLFTextField(); field.x = stage.stageWidth/2; field.y = 10; field.width = 0; field.height = 0; field.autoSize = TextFieldAutoSize.CENTER; field.wordWrap = false; field.multiline = false; field.condenseWhite = true; //変換 var flow:TextFlow = TextConverter.importToFlow( doc.toXMLString(), TextConverter.TEXT_FIELD_HTML_FORMAT ); var markup:XML = TextConverter.export( flow, TextConverter.TEXT_LAYOUT_FORMAT, ConversionType.XML_TYPE ) as XML; field.tlfMarkup = markup; //リンクフォーマット var linkNormalFormat:TextLayoutFormat = new TextLayoutFormat(); linkNormalFormat.color = 0x4371A0; var linkHoverFormat:TextLayoutFormat = new TextLayoutFormat(); linkHoverFormat.color = 0x6F8F0F; field.textFlow.linkNormalFormat = linkNormalFormat; field.textFlow.linkHoverFormat = linkHoverFormat; //更新 field.textFlow.invalidateAllFormats(); field.textFlow.flowComposer.updateAllControllers(); addChild( field ); } } } |
とりあえず今回要件を満たすには、テキストはTextLayout マークアップ形式で記述する必要があります。
この形式で記述するなら、たとえば、
var doc:XML = <TextFlow xmlns='http://ns.adobe.com/textLayout/2008'><p><span>これはTLFTextFieldです。ここを押すと</span><a href="http://blog.nipx.jp" target="_blank">リンク</a><span>します。</span></p></TextFlow>; |
のように記述しなければいけない。この例でも<span>の記述がなんだかめんどくさいと思うんだよね。
外部ファイルでメンテナンスできることを前程に考えているんで、知識のないひとに記述してもらうのはますます厳しい。
なので、元の、
var doc:XML = <div>これはTLFTextFieldです。ここを押すと<a href="http://blog.nipx.jp" target="_blank">リンク</a>します。</div>; |
を変換する方法で考えます。
記述をTextFlowに変換したりTextFlowをマークアップに変換したりする、TextConverterクラスがあるのですが、直接この記述を、
var doc:XML = <div>これはTLFTextFieldです。ここを押すと<a href="http://blog.nipx.jp" target="_blank">リンク</a>します。</div>; var flow:TextFlow = TextConverter.importToFlow( doc, TextConverter.TEXT_LAYOUT_FORMAT); |
のようにしても変換できません。
一旦、TextConverter.TEXT_FIELD_HTML_FORMATに変換してから、再度TextConverter.TEXT_LAYOUT_FORMATの記述に書き出します。
var flow:TextFlow = TextConverter.importToFlow( doc.toXMLString(), TextConverter.TEXT_FIELD_HTML_FORMAT ); var markup:XML = TextConverter.export( flow, TextConverter.TEXT_LAYOUT_FORMAT, ConversionType.XML_TYPE ) as XML; field.tlfMarkup = markup; |
TLFTextFieldのtextFlowではリンクのフォーマットを指定して、最後に更新する。
invalidateAllFormats()が重要。これを実行しないと新しいフォーマットが適用されなかった。
var linkNormalFormat:TextLayoutFormat = new TextLayoutFormat(); linkNormalFormat.color = 0x4371A0; var linkHoverFormat:TextLayoutFormat = new TextLayoutFormat(); linkHoverFormat.color = 0x6F8F0F; field.textFlow.linkNormalFormat = linkNormalFormat; field.textFlow.linkHoverFormat = linkHoverFormat; field.textFlow.invalidateAllFormats(); field.textFlow.flowComposer.updateAllControllers(); |
Safari 5.0 で画面が溶ける
2010 年 6月 22 日 火曜日 kosukeSafari 5.0 にしたら全面Flashのリサイズ時にオブジェクトが伸びるようになった。革新的過ぎる。他のサイトでも起きてるし、FireFoxでは今迄どおり動いているし。仕様か?バグか?新手の嫌がらせか?!
Safari バージョン 5.0 (6533.16)
forループ
2010 年 6月 14 日 月曜日 kosuke小ネタが続きます。
forステートメントは、指定回数のループに用いることが通常ですが、構文的には、
for( 初期値; 終了する条件; 次の値 ) |
です。なので例えば以下みたいに使うことも出来る。
var master:Vector.<String> = Vector.<String>([ "0", "1", "2", "1", "21", "2", "2" ]); var record:Vector.<String> = Vector.<String>([]); function getValue( str:String ):String{ var value:String; for each( var target:String in record ){ if( target == str ){ value = target; break; } } return value; } for( var i:uint=0; i<master.length; i++ ){ var n:String = master[i]; for( n; getValue(n); n+="+" ); record.push( n ); } trace( "master:" + master ); trace( "record:" + record ); |
上記のソースでは、ある文字列の配列をループして、同じ名前があったら、文字列の最後に「+」を付与しています。
for文のポイントはここ。
for( n; getValue(n); n+="+" ); |
初期値nには、配列から取得した文字列になります。
終了条件は、getValueで得ます。getValueはnの文字列が既に登録されていたらその文字列を、そうでなければ空を返す。
次の値はnの最後に「+」を付与したもの。
このループを通過後、nにはまだ登録されていない文字列が入っています。
結果は以下になります。
master:0,1,2,1,21,2,2
record:0,1,2,1+,21,2+,2++
これをどんな時に使うかというと、たとえばユーザが変更できるxmlから値を取得して使う時、その値は同じものがあってはならない場合なんかに有効。xmlで外部編集を可能にした場合、意図しない値をユーザが入力してしまう可能性があります。転ばぬ先の杖的にこういった構文を入れておくとよいかもしれないです。
AIR for Android Developer Prerelease を試してみた
2010 年 5月 25 日 火曜日 kosuke話題のAndroid用AIRの開発者向けプレリリースがどんなものなのか知りたく登録してみた。
プログラムはこちら。
Adobe AIR for Android
このプログラムは誰でも登録出来るのだけど、プログラムで得た内容を外部に開示してはならないようなことが記されているので詳細は書かず話を進めます。
ひとまず、本当に動くの?ってことが試したくて、昨日作った待ち受けFlashをas3で書き直してAIR化。Androidアプリにしてみる。
こちらも初めて使いましたが、Android SDKをダウンロードしてAndroidのエミューレート環境を作りインストールします。
どうかっていうと普通に動きます。拍子抜けするくらい簡単に。
で、先の理由で記事的には書きようがないわけですが、言いたいことが一つ出て来た。何かと言うと、
本当にいいの?Apple。Flash 無しで?
CS5は、これのiPhone版が既に完成された状態で組み込まれているっていうのにもったいないなぁ。FlashでiPhoneアプリ作りたいって開発者は大勢いるのに。iPhone OS4は本当にあの規約のままリリースするんですかね?