Cut Image into Squares (copyPixels)

Actionscript:
  1. [SWF(width=650, height=650)]
  2. var loader:Loader = new Loader();
  3. loader.load(new URLRequest("http://actionsnippet.com/wp-content/chair.jpg"));
  4. loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded);
  5.  
  6. var w:Number;
  7. var h:Number;
  8. var rows:Number = 20;
  9. var cols:Number = 20;
  10. var tiles:Vector.<BitmapData> = new Vector.<BitmapData>();
  11. var locX:Vector.<Number> = new Vector.<Number>();
  12. var locY:Vector.<Number> = new Vector.<Number>();
  13. var rX:Vector.<Number> = new Vector.<Number>();
  14. var rY:Vector.<Number> = new Vector.<Number>();
  15. var sX:Vector.<Number> = new Vector.<Number>();
  16. var sY:Vector.<Number> = new Vector.<Number>();
  17. function onLoaded(evt:Event):void{
  18.     w = evt.target.width;
  19.     h = evt.target.height;
  20.     var image:BitmapData = Bitmap(evt.target.content).bitmapData;
  21.     var tileWidth:Number = w / cols;
  22.     var tileHeight:Number = h / rows;
  23.     var inc:int = 0;
  24.     var pnt:Point = new Point();
  25.     var rect:Rectangle = new Rectangle(0,0,tileWidth,tileHeight);
  26.     for (var i:int = 0; i<rows; i++){
  27.         for (var j:int = 0; j<cols; j ++){
  28.              var currTile:BitmapData= new BitmapData(tileWidth, tileHeight, true, 0x00000000);
  29.              rect.x = j * tileWidth;
  30.              rect.y = i * tileHeight;
  31.              currTile.copyPixels(image, rect, pnt, null, null, true);
  32.              tiles[inc] = currTile;
  33.              rect.x += 25;
  34.              rect.y += 25;
  35.              sX[inc] = rect.x;
  36.              sY[inc] = rect.y;
  37.              locX[inc] = rX[inc] = -rect.width * 2
  38.              locY[inc] = rY[inc] =  Math.random() * stage.stageHeight;
  39.              setTimeout(startAnimation, inc *4 + 100, inc, rect.x, rect.y);
  40.              inc++;
  41.         }
  42.     }
  43. }
  44.  
  45. function startAnimation(index:int, dx:Number, dy:Number):void{
  46.     var interval:Number;
  47.     var animate:Function = function(index:int):void{
  48.         locX[index] += (dx - locX[index]) / 4;
  49.         locY[index] += (dy - locY[index]) / 4;
  50.         if (Math.abs(locX[index] - dx) <1 && Math.abs(locY[index] - dy)<1){
  51.             locX[index] = dx;
  52.             locY[index] = dy;
  53.             clearInterval(interval);
  54.         }
  55.     }
  56.    interval = setInterval(animate, 32, index);
  57. }
  58.  
  59. var canvas:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false, 0xFFFFFF);
  60. addChild(new Bitmap(canvas));
  61.  
  62. var loc:Point = new Point();
  63. addEventListener(Event.ENTER_FRAME, onLoop);
  64. function onLoop(evt:Event):void {
  65.       canvas.fillRect(canvas.rect, 0xFFFFFF);
  66.       for (var i:int = 0; i<tiles.length; i++){
  67.             var tile:BitmapData= tiles[i];
  68.             loc.x = locX[i];
  69.             loc.y = locY[i];
  70.             canvas.copyPixels(tile, tile.rect, loc, null, null, true);
  71.       }
  72. }

This snippet cuts a dynamically loaded image into a series of smaller BitmapData instances. These BitmapData instances are then drawn to a canvas BitmapData using copyPixels. The BitmapData.copyPixels() method is extremely fast - so this has some advantages over yesterdays post (which did basically the same thing with Sprites). I used setInterval and setTimeout to do a simple demo animation, but I recommend using TweenLite on a real project.

This entry was posted in BitmapData, Vector and tagged , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

9 Comments

  1. Posted July 15, 2009 at 12:25 am | Permalink

    copyPixel is fast, but the fastest way to put pixels into the image is the setVector method.

    try this in the loop function

    function onLoop(evt:Event):void {
    canvas.fillRect(canvas.rect, 0xFFFFFF);
    var destRect:Rectangle;
    for (var i:int = 0; i<tiles.length; i++){
    var tile:BitmapData= tiles[i];
    destRect = tile.rect.clone();
    loc.x = destRect.x = locX[i];
    loc.y = destRect.y = locY[i];
    canvas.setVector(destRect,tile.getVector(tile.rect));
    }
    }

  2. Posted July 15, 2009 at 3:33 am | Permalink

    Did you do a speed test on that… I get a max of 12 ms with setVector() and a max of 3 ms with copyPixels()… also, tile.rect.clone() in the for loop isn’t necessary. Can you post a speed test?

    I’m a bit busy today, but later on I’ll try a slightly different approach to using setVector() and compare the results… :)

  3. Posted July 15, 2009 at 1:18 pm | Permalink

    Saw your blogpost…cool stuff… but you put the speed test in the wrong place… putting the speed test in the correct place reveals that there isn’t much of a difference….

    Here are demo fla files you can use to compare speeds and see what I mean about correct speed test…
    http://actionsnippet.com/source/setVector.fla
    http://actionsnippet.com/source/copyPixels.fla

    Let me know what results you get… maybe it varies from computer to computer… on my machine both seems to run at about 25 - 30 ms (I upped the number of tiles).

    Nice work :) I wouldn’t have thought to use setVector() as a replacement for copyPixels.

    I think it makes sense to write a snippet specifically targeted at testing the speed of copyPixels vs setVector… I’ll try that in the near future….

  4. Posted July 15, 2009 at 1:19 pm | Permalink

    yes, you’re right, rect.clone is unnecessary on that loop.
    i did some more accurate speed tests here you can find here on my blog http://www.flashfuck.it/2009/07/15/bitmapdata-manipulation-benchmark/
    i tried out some ways to get the same example you did here and here’s the results is
    get\setvector is the fastest way, followed by get\setPixels, copyPixels is only third in this chart, and the slowest one is bitmapdata.merge.

    i’m running these tests on a mbp, waiting for someone to benchmark on windows

  5. Posted July 15, 2009 at 1:20 pm | Permalink

    just saw your comment here…i was updating the code on the post -.-’ cool synchronized coding! :D

  6. Posted July 15, 2009 at 1:32 pm | Permalink

    heh nice… what kind of results to you get if you up the rows and cols vars?

    for me setVector and copyPixels seems to be giving almost exactly the same speed results….

  7. Posted July 15, 2009 at 2:08 pm | Permalink

    just tried with 50×50 with every tests and each of them crashed before finishing the task, i think we’d better to use some tween engine instead of setinterval (which i suppose to be the crasher)…

  8. Posted July 15, 2009 at 2:12 pm | Permalink

    yeah … I think the best thing to do is use a different snippet, specifically designed to test this… weird that it crashes at 50×50.. I did 100×100 and it worked fine … on a macbook pro laptop 2.4 duo

  9. Posted July 16, 2009 at 12:30 pm | Permalink

    hey Piergiorgio… if you have a minute check out this post and let me know what results you get… or if you would change anything about the setVector() implementation to improve speed…

One Trackback

  1. By BitmapData manipulation benchmark | FlashFuck.it on July 15, 2009 at 12:54 pm

    [...] I encountered this blog post from Zevan (which blog is REALLY a good daily reading I suggest everyone to take) about bitmapData merging and [...]

Post a Comment

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

*
*