3 Replies Latest reply on May 18, 2006 7:34 AM by jordan brough

    Converting Flex Graphs to PDF/JPEG

    jordan brough
      We'd love to use Flex in our application. However, we would need a way to convert Flash components (or an entire SWF) to a PDF/JPEG.

      We've created a Flex application that allows users to create their own charts and we will even have the ability to generate a simple SWF file for each chart (using the command line compiler).

      Is there a way (or any ideas about a possible way) to do *any* of these things? --
      - Convert a static SWF file to PDF
      - Convert a static SWF file to JPEG/PNG/TIF/ETC
      - Grab a 'screenshot' of a Flex Component
      - Anything else that would do the job

      I've looked around for a product that would do any of the above, but I can't find anything that could be accessed programmatically (i.e. called via a script).
        • 1. Re: Converting Flex Graphs to PDF/JPEG
          Level 7
          The answer is yes. Here is a thread that should answer your question. I
          updated the PNGEncoder.as to compile with Beta3. However, I have not tested
          that it works in Beta3.

          Original Question:
          Specifically we need to export a bitmap (in any format, preferably PNG, but
          jpg or GIF will do) from the application. These bitmaps should be pixel
          perfect replicas of chart controls within the application. We were
          originally told that this was not possible in Flex 1.5. It appears however
          that in Flex 2.0, the BitmapData class of the Flash 8 player is now exposed,
          and with a little research it seems like we should be able to use it to
          access a Flex chart, pixel by pixel and send the data back to the server for
          rendering as an image file.

          So I have a couple questions:

          1.. Is the approach I have outlined above workable?
          2.. Does this approach require Flex 2.0?
          3.. Is there a better way of exporting a bitmap image of a Flex control?

          Response:

          1) You don't need to pull the data pixel by pixel. You can create a
          BitmapData, draw() the chart into the bitmap, and ask for its bits as a
          bytearray.

          2) Your best bet is to compress the bitmapData into a PNG and send that to
          the server. The server does nothing but turn around and send it right back
          in the response with the appropriate headers to trigger the browser to pop
          up a save dialog.

          3) I've attached some prototype code I wrote a while back to turn a Bitmap
          into a PNG. It was written against a pre-alpha build, so it will need some
          work. It's also not fully functional I think. Specifically, I know that when
          the size of the image crosses a boundary you need to split it up into chunks
          as you write it out into the file, which this code isn't doing. THere may be
          other problems too.

          4) Yes, this only works in Flex 2.


          PNGEncoder.as:



          package {

          import flash.display.*;
          import flash.geom.*;
          import flash.utils.*;
          import flash.net.*;

          public class PNGEncoder {


          private var _png:ByteArray;

          public function encode(img:BitmapData):ByteArray
          {
          var imgWidth:uint = img.width;
          var imgHeight:uint = img.height;

          var imgData:ByteArray = img.getPixels(new
          Rectangle(0,0,imgWidth,imgHeight));

          _png = new ByteArray();

          _png.writeByte(137);
          _png.writeByte(80);
          _png.writeByte(78);
          _png.writeByte(71);
          _png.writeByte(13);
          _png.writeByte(10);
          _png.writeByte(26);
          _png.writeByte(10);

          var IHDR:ByteArray = new ByteArray();
          IHDR.writeInt(imgWidth);
          IHDR.writeInt(imgHeight);
          IHDR.writeByte(8); // color depth: 8 bpp
          IHDR.writeByte(6); // color type: RGBA
          IHDR.writeByte(0); // compression: ZLIB
          IHDR.writeByte(0); // filter method
          IHDR.writeByte(0); // not interlaced;

          writeChunk([0x49,0x48,0x44,0x52],IHDR);

          var IDAT:ByteArray= new ByteArray();
          for(var i:uint=0;i<imgHeight;i++) {
          IDAT.writeByte(0);
          for(var j:uint=0;j<imgWidth;j++) {
          var p:uint = img.getPixel32(j,i);
          IDAT.writeByte((p>>16)&0xFF);
          IDAT.writeByte((p>> 8)&0xFF);
          IDAT.writeByte((p )&0xFF);
          IDAT.writeByte((p>>24)&0xFF);
          }
          }

          IDAT.compress();
          writeChunk([0x49,0x44,0x41,0x54],IDAT);



          writeChunk([0x49,0x45,0x4E,0x44],null);
          return _png;
          }

          public function dump():String
          {
          _png.position = 0;
          var out:String ="";
          for(var i:uint=0;i<_png.length;i++) {
          var code:String = "0123456789abcdef";
          var v:uint = _png.readUnsignedByte();
          out += code.charAt((v & 0xF0) >> 4);
          out += code.charAt(v & 0xF);
          out += " ";
          }
          return out;
          }
          private function writeChunk(type:Array,data:ByteArray):void
          {
          var len:uint = 0;
          if(data != null)
          len = data.length; // data length
          _png.writeUnsignedInt(len);

          var p:uint = _png.position;

          _png.writeByte(type[0]);
          _png.writeByte(type[1]);
          _png.writeByte(type[2]);
          _png.writeByte(type[3]);
          if(data != null)
          _png.writeBytes(data);

          var endP:uint = _png.position;
          _png.position = p;
          var c:uint = crc(_png,endP-p);
          _png.position = endP;
          _png.writeUnsignedInt(c);
          }

          /* Table of CRCs of all 8-bit messages. */
          private static var crc_table:Array;

          /* Flag: has the table been computed? Initially false. */
          private static var crc_table_computed:Boolean = false;

          /* Make the table for a fast CRC. */
          private function make_crc_table():void
          {
          var c:uint;
          var n:int;
          var k:int;

          crc_table = [];

          for (n = 0; n < 256; n++) {
          c = n;
          for (k = 0; k < 8; k++) {
          if (c & 1)
          c = uint(uint(0xedb88320) ^ uint(c >>> 1));
          else
          c = uint(c >>> 1);
          }
          crc_table[n] = c;
          }
          crc_table_computed = true;
          }

          /* Update a running CRC with the bytes buf[0..len-1]--the CRC
          should be initialized to all 1's, and the transmitted value
          is the 1's complement of the final running CRC (see the
          crc() routine below)). */

          private function update_crc(crc:uint, buf:ByteArray,
          len:uint):uint
          {
          var c:uint = crc;
          var n:int;
          var v:uint;

          if (!crc_table_computed)
          make_crc_table();
          for (n = 0; n < len; n++) {
          v = buf.readUnsignedByte();
          c = uint(crc_table[(c ^ v) & uint(0xff)] ^ uint(c >>> 8));
          }
          return c;
          }

          /* Return the CRC of the bytes buf[0..len-1]. */
          private function crc(buf:ByteArray, len:uint):uint
          {
          var cc:uint = update_crc(uint(0xffffffff), buf, len);
          return uint(cc ^ uint(0xffffffff));
          }

          }
          }


          --
          Jason Szeto
          Adobe Flex SDK Developer


          "jeb1138" <webforumsuser@macromedia.com> wrote in message
          news:e42jbv$ahv$1@forums.macromedia.com...
          > We'd love to use Flex in our application. However, we would need a way to
          > convert some resulting Flash components (or an entire SWF) to a PDF/JPEG.
          >
          > We've created a Flex application that allows users to create their own
          > charts
          > and we will even have the ability to generate a simple SWF file for each
          > chart
          > (using the command line compiler).
          >
          > Is there a way (or any ideas about a possible way) to do *any* of these
          > things? --
          > - Convert a static SWF file to PDF
          > - Convert a static SWF file to JPEG/PNG/TIF/ETC
          > - Grab a 'screenshot' of a Flex Component
          > - Anything else that would do the job
          >
          > I've looked around for a product that would do any of the above, but I
          > can't
          > find anything that could be accessed programmatically (i.e. called via a
          > script).
          >



          • 2. Re: Converting Flex Graphs to PDF/JPEG
            ElectricGrandpa
            Hi jeb1136,

            I was looking for the same thing recently, and I came upon this blog entry: http://www.envrac.org/index.php/2005/11/21/34-compression-png-as3-tuerie

            The blog is in French, but the code is in English. It has both the png encode code, as well as the PHP code to turn the data into an image that can be manipulated by GD(saved to server, etc). The only thing is that the code hasn't been updated for Beta 3, but that shouldn't be too much of a problem.

            -Matt Rix
            • 3. Converting Flex Graphs to PDF/JPEG
              jordan brough Level 1
              Thank you both of you! That's exactly what we were looking for. I'm trying it out right now and so far it's looking good. Flex is going to be incredible for us -- this is going to make our development cycle so much shorter.

              I wish there were a way to avoid the cost of sending the graphic back to the server and having the server then send it back. However, this is still very workable, especially with the built-in PNG conversion capabilities. Has Adobe considered adding PDF conversion utilities (to preserve selectable text & etc.)?

              I can't wait until the final version is released so that we can buy it and get rid of that crazy "Flex Charting Trial" watermark on the graphs. It's much harder to sell executives on a product/process when the demos have ugly watermarks all over, especially since the watermark doesn't scale and our one-inch chart thumbnails each have four-inch watermarks.

              In any case, this is exactly what I needed to know. Thanks again.