1. 程式人生 > >在Flashplayer中顯示PDF檔案, SWFTools怎麼用

在Flashplayer中顯示PDF檔案, SWFTools怎麼用

目前在百度文件和另外一個什麼線上文件中見過這個做法,在美國的box網站也見過。

在網址:http://www.swftools.org/download.html(或http://wiki.swftools.org/wiki/Main_Page)下載SWFTools的最新版的exe安裝檔案,然後安裝到Windows。

swftools-inst-dir

現在,本地已經有pdf2swf.exe了,在cmd視窗中使用它:

C:\Program Files\SWFTools>pdf2swf D:\KONICA\displayPDF\Q_CRCC_0123.pdf -o D:\KONICA\displayPDF\Q_CRCC_0123.swf

pdf-2-swf-in-cmd

建立的SWF檔案,看起來與原版的PDF沒有什麼不同:

converted-swf

28th June 2012增補:

現在再來看看如何將一個swf的第一幀輸出為一個影象:

swfrender-command

SWFTools這套工具並非對所有的SWF都有效,因為SWF裡面可能包含actionscript,而actionscript可能會通過網路訪問其他域名下的資源,並且同時,所有執行SWF的環境都會應用安全沙箱的規則來限制actionscript對於外界的訪問,所以在SWF裡的程式碼要訪問網路才能正常呈現的情況下,SWFTools並不能如我們期望的那樣解決問題。而如果畫面的內容是主要通過actionscript繪製的,那麼不能期待它正常工作


13rd Dec 2012增補:

不過,我剛剛用swfrender將swftool從pdf轉製出來的swf的畫面輸出為png,是成功的。

C:\Program Files\SWFTools>swfrender Q_CRCC_0213.swf -o C:\sample.png

18th Dec 2012增補:

現在又出現一個新問題,當我真正嘗試將轉製出來的SWF載入至我的Flash裡播放時,我發現一個問題,就是被載入進來的SWF的型別是AVM1Flash影片。我們先假設文件類的內容如下:

package  {
	
	import flash.display.MovieClip;
	import flash.display.Loader;
	import flash.events.Event;
	import flash.net.URLRequest;
	
	import flash.display.AVM1Movie;
	
	public class main extends MovieClip
	{
		private var _ldr:Loader;
		
		
		public function main() 
		{
			this.addEventListener(Event.ADDED_TO_STAGE, this.addedToStageHandler);
		}
		
		
		private function addedToStageHandler($e:Event):void
		{
			this._ldr = new Loader();
			this._ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, this.loadedHandler);
			var $req:URLRequest = new URLRequest("iso.swf");
			this._ldr.load($req);
		}
		
		
		private function loadedHandler($e:Event):void
		{
			trace($e.target.content);
			var $dd:AVM1Movie = $e.target.content as AVM1Movie;
			this.addChild($dd:);
		}

	}
	
}

我們將會看到, trace($e.target.content) 輸出的內容為: [object AVM1Movie]。而且我們同時也得到一個異常:

ArgumentError: Error #2180: 在 AVM1 內容已載入至 AVM2 (AS3) 內容的情況下,將 AVM1 內容 (AS1 或 AS2) 移動至 displayList 的不同部分是不合法的。

假如這個時候,我們想要解決的問題僅僅是顯示這個SWF的問題的話,那麼可以在載入完成事件觸發以前,就把Loader物件新增到 displayList 中。這樣,上述寫法就變成:

package  {
	
	import flash.display.MovieClip;
	import flash.display.Loader;
	import flash.events.Event;
	import flash.net.URLRequest;
	
	import flash.display.AVM1Movie;
	
	public class main extends MovieClip
	{
		private var _ldr:Loader;
		
		
		public function main() 
		{
			this.addEventListener(Event.ADDED_TO_STAGE, this.addedToStageHandler);
		}
		
		
		private function addedToStageHandler($e:Event):void
		{
			this._ldr = new Loader();
			this._ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, this.loadedHandler);
			var $req:URLRequest = new URLRequest("iso.swf");
			this._ldr.load($req);
			this.addChild(_ldr);
		}
		
		
		private function loadedHandler($e:Event):void
		{
			trace($e.target.content);
			var $dd:AVM1Movie = $e.target.content as AVM1Movie;
		}

	}
	
}

然而這個辦法的壞處是很顯然的,你無法進一步操作這個載入進來的AVM1物件。於是進一步的搜尋令我尋找到一個稱為ForcibleLoader的工具類,它可以將AVM1轉換為MovieClip。示例程式碼可以點此下載

ForcibleLoader的使用方法為:

package  {
	
	import flash.display.MovieClip;
	import flash.display.Loader;
	import flash.events.Event;
	import flash.net.URLRequest;
	
	import flash.display.AVM1Movie;
	
	public class main extends MovieClip
	{
		private var _ldr:Loader;
		private var _fLoader:ForcibleLoader;
		private var _mc:MovieClip ;
		
		
		public function main() 
		{
			this.addEventListener(Event.ADDED_TO_STAGE, this.addedToStageHandler);
		}
		
		
		private function addedToStageHandler($e:Event):void
		{
			this._ldr = new Loader();
			this._fLoader = new ForcibleLoader(_ldr)
			this._fLoader.load(new URLRequest('iso.swf'));
			this.addChild(_ldr);
			this.addEventListener(Event.ENTER_FRAME, this.onloadFunction);
		}
		
		
		private function onloadFunction(e:Event):void 
		{
			if (this._ldr.content != null) 
			{
				this.removeEventListener(Event.ENTER_FRAME, onloadFunction);
				this._mc = this._ldr.content as MovieClip;
				//this._mc.addFrameScript(12, loop);
				trace(this._mc.totalFrames);
				this._mc.gotoAndStop(1);
			}
		}
		
	}
	
}

18th Dec 2012增補:

之所以會堅持以為通過在AS載入AVM1的swf時,尋找解決方法,是因為受到一篇文章的誤導:

這個印度阿三在裡面確定無疑地說SWFTools不能生成AVM2影片剪輯。不過這篇文章寫於2009年。後來我在SWFTools的官網上面找到連結:

於是我嘗試了使用新的命令來建立SWF(注意:其中insertstop的結果將使SWF的每一幀都有stop()指令,否則,SWF將會自動在逐個幀之間迴圈播放,而幀頻被設定為0.25,即每幀停留4秒):

C:\Program Files\SWFTools>pdf2swf -T9 -s insertstop ISO27001.pdf -o xxx.swf

cmd-with-version-shot

現在使用最初的文件類的寫法載入這個新生成的SWF:

package  {
	
	import flash.display.MovieClip;
	import flash.display.Loader;
	import flash.events.Event;
	import flash.net.URLRequest;
	
	public class main extends MovieClip
	{
		private var _ldr:Loader;
		
		public function main() 
		{
			this.addEventListener(Event.ADDED_TO_STAGE, this.addedToStageHandler);
		}
		
		
		private function addedToStageHandler($e:Event):void
		{
			_ldr = new Loader();
			_ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, this.loadedHandler);
			var $req:URLRequest = new URLRequest("t9.swf");
			_ldr.load($req);
		}
		
		
		private function loadedHandler($e:Event):void
		{
			trace($e.target.content);
			var $mc:MovieClip = $e.target.content as MovieClip;
			addChild($mc);
			trace($mc.totalFrames);
			$mc.gotoAndStop(5);
		}
		
	}
	
}

其中 trace($e.target.content) 得到的第一行輸出為:

[object MainTimeline_9549329e]

另外,在通過windows上面的GUI版本的SWFTools可以建立帶有閱覽器的SWF,但是我並未能夠成功用命令列建立帶有viewer的SWF檔案。

with-viewer

19th Dec 2012增補:

根據上面連結中的內容,做了如下嘗試:

C:\Program Files\SWFTools>swfcombine -o ff.swf rfx8.swf viewport=sss.swf

viewport後面的swf即是之前從pdf轉制的swf。當然,需要注意,兩個被合併的swf需要版本相同。不然會得到警告:

Warning: File contains both flash 8 and flash 9 actionscript

可是現在的問題仍然是,如何在轉制的時候就一起合併。

在之前的實驗中已經發現,viewer的swf需要與pdf2swf.exe在同一路徑下。所以在這個前提下,下面的命令是會成功執行並且得到期望結果的:

C:\Program Files\SWFTools>pdf2swf -B rfx8.swf ISO27001.pdf -o 19th.swf

但從執行過程的輸出來看,其實pdf2swf自動呼叫了swfcombine:

C:\Program Files\SWFTools>pdf2swf -B rfx8.swf ISO27001.pdf -o 19th.swf
NOTICE  processing PDF page 1 (841x595:0:0)
NOTICE  File contains jpeg pictures
NOTICE  processing PDF page 2 (841x595:0:0)
NOTICE  processing PDF page 3 (841x595:0:0)
NOTICE  processing PDF page 4 (841x595:0:0)
NOTICE  processing PDF page 5 (841x595:0:0)
NOTICE  processing PDF page 6 (841x595:0:0)
NOTICE  processing PDF page 7 (841x595:0:0)
NOTICE  processing PDF page 8 (841x595:0:0)
NOTICE  processing PDF page 9 (841x595:0:0)
NOTICE  processing PDF page 10 (841x595:0:0)
NOTICE  processing PDF page 11 (841x595:0:0)
NOTICE  processing PDF page 12 (841x595:0:0)
NOTICE  processing PDF page 13 (841x595:0:0)
NOTICE  processing PDF page 14 (841x595:0:0)
NOTICE  processing PDF page 15 (841x595:0:0)
NOTICE  processing PDF page 16 (841x595:0:0)
NOTICE  processing PDF page 17 (841x595:0:0)
NOTICE  processing PDF page 18 (841x595:0:0)
NOTICE  processing PDF page 19 (841x595:0:0)
NOTICE  processing PDF page 20 (841x595:0:0)
NOTICE  processing PDF page 21 (841x595:0:0)
NOTICE  processing PDF page 22 (841x595:0:0)
NOTICE  Writing SWF file 19th.swf
swfcombine  -X 841 -Y 595 "rfx8.swf" viewport="19th.swf" -o "19th.swf"

現在的問題是如何自制一個flash 9版本的viewer。過程如下,首先stage的尺寸是600x800;建立三個MovieClip元件,其子內容皆為在Flash Pro CS5.5中繪製的Graphic,將三者拖放到stage中:

viewer-design

三個元件的名稱為:prev,next,viewport。

第一幀程式碼層上as程式碼如下:

import flash.events.MouseEvent;

prev.addEventListener(MouseEvent.MOUSE_DOWN, onPrev);
next.addEventListener(MouseEvent.MOUSE_DOWN, onNext);

function onPrev($e:MouseEvent):void
{
	viewport.prevFrame();
}

function onNext($e:MouseEvent):void
{
	viewport.nextFrame();
}

viewport.gotoAndStop(1);

測試執行,生成一個名為viewer.swf的flash檔案。將它複製到SWFTools的路徑下,重新執行命令。

C:\Program Files\SWFTools>pdf2swf -T9 -s insertstop -B viewer.swf ISO27001.pdf -o 19th-2.swf
NOTICE  processing PDF page 1 (841x595:0:0)
NOTICE  File contains jpeg pictures
NOTICE  processing PDF page 2 (841x595:0:0)
NOTICE  processing PDF page 3 (841x595:0:0)
NOTICE  processing PDF page 4 (841x595:0:0)
NOTICE  processing PDF page 5 (841x595:0:0)
NOTICE  processing PDF page 6 (841x595:0:0)
NOTICE  processing PDF page 7 (841x595:0:0)
NOTICE  processing PDF page 8 (841x595:0:0)
NOTICE  processing PDF page 9 (841x595:0:0)
NOTICE  processing PDF page 10 (841x595:0:0)
NOTICE  processing PDF page 11 (841x595:0:0)
NOTICE  processing PDF page 12 (841x595:0:0)
NOTICE  processing PDF page 13 (841x595:0:0)
NOTICE  processing PDF page 14 (841x595:0:0)
NOTICE  processing PDF page 15 (841x595:0:0)
NOTICE  processing PDF page 16 (841x595:0:0)
NOTICE  processing PDF page 17 (841x595:0:0)
NOTICE  processing PDF page 18 (841x595:0:0)
NOTICE  processing PDF page 19 (841x595:0:0)
NOTICE  processing PDF page 20 (841x595:0:0)
NOTICE  processing PDF page 21 (841x595:0:0)
NOTICE  processing PDF page 22 (841x595:0:0)
NOTICE  Writing SWF file 19th-2.swf
swfcombine  -X 841 -Y 595 "viewer.swf" viewport="19th-2.swf" -o "19th-2.swf"

實際上有一些地方需要注意,我將兩個黃色翻頁按鈕擺放的Y位置是511,因為通過pdf2swf生成的SWF的高是按照pdf中的高度來設定的,就是提示中的595,而之後當呼叫swfcombine時這個數字作為引數被傳入,結果,與viewer合成後的swf的高就變成了595了。現在的問題是,如何在pdf2swf中就指定這個高度,來調整輸出的swf的高度,這樣就可以令按鈕不必遮住pdf的內容。

printed-swf

現在,這個新生成的swf是flash 9的版本,同時又具有了viewer,我們再來看看把它載入進一個Flash之後,得到的是個什麼東東:

trace($mc.numChildren);	// 3
var $obj1:* = $mc.getChildAt(0);	// MovieClip, viewport
var $obj2:* = $mc.getChildAt(1);	// MovieClip, prev
var $obj3:* = $mc.getChildAt(2);	// MovieClip, next

這個結構與當初建立viewer時的結構是一樣的,參見上面的截圖。

相關文件:

Refs: