Jul 14, 2009

format.jpg.Writer finished!

I’ve finally completed the JPEG Writer for the hxformat library. After the initial port from an “optimized” as3 JPG Encoder class it was a lot of time spent in comparing the output from the format.jpg.Writer to the as3 results.

The biggest challenge I guess was that, since the hxformat library is aiming to be cross target (i.e. should be usable in neko, php, FP10, FP8, javascript and cpp), I could not just port it straight up as I couldn’t rely on the flash specific bitmapData.getPixel methods etc. Instead I’ve kept the target specific code inside a format.jpg.Tools class, so to use the library in a SWF target it would look like this:

var o = new haxe.io.BytesOutput();
var w = new format.jpg.Writer( o );
w.write( format.jpg.Tools.fromBitmapData( bmp ) );
// Now we have a jpg stream in "o".

And similarly (assuming we’ve made a javascript friendly format.jpg.Tools already, which I haven’t yet) it would look like this in a JS target:

var o = new haxe.io.BytesOutput();
var w = new format.jpg.Writer( o );
w.write( format.jpg.Tools.fromCanvas( js.Lib.document.getElementById( "image" ) ) );
// Now we have a jpg stream in "o".

The idea is that the format.jpg.Tools.from* methods should create a format.jpg.Data typedef which then may be passed into the format.jpg.Writer#write method.

Creating that typedef could off course also be done manually, but I’m a fan of convenience methods :) And also, the methods should off course be optimized for the target, so in a FP8 target we’d use a loop with bmp.getPixel to extract the pixel stream, while in FP9+ we just use bmp.getPixels instead.

I also did a version using linked lists instead of Arrays (or Vectors if it’s FP10), but I didn’t see a bit improvement and it was a lot messier so I decided to keep the Array version.

I’m hoping someone could help me optimize it even further, maybe using the flash.Memory feature of FP10 or some other clever optimizations. I’m currently down to about 6 seconds on my brand new Macbook Pro on a 2880x2880 px image, the same one as used in the optimized version at ByteArray.org, which takes about 3.5 seconds(!). I really hope we can make the hxformat version comparable, if not even faster, in the end. I’ve given it my best so far, getting it down from a timeout (>15 seconds) to 6 seconds.

I was stuck for a while when the finished image did not look at all like the original, it was black almost entirely. The problem was, I realized after way to many attempts, that the source image was transparent (mostly) and transparent pixels was converted to black ones, DOH!

So, you can find the source code here, I haven’t added any tests for it in the library though, but the lines above should be enough to get started :) It’s the exact same syntax if you want to try out the PNG or BMP Writer/Reader, except another package.

If you want to help out you can either:

  • Try it out with different images and see if it gives proper results, and if you can open it in your favorite application.
  • Make it faster! Find anywhere that we can optimize?
  • Write “tools” for javascript/canvas and other targets, although the neash project might make the current fromBitmapData work for most targets already?
  • I’m pondering the possibility to use the previous format.tools.Huffman class to compute those huffman tables instead and wouldn’t mind some input on that.
  • Get your hands real dirty and write the format.jpg.Reader class ;) Perhaps the tables used in the format.jpg.Writer should be extracted to be used in the Reader as well?
  • Another thing I’m planning to add to the image formats (especially jpg as it’s so slow) is asynchronous writing. This would probably not be used in targets like neko or cpp, what do you think?
Comment
About
developing software is fun.
sitting in a pleasant sofa is fun.
combine for double the fun.
Search