5

I've got a large (4096x4096) image loaded into memory, but when I try to use addChild, there is a long delay before it actually gets drawn to the screen. This is expected. However, is there an event I can listen for to know the moment that the DisplayObject (a .png image) is actually drawn to the screen?

I am trying to load the images onto the screen, then do something after they are actually drawn.

producerism
  • 344
  • 4
  • 17
  • 2
    So far my workaround has been to run a timer at 100ms that constantly checks to see the width of the DisplayObject. Once the number is greater than 0, I know it's finally been drawn to the screen. – producerism Jan 08 '13 at 21:37
  • 3
    Does `Event.ADDED_TO_STAGE` work? Or does that dispatch directly after it's been added only, before it's actually rendered? – puggsoy Jan 08 '13 at 21:45
  • Are you loading the image externally or is this image compiled in the swf? – Tim Lieberman Jan 08 '13 at 21:47
  • You may want to try. if ( youImgName.framesLoaded ) {} – Tim Lieberman Jan 08 '13 at 21:50
  • 1
    Along with Added_To_Stage (if that's too early) you may want to check out the RENDER event. Certainly if you just need to be able to manipulate the bitmapData you can use the COMPLETE event from the Loader (if it's loaded at run-time as opposed to embedded). – shaunhusain Jan 08 '13 at 22:01
  • unfortunately, ADDED_TO_STAGE and RENDER events do not help. They are both called when the DisplayObject is added to the stage, but this is still at least 3-5 seconds before the data is actually drawn to the screen. I'm loading in external images (PNG and GIF) which range from 10-60 MB each. – producerism Jan 08 '13 at 22:24
  • @puggsoy, unfortunately ADDED_TO_STAGE dispatches after it's added, not after it's rendered. As for checking against framesLoaded, that would only be useful for a SWF or movieclip, not a Bitmap. Appreciate the advice so far, this seems like a fringe-case issue. – producerism Jan 10 '13 at 23:02
  • 1
    Ah, OK then. Thought it might be worth a shot. As far as I know then your solution in the first comment is probably as good as it'll get, but perhaps checking it on every new frame using the `ENTER_FRAME` instead of every 100ms might be better. I don't know much about optimization, but since your checking for when it's rendered then it might be more efficient to check each frame. – puggsoy Jan 11 '13 at 12:49
  • Thanks, that's a good point to consider. I'm cautious about adding unnecessary logic to every frame, since that could potentially make it take even longer to display the pixels, but it's all theoretical until I find a solution without a workaround. – producerism Jan 11 '13 at 17:03
  • My suspicion is that rather than adding a very large image to the display list, what you would benefit more from is copying only the pixels you want from the 10MP image(s) into a BitmapData / Bitmap object that always lives on the stage. This may still take time, but should ideally take less of it than adding the entire large image to the stage. – scriptocalypse Jan 11 '13 at 18:46
  • @scriptocalypse tried a "blitting" sort of approach as well, but since the process involves panning the image around smoothly (essentially dragging the image on a large HD touchscreen), and perhaps in addition to the large amount of pixels that need to be processed, it didn't help at all. As others have suggested, using Starling may be another approach. – producerism Jan 11 '13 at 19:18
  • Howdy Producerism, I want to connect. I think you have producerism.com and I have producerism.org and think we should work together. Orbitingeden@gmail – Orbiting Eden Jul 13 '20 at 18:10

2 Answers2

4

The delay is due to Flash Player decompressing the image in preparation for rendering.

The trick is to force Flash Player to decompress before you need it - then it will 'instantly' appear on the stage.

I can't take any credit for idea - but i'll take the bounty ;). Here's the article that enlightened me and explains it fully: http://jacksondunstan.com/articles/2080

  • wow, exactly what I was looking for, thank you. It's still a hack - but it seems like the best answer I could hope for. – producerism Jan 11 '13 at 19:20
  • 1
    Holy moly that is fantastic. I had no idea that it worked like that and that article was both interesting and extremely helpful. I sometimes work with massive images too, so I will definitely use this in the future. Not that I needed this functionality exactly but it'd help nonetheless. So thanks a lot. Thanks to you too producerism, for both asking this question and setting that bounty to get this answer ;) – puggsoy Jan 11 '13 at 21:29
  • 2
    np, glad this could help someone else too. fyi, here is a link that goes into more detail. Apparently you can set a Loader's loaderContext property so that it won't fire a COMPLETE event until it's also been decompressed. It even specifies this as being useful for 10MP+ images for AIR apps. Couldn't have asked for any more info than that! http://help.adobe.com/en_US/as3/dev/WS52621785137562065a8e668112d98c8c4df-8000.html – producerism Jan 11 '13 at 21:43
  • Oh wow, thanks. Asynchronously too! Lee's solution, while great, appears to be synchronous from what I can see. So if you had a truly gargantuan image it may lock up the application for a while. Of course, if you're not using a `Loader` then you probably won't encounter such gigantic images anyway, but still. Either way both methods are great, thanks for sharing that! – puggsoy Jan 11 '13 at 23:37
  • 2
    Nice work with the loaderContext info! Thats definitely the way to go. It should work with embedded images too; by using Loader.loadBytes(byteArray, loaderContext); –  Jan 11 '13 at 23:46
0

If you are using a Loader class it's because the content isn't loaded yet.

Somewhere in your code you probably have something like this:

var loader : Loader = new Loader();
loader.load( new URLRequest( "theURL" ) );
stage.addChild( loader );

Now, this all happens in a few milliseconds. The content that you are loading isn't actually loaded yet though. The Loader is on the stage, but the content isn't placed in the loader until it is done loading.

Here's what you need to do.

var loader : Loader = new Loader();
loader.contentLoaderInfo.addEventListener( Event.COMPLETE, onImageLoaded, false, 0, true );
loader.load( new URLRequest( "theURL" ) );
stage.addChild( loader );

Then have this function in the same scope.

function onImageLoaded( evt : Event ) : void
{
    loader.contentLoaderInfo.removeEventListener( Event.COMPLETE, onImageLoaded );
}

In that function the image and all its properties will be accessible. It may not be actually drawn to the screen yet, but that will happen on the next frame which is probably within a few milliseconds, but as far as the code is concerned, it's on stage.

Hope that helps!

Jordan
  • 1,233
  • 2
  • 12
  • 32
  • Thank you, and you are correct I'm using a loader (greensock LoaderMax library to be specific). Getting the properties of the object is not the issue. Even if I completely load the images in memory (or even embed them into the SWF at compile time, instead of using a loader), the act of adding them to the display via addChild seems to be adding a delay (for large images 10MP+). If I try to use addChild to a parent with visible = false.. then when setting that parent to visible.true after the children are loaded and added, it causes the same problem. – producerism Jan 09 '13 at 15:05
  • Seems like there is nothing you can do with DisplayList renderer to solve your problem, but it may help to just use a completely different approach to rendering. Have you tried using Starling or some other Stage3D based 2D framework? Using Stage3D you are limited to 2048x2048 texture size, but you can split your larger images to several pieces. – borisgolovnev Jan 11 '13 at 18:12
  • @borisgolovnev - I have looked into Starling for improved performance, and may indeed need to go that route if this issue becomes more prevalent as development continues. Thanks, I'll continue to view that as an option. I've also considered using something like DeepZoom, which splits hi-res images into many different tiles, but most projects have been abandoned, and it's not a perfect fit anyways. But a tile system with culling would be another great option... if it already exists. – producerism Jan 11 '13 at 19:16