Flashから日本語PDFを生成(AlivePDF+MBPDF)

Flashから日本語PDFを生成(AlivePDF+MBPDF)日本語PDFを作ってみた。Alive PDFに日本語を埋め込めるようにするクラス、MBPDFを追加したらできた。

先日の「FlashからPDFを生成(AlivePDF)」では、日本語を埋め込むことができなかった。AlivePDFが日本語(マルチバイト)に対応していないためだ。そこで、AlivePDFを継承し、日本語を埋め込むための機能を追加したクラスがMBPDF。

そんなわけで作ってみた。

[kml_flashembed fversion=”9.0.0″ movie=”http://www.mztm.jp/wp/wp-content/uploads/2009/07/umhr_alivepdf2.swf” targetclass=”flashmovie” publishmethod=”static” width=”465″ height=”465″]

Get Adobe Flash player

[/kml_flashembed]

かなりクセがあってとまどった。特にテキストを配置する方法がたくさんあって、それぞれできることが微妙に違うところは、なかなか慣れない。
あと、フォントはゴシックに指定しているけど、明朝の文字になってしまう。英語版では問題ないので、これはMBPDF側の問題なのかな。

▼ファイル一式
http://www.mztm.jp/wp/wp-content/uploads/2009/07/umhr_alivepdf2.zip

▼MBPDF(Flex3 PDF作成その2)
http://www.harhid-labo.com/p1/index.php?Flex3%20PDF作成その2

▼AlivePDF API Documentation
http://www.bytearray.org/wp-content/projects/alivepdf/alivepdf-asdoc/

▼ActionScript AS3(FP9)

package {
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.display.SimpleButton;
	import flash.events.Event;
	import fl.controls.NumericStepper;
	import br.com.stimuli.loading.BulkLoader;
	//Alive PDF
	import org.alivepdf.pdf.PDF;
	import org.alivepdf.layout.Orientation;
	import org.alivepdf.layout.Size;
	import org.alivepdf.layout.Unit;
	import org.alivepdf.layout.Layout;
	import org.alivepdf.display.Display;
	import org.alivepdf.saving.Method;
	import org.alivepdf.fonts.FontFamily;
	import org.alivepdf.fonts.Style;
	import org.alivepdf.colors.RGBColor;
	import org.alivepdf.fonts.FontFamily;
	//MBPDF
	import org.alivepdf.japanese.pdf.MBPDF;
	import org.alivepdf.japanese.fonts.MBFontFamily;
	
	public class Main extends Sprite {
		
		private var loader : BulkLoader;
		private var naiyo_array:Array;
		private var NumericStepper_array:Array;
		private var tanka_array:Array;
		private var para:BitmapData;
		private var bmp_obj:Bitmap;
		private var myPDF:PDF;
		private var bm:Bitmap;
		private var title:TextField = Create.newTextField([5,5,455,23],[["border",true],["type","input"],["background",true],["wordWrap",true]]);
		private var tf:TextField = Create.newTextField([205, 30, 255, 205], [["border", true], ["type", "input"], ["background", true], ["wordWrap", true]]);
		function Main() {
			var baseURL:String = "";
			if(stage.loaderInfo.url.indexOf("mztm.jp") > -1){
				baseURL = "http://www.mztm.jp/wp/wp-content/uploads/2009/07/";
			}else if(stage.loaderInfo.url.substr(0,5) == "file:"){
			}
			
			loader = new BulkLoader("main-site");
			loader.add(baseURL+"fig.jpg", {id:"naiyouimg"});
			loader.addEventListener(BulkLoader.COMPLETE, COMPLETE);
			loader.start();
		}
		public function COMPLETE(evt:Event) : void {
			bm = loader.getBitmap("naiyouimg");
			
			var sp:Sprite = new Sprite();
			sp.addChild(bm);
			sp.y = 40;
			sp.scaleX = sp.scaleY = 0.5;
			addChild(sp);
			
			//入力欄
			title.text = "公国軍突撃機動軍司令 御中";
			addChild(title);
			tf.text = "日本語をいれる。\nAlivePDF1.4.9では日本語フォントをPDFに埋め込めません。そこでAlivePDFの機能を拡張したのがMBPDF。MulitiByteのMB+PDF=MBPDF。これで晴れて日本語を埋め込めるようになりました。ただし、開発が終わったものではないので、かなり制約やクセがあります。今後改善されるとは思いますがしばらくはこの制約の範囲で工夫していく必要がありそうです。";
			
			//ちょっとしつこくて面白くないかも
			//tf.text = "水玉エレクトロニクスご担当者様\r先ほど、FAXで企画案をお送りしましたが、届きましたでしょうか?ご確認お願いします。\n先日相談した、デカツヨの件です。新しいおっと思わせる要素があってとにかく負けないやつが欲しいんです。そろそろ巻き返してガツンと行きたいですよね。\n管理部からニュータイプ(?)機には脱出装置必須って言われているんですけど対応できますか?一般兵向けにはとりあえず不要です。\nあと、とにかく急かされている!!ラウンチを早くできるような調整は全然OKです。\nとりあえずザックリで良いんで、ナル早で見積りをお願いします。\n\nP.S.一段楽したら、呑みに行きましょう!赤坂にいい感じのB級グルメの店見つけました!!"
			addChild(tf);
			
			var naiyo:Array = ["本体(艦隊攻撃級)", "サイコミュ高機動対応", "コックピット1(ニュータイプ用脱出機能付)", "コックピット2(一般用半自動オールレンジ攻撃機能付)", "武装(有線制御式5連装メガ粒子砲)", "武装(頭部メガ粒子砲)", "武装(腰部メガ粒子砲)", "*脚部は別途お見積もりといたします。"];
			var suryo:Array = ["1","1","1","1","2","1","2","0"];
			var tanka:Array = ["3200000","740000","230000","110000","2400000","1100000","1000000","0"];
			naiyo_array = new Array();
			NumericStepper_array = new Array();
			tanka_array = new Array();
			for (var i:int = 0; i < naiyo.length; i++) {
				naiyo_array[i] = new TextField();
				naiyo_array[i].x = 5;
				naiyo_array[i].y = 237+i*25;
				naiyo_array[i].width = 321;
				naiyo_array[i].height = 23;
				naiyo_array[i].border = true;
				naiyo_array[i].type = "input";
				naiyo_array[i].background = true;
				naiyo_array[i].text = naiyo[i];
				addChild(naiyo_array[i]);
				NumericStepper_array[i] = new NumericStepper();
				NumericStepper_array[i].x = 328;
				NumericStepper_array[i].y = 238+i*25;
				NumericStepper_array[i].width = 50;
				NumericStepper_array[i].value = suryo[i];
				addChild(NumericStepper_array[i]);
				tanka_array[i] = new TextField();
				tanka_array[i].x = 380;
				tanka_array[i].y = 237+i*25;
				tanka_array[i].width = 80;
				tanka_array[i].height = 23;
				tanka_array[i].border = true;
				tanka_array[i].type = "input";
				tanka_array[i].background = true;
				tanka_array[i].text = tanka[i];
				addChild(tanka_array[i]);
			}
			
			
			//Generateボタン
			var btn:SimpleButton = Create.newSimpleButton([(465-100)/2,440,100,22,"見積書を生成"]);
			addChild(btn);
			btn.addEventListener( MouseEvent.CLICK, CLICK);
		}
		private function CLICK(e:MouseEvent):void {
			var myMBPDF:MBPDF = new MBPDF( Orientation.PORTRAIT, Unit.POINT, Size.A4 );
			myMBPDF.charSet = MBPDF.SHIFT_JIS;
			myMBPDF.addMBFont(MBFontFamily.GOTHIC,MBPDF.CMap_SJIS);
			myMBPDF.setDisplayMode ( Display.REAL ); 
			myMBPDF.addPage();
			//フォーマット(線)
			myMBPDF.lineStyle( new RGBColor ( 0x000000 ), 0);
			myMBPDF.moveTo ( 20, 35 );
			myMBPDF.lineTo ( 117, 35 );
			myMBPDF.drawRoundRect(new Rectangle(20, 57, 170, 80),2);
			//横罫線
			myMBPDF.drawRect(new Rectangle(20, 160, 170, 75));
			for (var i:int = 0; i < 10; i++) {
				myMBPDF.moveTo ( 20, 165+7*i );
				myMBPDF.lineTo ( 190, 165+7*i );
			}
			myMBPDF.moveTo ( 130, 247 );
			myMBPDF.lineTo ( 190, 247 );
			//縦罫線
			myMBPDF.moveTo ( 130, 160 );
			myMBPDF.lineTo ( 130, 221 );
			myMBPDF.moveTo ( 140, 160 );
			myMBPDF.lineTo ( 140, 221 );
			myMBPDF.moveTo ( 164, 160 );
			myMBPDF.lineTo ( 164, 235 );
			myMBPDF.end();
			//下部のロゴ
			var me:MovieClip = new melogo();
			myMBPDF.addImage(me,98,270,me.width/10,me.height/10);
			
			//フォーマット(文字)
			myMBPDF.setFont(MBFontFamily.GOTHIC,Style.BOLD,16);
			myMBPDF.setXY(20, 10);
			myMBPDF.textStyle(new RGBColor ( 0xFFFFFF ));
			myMBPDF.addCell (31, 6," お見積書",0,0,"",1);
			myMBPDF.textStyle(new RGBColor ( 0x000000 ));
			myMBPDF.setFont(MBFontFamily.GOTHIC,Style.NORMAL,9);
			myMBPDF.setFontSize(10);
			myMBPDF.setXY(130, 11);
			myMBPDF.addMultiCell(60,0,"発行日:UC0079年"+((new Date).month+1)+"月"+(new Date).date+"日",0,"R")
			myMBPDF.setFontSize(7);
			myMBPDF.setXY(130, 15);
			myMBPDF.addMultiCell(60, 0, "見積もり有効期限:UC0079年12月31日", 0, "R")
			myMBPDF.setFontSize(14);
			myMBPDF.addText ("水玉エレクトロニクス",130, 33);
			myMBPDF.setFontSize(8);
			myMBPDF.setXY(130, 35);
			myMBPDF.addMultiCell(60, 3, "〒169-0072スペースコロニーサイド6\n新宿区大久保2-20-8,301\nTel/FAX 03-3204-3213")
			myMBPDF.setFontSize(9);
			myMBPDF.setXY(20, 56);
			myMBPDF.addText ("ご依頼内容",20, 56);
			myMBPDF.setFontSize(9);
			myMBPDF.addText ("下記の通りお見積いたします",20, 159.2);
			myMBPDF.setFontSize(9);
			myMBPDF.addText ("項目",75, 164);
			myMBPDF.addText ("数量",131, 164);
			myMBPDF.addText ("単価",148, 164);
			myMBPDF.addText ("金額",173, 164);
			myMBPDF.addText ("計",158, 226);
			myMBPDF.addText ("消費税(5%)",144, 233);
			myMBPDF.addText ("合計", 130, 246);
			
			//記述内容
			myMBPDF.setFont(MBFontFamily.GOTHIC,Style.BOLD,12);
			myMBPDF.addText (title.text,20, 33);
			myMBPDF.addImage(bm,22,60,bm.width/5,bm.height/5);
			myMBPDF.setFont(MBFontFamily.GOTHIC, Style.NORMAL, 8);
			myMBPDF.setXY(123, 58.7);
			myMBPDF.addMultiCell(65, 4.5, (tf.text).replace(/\r/g,"\n"),1);
			myMBPDF.setFontSize(10);
			
			var goukei:Number = 0;
			for (i = 0; i < NumericStepper_array.length; i++) {
				myMBPDF.addText (naiyo_array[i].text, 23, 170 + i * 7);
				if (NumericStepper_array[i].value == "0") {
					continue;
				}
				myMBPDF.addText (NumericStepper_array[i].value,134, 170+i*7);
				myMBPDF.setXY(140, 169+i*7);
				myMBPDF.addMultiCell(23, 0, toCommaString(Number(tanka_array[i].text)), 0, "R");
				myMBPDF.setXY(165, 169+i*7);
				myMBPDF.addMultiCell(23, 0, toCommaString(Number(NumericStepper_array[i].value) * Number(tanka_array[i].text)), 0, "R");
				goukei += Number(NumericStepper_array[i].value) * Number(tanka_array[i].text);
			}
			myMBPDF.setXY(165, 225);
			myMBPDF.addMultiCell(23, 0, toCommaString(goukei), 0, "R");
			myMBPDF.setXY(165, 232);
			myMBPDF.addMultiCell(23, 0, toCommaString(goukei*0.05), 0, "R");
			myMBPDF.setFontSize(16);
			myMBPDF.setXY(145, 244);
			myMBPDF.addMultiCell(43, 0, toCommaString(goukei*1.05), 0, "R");
			
			//phpに送る
			myMBPDF.save(Method.REMOTE, "http://mztm.heteml.jp/umhr/pdf/create.php");
		}
		
		//数字をカンマ区切りに
		private function toCommaString(n:Number):String {
			var str:String = String(n);
			var numStr:String = String(str).replace(/,|¥/g,"");
			var tmpStr:String;
			while (numStr != tmpStr){
				tmpStr = numStr;
				numStr = numStr.replace(/^([+-]?\d+)(\d{3})/, "$1,$2");
			}
			return numStr;
		}
	}
}



import flash.display.DisplayObject;
import flash.display.Graphics;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.display.Sprite;
import flash.display.Shape;
import flash.display.SimpleButton;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.events.KeyboardEvent;


class Create{
	public static var defaultTextFormat:TextFormat = new TextFormat();
	
	public static function newSimpleButton(x_y_w_h_txt:Array = null,property:Array=null,graphics:Array=null):SimpleButton{
		var upState:Sprite = newSprite([x_y_w_h_txt[0],x_y_w_h_txt[1]],null,[["beginFill",[0xCCCCCC,1]],["drawRoundRect",[0,0,x_y_w_h_txt[2],x_y_w_h_txt[3],8]]]);
		upState.addChild(newShape([2,2],null,[["beginFill",[0xE5E5E5,1]],["drawRoundRect",[0,0,x_y_w_h_txt[2]-4,x_y_w_h_txt[3]-4,6]]]))
		var overState:Sprite = newSprite([x_y_w_h_txt[0],x_y_w_h_txt[1]],null,[["beginFill",[0xBBBBBB,1]],["drawRoundRect",[0,0,x_y_w_h_txt[2],x_y_w_h_txt[3],8]]]);
		overState.addChild(newShape([2,2],null,[["beginFill",[0xEEEEEE,1]],["drawRoundRect",[0,0,x_y_w_h_txt[2]-4,x_y_w_h_txt[3]-4,6]]]))
		var downState:Sprite = newSprite([x_y_w_h_txt[0],x_y_w_h_txt[1]],null,[["beginFill",[0xAAAAAA,1]],["drawRoundRect",[0,0,x_y_w_h_txt[2],x_y_w_h_txt[3],8]]]);
		downState.addChild(newShape([2,2],null,[["beginFill",[0xDDDDDD,1]],["drawRoundRect",[0,0,x_y_w_h_txt[2]-4,x_y_w_h_txt[3]-4,6]]]))
		var hitTestState:Shape = newShape([x_y_w_h_txt[0],x_y_w_h_txt[1]],null,[["beginFill",[0,1]],["drawRoundRect",[0,0,x_y_w_h_txt[2],x_y_w_h_txt[3],8]]]);
		if(x_y_w_h_txt[4]){
			upState.addChild(newTextField([0,2,x_y_w_h_txt[2],x_y_w_h_txt[3]-2],[["defaultTextFormat",new TextFormat("_sans", null, null, null, null, null, null, null, "center")],["text",x_y_w_h_txt[4]]]));
			overState.addChild(newTextField([0,2,x_y_w_h_txt[2],x_y_w_h_txt[3]-2],[["defaultTextFormat",new TextFormat("_sans", null, null, null, null, null, null, null, "center")],["text",x_y_w_h_txt[4]]]));
			downState.addChild(newTextField([0,3,x_y_w_h_txt[2],x_y_w_h_txt[3]-3],[["defaultTextFormat",new TextFormat("_sans", null, null, null, null, null, null, null, "center")],["text",x_y_w_h_txt[4]]]));
		}
		var sb:SimpleButton = new SimpleButton(upState,overState,downState,hitTestState);
		
		return sb;
	}
	
	public static function newShape(x_y_w_h_sh:Array = null,property:Array=null,graphics:Array=null):Shape{
		var i:int;
		var sh:Shape;
		if(x_y_w_h_sh && x_y_w_h_sh[4]){
			sh = x_y_w_h_sh[4];
		}else{
			sh = new Shape();
		}
		if(x_y_w_h_sh){
			if (x_y_w_h_sh[0]) { sh.x = x_y_w_h_sh[0] };
			if (x_y_w_h_sh[1]) { sh.y = x_y_w_h_sh[1] };
		}
		if(property){
			for (i = 0; i < property.length; i++) {
				if(property[i] && property[i].length > 1){
					sh[property[i][0]] = property[i][1];
				}
			}
		}
		if(graphics){
			for (i = 0; i < graphics.length; i++) {
				if(graphics[i] && graphics[i].length > 1){
					sh.graphics[graphics[i][0]].apply(null, graphics[i][1]);
				}
			}
			
		}
		if(x_y_w_h_sh){
			if (x_y_w_h_sh[2]) { sh.width = x_y_w_h_sh[2] };
			if (x_y_w_h_sh[3]) { sh.height = x_y_w_h_sh[3] };
		}
		return sh;
	}
	public static function newSprite(x_y_w_h_sp:Array = null,property:Array=null,graphics:Array=null,addChild:DisplayObject = null):Sprite{
		var i:int;
		var sp:Sprite;
		if(x_y_w_h_sp && x_y_w_h_sp[4]){
			sp = x_y_w_h_sp[4];
		}else{
			sp = new Sprite();
		}
		if(x_y_w_h_sp){
			if (x_y_w_h_sp[0]) { sp.x = x_y_w_h_sp[0] };
			if (x_y_w_h_sp[1]) { sp.y = x_y_w_h_sp[1] };
		}
		if(property){
			for (i = 0; i < property.length; i++) {
				if(property[i] && property[i].length > 1){
					sp[property[i][0]] = property[i][1];
				}
			}
		}
		if(graphics){
			for (i = 0; i < graphics.length; i++) {
				if(graphics[i] && graphics[i].length > 1){
					sp.graphics[graphics[i][0]].apply(null, graphics[i][1]);
				}
			}
			
		}
		if(addChild){
			sp.addChild(addChild);
		}
		if(x_y_w_h_sp){
			if (x_y_w_h_sp[2]) { sp.width = x_y_w_h_sp[2] };
			if (x_y_w_h_sp[3]) { sp.height = x_y_w_h_sp[3] };
		}
		return sp;
	}

	public static function newTextField(x_y_w_h_txt_color_alpha:Array = null,property:Array=null,method:Array=null):TextField{
		var i:int;
		var ta:TextField = new TextField();
		ta.defaultTextFormat = defaultTextFormat;
		if(x_y_w_h_txt_color_alpha){
			if (x_y_w_h_txt_color_alpha[0]) { ta.x = x_y_w_h_txt_color_alpha[0] };
			if (x_y_w_h_txt_color_alpha[1]) { ta.y = x_y_w_h_txt_color_alpha[1] };
			if (x_y_w_h_txt_color_alpha[2]) { ta.width = x_y_w_h_txt_color_alpha[2] };
			if (x_y_w_h_txt_color_alpha[3]) { ta.height = x_y_w_h_txt_color_alpha[3] };
			if (x_y_w_h_txt_color_alpha[4]) { ta.text = x_y_w_h_txt_color_alpha[4] };
			if (x_y_w_h_txt_color_alpha[5]) { ta.textColor = x_y_w_h_txt_color_alpha[5] };
			if (x_y_w_h_txt_color_alpha[6]) { ta.alpha = x_y_w_h_txt_color_alpha[6] };
		}
		if(property){
			for (i = 0; i < property.length; i++) {
				if(property[i] && property[i].length > 1){
					ta[property[i][0]] = property[i][1];
				}
			}
		}
		if(method){
			for (i = 0; i < method.length; i++) {
				if(method[i] && method[i].length > 1){
					ta[method[i][0]].apply(null, method[i][1]);
				}
			}
		}
		return ta;
	}
}