Processing BitmapData.getPixels() With PHP

Have you ever worked with BitmapData.getPixels() method? This method generates a byte array from a rectangular region of pixel data. Writes an unsigned integer (a 32-bit unmultiplied pixel value) for each pixel into the byte array. Thats sounds good, but what is it good for to have a ByteArray full of integers? There is not even a decoder for this format on my backend?!… Well, this format is so cool, and easy to access that you do are able to write your own decoder e.g. in PHP.

The resulting bytes are 32-bit unsigned integers for each pixel represented by AARRGGBB format, followed by another pixels and so on e.g.:

AA RR GG BB:
-- -- -- --
FF FF 00 00
00 00 FF 00

First pixel is full opaque red color, second pixel is full transparent green color. That sounds good enough to use with imagesetpixel(), that requires color in almost identic format, however PHP GD library recognizes alpha values from 0 to 127 in reversed logic (127 full transparent, 0 full opaque). So we only need to change the alpha value and we are good to go:

AA -> AA (php)
--    --
FF -> 00
00 -> 7F

What are we going to do is:

  • this format does not know about width and height of image, we have to define it manualy
  • access pixels (unsigned integers) from byte array (unpack() is the fastest method for this in PHP i guess)
  • iterate over each pixel / color
  • get color value and transform to PHP alpha logic
    • $color>>24 returns alpha value (0-255), what we need is to divide it by two (0-127 for php) so $color>>25 works fine
    • inversed logic requires values to be changed from 0-127 to 127-0: 0x7f-AA
    • shift alpha value back to its correct position AA<<24
    • add original RRGGBB values to our new alpha AA|($color&0xffffff)
  • pass transformed color value into imagesetpixel() with correct x, y coordinate

This process should return correct image identifier. Lets have a new PHP function imagecreatefrombmdstring()

<?php
function imagecreatefrombmdstring($bytes, $width, $height)
{
	$img=imagecreatetruecolor($width, $height);
	imagealphablending($img, false);
	imagesavealpha($img, true);
	
	$x=0;
	$y=0;
	$colors=unpack("N*", $bytes);
	foreach($colors as $color)
	{
		imagesetpixel($img, $x, $y, (0x7f-($color>>25)<<24)|($color&0xffffff));
		if(++$x==$width)
		{
			$x=0;
			$y++;
		}
	}
	return $img;
}

The ActionScript code may look something like this, this method is in fact very fast on client side:

var bitmapData:BitmapData = ...
var bytes:Bytes=bitmapData.getPixels(bitmapData.rect);
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest();
request.url = "our.php";
request.contentType = "application/octet-stream";
request.method = URLRequestMethod.POST;
request.data = bytes;
loader.load(request);

To optimize it even more, use ByteArray.compress() to compress bytes before sending, now you should get binary request not much bigger than length of the same request containing PNG encoded image bytes. On PHP side use gzuncompress() to get raw bytes.

Why did I developer/used this method of sending image to server? Well, I was not able to find fast enought/asynchronous PNG encoder. By using this technique, I was able to scale the getPixels+compress process into multiple frames (asynchronously) in order to create smooth upload process (using MultipartURLLoader).

5 comments so far

  1. vic February 24, 2011 17:30

    interesting post!
    is it possible to use your example to send an image as an email attachment? (without saving it to a webserver first)
    that would be awesome. please let me know.

  2. Jozef Chúťka February 24, 2011 17:40

    @vic, I believe you need server side to send emails. Now there are a few ways how to do it:
    1. you can use mailto: (pseudo protocol) to dispatch your system native email client with a content defined within the URLRequest … http://www.murtensaerbi.be/blog/index.php/tag/urlrequest/

    2. you can use your server side layer to send the email … like your custom mail.php script.

    3. you can follow email specification and make the socket request by yourself (?) I believe this should be possible…

    now what is you want to do?

  3. vic February 26, 2011 02:36

    thanks for your response.

    No. 2 is it.
    I’ld like to call a PHP and attach the image dynamically. (without saving it to a webserver first)

    You think it’s possible?

  4. Jozef Chúťka February 26, 2011 22:02

    @vic, yes this is definitely possible. You can send your image bytes (as shown in code) plus any other required params in one request that is also sending an email from php file. I would prefer using MultipartURLLoader class ( http://code.google.com/p/in-spirit/wiki/MultipartURLLoader ) for this. Then on a backend side transcode the image bytes into mail request. The easiest way to do that is to use some mail library or you can study protocol and make your own custom solution, you should ask on php forum for a help

  5. shammi August 3, 2011 21:17

    i cant believe you have solutions to everything i need. we need this one one of our project here image sequence are send to the server and video is generated. i was trying asynchronous jpeg encoder but the end user had to wait for a very long time. this should work thanks

Leave a comment

Please be polite and on topic. Your e-mail will never be published.