Player10.0 でも purePDF で日本語PDFを作る

purePDF とは

PDF を FlashPlayer 内で作成する為のライブラリです。 Java の iText ライブラリを AS3 移植とのことです。 チャプタ・セクション・パラグラフ・フレーズ・イメージなどの基本要素と、カラム・リスト・テーブル・セルなどのレイアウト要素を用い自由にレイアウトした PDF を作成することができます。 また、 AS の GraphicsAPI のようなベクターグラフィックスやグラデーション塗りにも対応した多機能なライブラリです。

purePDF についての情報は下記リンクをご覧下さい。

問題点

日本語などの 2 バイト文字が特定の環境下で正常に出力できません。 これはライブラリのバグではなく、 FlashPlayer 10.0 のバグです。 FlashPlayer 10.1 (10/05/10 時点では RC4) だとバグフィックスされているので、バグ対応することなく日本語の使用が可能です。(nod さんからTwitter で教えて頂きました。ありがとうございます。) Windows FlashPlayer 10.0 では日本語が全て文字化けして出力されます。 Macintosh FlashPlayer 10.0 では 2 バイト文字中に 1 バイト文字が入ると同要素内の以降の文字が出力されません。 Linux FlashPlayer 10.0 では何も出力されません。

原因

環境によって問題の現象が異なりますが、原因は同じ関数のバグによるものです。 ByteArray.writeMultiByte(hoge, 'unicodeFFFE')が FlashPlayer10.0 で 正常に動作していないことが直接の原因です。

対処法

FlashPlayer10.0 で encoding が 'UnicodeBigUnmarked' の場合、文字列を走査し、キャラクタコードを書き込みます。 jp.ferv.blog » Blog Archive » ByteArray に ‘unicodeFFFE’ を書き込む際のバグ に諸環境下でのバグの症状と対応策の詳細を書きましたので、合わせてご覧下さい。

バグFIX済み purePDF によるプレビュー

ローマ字・半角カナ・第一水準漢字・第二水準漢字を書き込んだ PDF を FlashPlayer 内で作成します。

purePDF_jp

この SWF から各環境下で作成した PDF です。

対応済み purePDF のソース・swc と Expample 用の as ファイルのダウンロード

purePDF_jp.zip

purePDF のライセンスは LGPL なので、継承して LGPL ライセンスでの配布となります。

変更箇所

バグのある関数をコールしている箇所を、 ByteArrayUtils クラス内のバグ対応用の関数をコールするように変更します。

  • ActionScript
  • PdfEncodings.as
  • Source
//byte.buffer.writeMultiByte( text, ByteArrayUtils.getEncoding( encoding ) );
ByteArrayUtils.writeMultiByte( byte.buffer, text, ByteArrayUtils.getEncoding( encoding ) ); // modified by dsk(http://ferv.jp)
  1. //byte.buffer.writeMultiByte( text, ByteArrayUtils.getEncoding( encoding ) );
  2. ByteArrayUtils.writeMultiByte( byte.buffer, text, ByteArrayUtils.getEncoding( encoding ) ); // modified by dsk(http://ferv.jp)

バグ対応用の関数です。 まず Capabilities.version から FlashPlayer のバージョンを判定します。 問題のないバージョンの場合は文字列を走査せず、 そのまま writeMultiByte() で書き込みます。 問題のあるバージョンの場合は文字列を走査しつつキャラクタコードを取得し、 2 バイトに収まるキャラクタコードの場合は writeShort() で書き込み、 収まらない場合は 4 バイトとして writeUnsignedInt() で書き込みます。

  • ActionScript
  • ByteArrayUtils.as
  • Source
import flash.system.Capabilities;
  1. import flash.system.Capabilities;

  • ActionScript
  • ByteArrayUtils.as
  • Source
/**
 * @author dsk (http://ferv.jp)
 */
private static var _specifiedVersion:Boolean = false;

/**
 * @author dsk (http://ferv.jp)
 */
private static var _isUnder10_1:Boolean;
  1. /**
  2.  * @author dsk (http://ferv.jp)
  3.  */
  4. private static var _specifiedVersion:Boolean = false;
  5.  
  6. /**
  7.  * @author dsk (http://ferv.jp)
  8.  */
  9. private static var _isUnder10_1:Boolean;

  • ActionScript
  • ByteArrayUtils.as
  • Source
/**
 * bug fix : fail to work "buffer.writeMultiByte( value, 'unicodeFFFE' )" at FP10.0;
 * @author dsk (http://ferv.jp)
 */
public static function writeMultiByte( buffer: ByteArray, value: String, charSet: String ):void
{
	if (!_specifiedVersion)
		_specifyVersion();
	
	if (!(_isUnder10_1 && charSet = 'unicodeFFFE'))
		buffer.writeMultiByte( value, charSet );
	else
		_writeUnicodeFFFEByte( buffer, value );
	
	buffer.position = 0;
}

/**
 * emulate writing utf-16 BE
 * bug fix : fail to work "buffer.writeMultiByte( value, 'unicodeFFFE' )" at FP10.0
 * @author dsk (http://ferv.jp)
 */
private static function _writeUnicodeFFFEByte( buffer: ByteArray, value: String ):void
{
	var len:int = value.length;
	var i:int, code:uint;
	for (i = 0; i < len; i ++)
	{
		code = value.charCodeAt(i);
		if (code < 0x10000)
			buffer.writeShort(code);
		else
			buffer.writeUnsignedInt(code);
	}
}

/**
 * specify the Flash Player platform and version
 * @author dsk (http://ferv.jp)
 */
private static function _specifyVersion():void
{
	var info:Array = Capabilities.version.split(' ');
	var versions:Array = info[1].split(',');
	var majorMinor:Number = parseFloat(versions[0] + '.' + versions[1]);
	_isUnder10_1 = (majorMinor < 10.1);
	trace('ByteArrayUtils.specifyVersion. to be implemented :', 'isUnder10_1 =', _isUnder10_1);
	
	_specifiedVersion = true;
}
  1. /**
  2.  * bug fix : fail to work "buffer.writeMultiByte( value, 'unicodeFFFE' )" at FP10.0;
  3.  * @author dsk (http://ferv.jp)
  4.  */
  5. public static function writeMultiByte( buffer: ByteArray, value: String, charSet: String ):void
  6. {
  7.     if (!_specifiedVersion)
  8.         _specifyVersion();
  9.    
  10.     if (!(_isUnder10_1 && charSet = 'unicodeFFFE'))
  11.         buffer.writeMultiByte( value, charSet );
  12.     else
  13.         _writeUnicodeFFFEByte( buffer, value );
  14.    
  15.     buffer.position = 0;
  16. }
  17.  
  18. /**
  19.  * emulate writing utf-16 BE
  20.  * bug fix : fail to work "buffer.writeMultiByte( value, 'unicodeFFFE' )" at FP10.0
  21.  * @author dsk (http://ferv.jp)
  22.  */
  23. private static function _writeUnicodeFFFEByte( buffer: ByteArray, value: String ):void
  24. {
  25.     var len:int = value.length;
  26.     var i:int, code:uint;
  27.     for (i = 0; i < len; i ++)
  28.     {
  29.         code = value.charCodeAt(i);
  30.         if (code < 0x10000)
  31.             buffer.writeShort(code);
  32.         else
  33.             buffer.writeUnsignedInt(code);
  34.     }
  35. }
  36.  
  37. /**
  38.  * specify the Flash Player platform and version
  39.  * @author dsk (http://ferv.jp)
  40.  */
  41. private static function _specifyVersion():void
  42. {
  43.     var info:Array = Capabilities.version.split(' ');
  44.     var versions:Array = info[1].split(',');
  45.     var majorMinor:Number = parseFloat(versions[0] + '.' + versions[1]);
  46.     _isUnder10_1 = (majorMinor < 10.1);
  47.     trace('ByteArrayUtils.specifyVersion. to be implemented :', 'isUnder10_1 =', _isUnder10_1);
  48.    
  49.     _specifiedVersion = true;
  50. }


About this entry