SWFTools (pdf2swf) to properly work with Flex

Filed under Experiments, Flex, Flex 3, Flex Tutorials, Labs, Open Source Stuffs, Sample Application

It’s hype, there’s no word to describe how to involve and open-source command-line tool to transcode from pdf to swf file and get it right work with Flex.
So, I googled a lot yesterday and today morning, and didn’t find any relevance information on this field. I just saw a collection of developers getting problem to put it to work. For sure it’s a little hard work to put it in right to work.
The problem took me attention because we got a job from a start-up company that does document of any type and convert into a swf. Of course that you should put more effort to accomplish bunch things like Scribd does.
To help theses unlucky devs out there follow the steps of this tutorial bellow and 20% of your problem will solve, bet if solves 100% isn’t?

Get Start

  • Download the last version of SWFTools and put in the root of your HD access mine was (C:\swftools)
  • Grab some pdf you want to convert into swf and start transcode.
  • Open up your Prompt command and goes to the path where you put your SWFTools

To run the pdf to swf converter you just type :

C:\SWFTools\pdf2swf originalfile.pdf -o newfile.swf

This is automatically converts your pdf into something easy format like swf and ready to Flash Player.

The pdf2swf has many options see them bellow:

  • −h, −−help Print short help message and exit
  • −V, −−version Print version info and exit
  • −o, −−output file.swf will Go into a seperate file.
  • −p, −−pages range Ex:3-5,10-12
  • −P, −−password password Use password for deciphering the pdf.
  • −v, −−verbose Be verbose. Use more than one -v for greater effect.
  • −z, −−zlib The resulting SWF will not be playable in browsers with Flash Plugins 5 and below!
  • −i, −−ignore SWF files a little bit smaller, but it may also cause the images in the pdf to look funny.
  • −j, −−jpegquality quality Set quality of embedded jpeg pictures to quality. 0 is worst (small), 100 is best (big). (default:85)
  • −s, −−set param=value Set a SWF encoder specific parameter. See pdf2swf -s help for more information.
  • −w, −−samewindow When clicked on, the page they point to will be opened in the window the SWF is displayed.
  • −t, −−stop The resulting SWF file will not turn pages automatically.
  • −T, −−flashversion num Set Flash Version in the SWF header to num.
  • −F, −−fontdir directory Add directory to the font search path.
  • −b, −−defaultviewer Therefore the swf file will be “browseable”, i.e. display some buttons for turning pages.
    The viewer swf to be used is determined by a symlink named “default_viewer.swf” in
    the swftools data directory.
  • −l, −−defaultloader The loader swf to be used is determined by a symlink named “default_loader.swf” in
    the swftools data directory.
  • −B, −−viewer filename See http://www.quiss.org/swftools/pdf2swf_usage.html for information on how to create your own viewers.
  • −L, −−preloader filename filename is an arbitrary swf animation.
  • −q, −−quiet Suppress normal messages. Use -qq to suppress warnings, also.
  • −S, −−shapes Don’t use SWF Fonts, but store everything as shape.
  • −f, −−fonts Store full fonts in SWF. (Don’t reduce to used characters).
  • −G, −−flatten This usually makes the file faster to render and also usually smaller, but will increase
    conversion time.
  • −I, −−info Don’t do actual conversion, just display a list of all pages in the PDF.
  • −Q, −−maxtime n Abort conversion after n seconds. Only available on Unix.

Converting in the right way

The creators of SWFTools claim that you can export in AVM2, but in fact the Flash Player only recognize the header in the swf, not the document structure, which for Flex DOM is fundamental to understand.

Ok, How I convert mine with options?

I used ANT to do stuff things for conventions since I don’t want to re-type always I have a new PDF to convert in house. But simplifying it worked for me this command line argument.

C:\SWFTOOLS>pdf2swf -z -t sourceFile.pdf -o OutputFile.swf

That’s right, you have your swf file converted and running, What was done? I insert a stop action in each frame because this cause the swf to play each frame. Also I compacted the file using gzip to decrease the size, same as Scribd does.

Flex side

Create a new Flex project, name it as you wish. After that you might be think it’s simple we can load it using SWFLoader, but you will have problems to control and Flex will understand that this file is just as asset not as a component. To work with that, you have various options like, Loader, ByteLoader, ModuleLoader and BulkLoader. To load into Flex and given you a certain to control it.

My solution was simple, as I known that pdf2swf just give me swf in head with 8 version, I can manage a instance and place where I wish. That was easy, but what about Flex to control from Flash 5,6,7,8, both have their own way of render and work. To accomplished that I googled a little, because I knew it that some one should have fight this problem before and for lucky I found this class that kick ass problem. See class bellow:

package
{
	import flash.display.Loader;
	import flash.net.URLRequest;
	import flash.net.URLStream;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.Event;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	import flash.errors.EOFError; 

	public class ForcibleLoader
	{
		public function ForcibleLoader(loader:Loader)
		{
			this.loader = loader;
			_stream = new URLStream();
			_stream.addEventListener(Event.COMPLETE, completeHandler);
			_stream.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
			_stream.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
		}
		private var _loader:Loader;
		public var _stream:URLStream;
		public function get loader():Loader
		{
			return _loader;
		}
		public function set loader(value:Loader):void
		{
			_loader = value;
		}
		public function load(request:URLRequest):void
		{
			_stream.load(request);
		}
		private function completeHandler(event:Event):void
		{
			var inputBytes:ByteArray = new ByteArray();
			_stream.readBytes(inputBytes);
			_stream.close();
			inputBytes.endian = Endian.LITTLE_ENDIAN;
			if (isCompressed(inputBytes)) {
				uncompress(inputBytes);
			}
			var version:uint = uint(inputBytes[3]);
			if (version <= 10) {
				if (version == 8 || version == 9 || version == 10){
					flagSWF9Bit(inputBytes);
				}
				else if (version <= 7) {
					insertFileAttributesTag(inputBytes);
				}
				updateVersion(inputBytes, 9);
			}
			loader.loadBytes(inputBytes);
		}
		private function isCompressed(bytes:ByteArray):Boolean
		{
			return bytes[0] == 0x43;
		}
		private function uncompress(bytes:ByteArray):void
		{
			var cBytes:ByteArray = new ByteArray();
			cBytes.writeBytes(bytes, 8);
			bytes.length = 8;
			bytes.position = 8;
			cBytes.uncompress();
			bytes.writeBytes(cBytes);
			bytes[0] = 0x46;
			cBytes.length = 0;
		}
		private function getBodyPosition(bytes:ByteArray):uint
		{
			var result:uint = 0;
			result += 3; // FWS/CWS
			result += 1; // version(byte)
			result += 4; // length(32bit-uint)
			var rectNBits:uint = bytes[result] >>> 3;
			result += (5 + rectNBits * 4) / 8; // stage(rect)
			result += 2;
			result += 1; // frameRate(byte)
			result += 2; // totalFrames(16bit-uint)
			return result;
		}
		private function findFileAttributesPosition(offset:uint, bytes:ByteArray):uint
		{
			bytes.position = offset;
			try {
				for (;;) {
					var byte:uint = bytes.readShort();
					var tag:uint = byte >>> 6;
					if (tag == 69) {
						return bytes.position - 2;
					}
					var length:uint = byte & 0x3f;
					if (length == 0x3f) {
						length = bytes.readInt();
					}
					bytes.position += length;
				}
			}
			catch (e:EOFError) {
			}
			return NaN;
		}
		private function flagSWF9Bit(bytes:ByteArray):void
		{
			var pos:uint = findFileAttributesPosition(getBodyPosition(bytes), bytes);
			if (!isNaN(pos)) {
				bytes[pos + 2] |= 0x08;
			}
		}
		private function insertFileAttributesTag(bytes:ByteArray):void
		{
			var pos:uint = getBodyPosition(bytes);
			var afterBytes:ByteArray = new ByteArray();
			afterBytes.writeBytes(bytes, pos);
			bytes.length = pos;
			bytes.position = pos;
			bytes.writeByte(0x44);
			bytes.writeByte(0x11);
			bytes.writeByte(0x08);
			bytes.writeByte(0x00);
			bytes.writeByte(0x00);
			bytes.writeByte(0x00);
			bytes.writeBytes(afterBytes);
			afterBytes.length = 0;
		}
		private function updateVersion(bytes:ByteArray, version:uint):void
		{
			bytes[3] = version;
		}
		private function ioErrorHandler(event:IOErrorEvent):void
		{
			loader.contentLoaderInfo.dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR));
		}
		private function securityErrorHandler(event:SecurityErrorEvent):void
		{
			loader.contentLoaderInfo.dispatchEvent(new SecurityErrorEvent(SecurityErrorEvent.SECURITY_ERROR));
		}
	}
}

With this face off, you can handle quickly in Flex, I’ve built an application example. And for your own risk you can implement, share more functionalities, more controls, anyaway, you’re free for it.

Here’s the Main application.





		[Event(name="PDFComplete",type="flash.events.Event")]


	
		
	
	
			
			
			
				
			
			

You see, I didn’t used the SWFLoader of Flex, as explained before, I prefer to handle in diffrent way.
This application is simple, has some buggies (littles), but in general, just figure you out how to do such thing.

Missing things you could implement, TextSearch, Thumbnail generation from loaded swf to pages.

Download the FULL source code of this application here. Wanna see example of running, you have to download and it’s included. Because I didn’t put effort in secury sandbox levels in it.

Links of my researches:

17 Comments

  1. Jerry Case
    Posted February 11, 2009 at 8:03 pm | Permalink

    Igor,

    thanks a ton, this was just the thing I was googling for! Swftools’s pdf2swf and your browser is an excellent replacement for Adobe FlashPaper!

  2. Posted February 12, 2009 at 12:55 pm | Permalink

    Hi,
    ForcibleLoader is not required in this case as, the latest swftools does have inbuilt support for exporting the swf into flash player 9 version. And, regarding the text selection process, textSnapShot is having a bug (lately reported) http://bugs.adobe.com/jira/browse/SDK-15295?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel

    It requires more votes, to get solved. That prevents from selecting the text as per user requirement.

    For Thumnail, again we can use the swftools to split the multiframe swf into singleframe swfs.

    Regards,
    Devaraj

  3. Olivier
    Posted March 11, 2009 at 10:13 am | Permalink

    Thanks Igor for your article which brings lots of perspectives.

    There is still a problem I cannot solve and maybe you can help me get on the way.

    The loader.contentLoaderInfo never fires the “complete” event when loading a single page pdf / single frame swf
    any clue ?

  4. Posted October 10, 2009 at 7:37 pm | Permalink

    It is stable, in fact I have not experienced any bugs . ,

  5. Antonio
    Posted November 13, 2009 at 10:19 am | Permalink

    Hi Igor, thanks for this material, i would like to know how can i put the function to select a text, can you pass some link explain this?

    thanks

  6. Posted November 15, 2009 at 11:12 pm | Permalink

    Hi Igor,
    Thank you for your great work of solve loading the pdf’s swf file. After learning and running your programn,I find a small bug exists in face control. The bug is that you can’t switch the last two frames from each other correctly.The currentFrame property of MovieClip can’t equal with this MovieClip.totalFrames forever. Of course maybe it’s Flash bug。I spent much time in removing this bug.Last i used a skill avoiding the bug.
    what you need do is add “Application.application.libMC.gotoAndStop(e.currentTarget.pageNumber-2);” into the first line of function dispatchPage of Pages.mxml . Such as:
    private function dispatchPage(e:MouseEvent):void {
    //此处用到小技巧,解决最后两页切换的无法转换的问题
    Application.application.libMC.gotoAndStop(e.currentTarget.pageNumber-2);
    Application.application.libMC.gotoAndStop(e.currentTarget.pageNumber);
    }
    Maybe you can make your work more perfect!Thank you for you prework!

  7. Mayuresh
    Posted November 18, 2009 at 9:30 am | Permalink

    Hi,
    I am also using this project …. But it has some bugs and I am not able to fix them. Please help.
    The bug is that this project does not display the swf file which has only one page/frame. Also that, it never goes to the last pageof the file. I will post the bug in detail after you reply.

    I am waiting for your reply… Thank you…

  8. Posted January 9, 2010 at 6:50 pm | Permalink

    Thanks again for providing some insights on the loading part. Part of this solution is used in the open source project FlexPaper:

    http://www.devaldi.com/?page_id=260

  9. Aguilar
    Posted January 24, 2010 at 12:00 pm | Permalink

    Hi Igor, thanks for this project, i implemented some other things in this, you can see here
    http://www.iepec.com/leitorPDF/&idCurso=19
    if you want i can share the code, thanks

  10. Posted January 24, 2010 at 6:29 pm | Permalink

    Great implementation. Did you own the code for that? Or did you use other source code involved? Liked it.

  11. Ana
    Posted March 9, 2010 at 3:15 pm | Permalink

    Thanks Igor for this nice project.

    Aguilar, your implementation is very very nice. Of course it would be great if you can share the code. Thanks a lot.

  12. wangwenke
    Posted May 23, 2010 at 11:39 am | Permalink

    can you make a flashbased document reader for me,please contact to me, i can pay for it.

  13. Posted August 23, 2010 at 7:02 am | Permalink

    hey i am trying to added a progress bar on this code and the progress bar is appearing but the bar is not moving from zero thanks

  14. Mahendran
    Posted March 8, 2011 at 1:40 am | Permalink

    hi. this pdf2swf is not converting pdf files which has whitespace in file name. what i’ve to do?

  15. aaron
    Posted December 22, 2011 at 8:04 pm | Permalink

    anyone can provide a print function of selected page and page range. i really want to know. thanks

  16. Veronica
    Posted September 26, 2012 at 11:31 am | Permalink

    Hey Igor, do you have any solutions for files that has just one frame? Flexpaper doesnt load them.

    Thank you.

  17. Posted November 14, 2012 at 6:16 pm | Permalink

    No I don’t. Sorry for not be helpful.

2 Trackbacks

  1. [...] SWFTools (pdf2swf) to properly work with Flex (from Igor Costa) [...]

  2. [...] I thought that I might be able to add some value here. Special thanks to Igor Costa for providing a good example on loading the swf’s [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*