1

I'm making a program for myself that can open unarranged sprite sheets, arrange them according to an XML file, and then save them as PNGs. What it does is it loads the unarranged sheet and puts it in a BitmapData, then according to a specific XML file it grabs each frame on the sheet (using BitmapData.copypixels()), and adds the resulting Bitmap to an array in order. Then it arranges them by adding these Bitmaps to a Sprite object, making new lines accordingly. In essence, what I end up with is a Sprite containing Bitmaps that are arranged how I want them.

Now what I normally do from here is draw the Sprite onto a BitmapData using BitmapData.draw(), which works, and then I go on to encode it as a PNG and save it. This all works, except for in one case. Sometimes I make one arranged spritesheet out of multiple unorganised ones, which results in a fairly large sheet. In one case this resulting sheet is extremely large, and for some reason the BitmapData that I want to draw to just won't accept being that large. That is, I create a new BitmapData, with dimensions equal to the Sprite, but when I try to do that I get this error:

ArgumentError: Error #2015: Invalid BitmapData.

As far as I know this only happens if I make a BitmapData with a width and/or height of 0, or if I exceed the maximum dimensions. I'd think it was the latter if it wasn't for the fact that Flash 11 and AIR 3 don't have a limit.

In any case I haven't found a way out of it, so basically this is my question: is there any way to do this differently? For example, can I get the pixel data of a Sprite without making a BitmapData? Or, can I somehow store the data in a BitmapData without having to give it the same dimensions as the image? Or is there some different way to do this altogether?

I realise I can split up the image into 2 separate BitmapDatas, but I want to know if there's an alternative before resorting to this.

By the way, if it matters, it's an Adobe AIR app made using FlashDevelop and the Flex 4 SDK. I'm using PNGEncoder2 to encode the final sprite sheet that I save.

EDIT: I have discovered that the problem seemed to be that my PC simply can't handle a BitmapData of the required size. I tried splitting it into two separate BitmapDatas, but unfortunately when creating the second BitmapData I received the same error. Therefore it simply seems that that amount of data cannot be contained in my PC's memory as BitmapDatas at one time. Unfortunately this means that I can't even use g10's solution of merging two BitmapDatas into a single PNG using the PNG encoder he linked to. My solution so far has been to store draw half of the image into a BitmapData, encode it, then dispose() the BitmapData and store the second half in it and encode that. Then I save the ByteArrays (which are the result of the encoding) as separate images, which I can reconstruct into one using an external program.

So now, my question is more "can I somehow save this as a single PNG" rather than "can I get it as a single BitmapData".

puggsoy
  • 1,270
  • 1
  • 11
  • 34

2 Answers2

2

I ran into the problem as well, and found that there is a limit between 19,000 x 19,000 pixels. That's on Windows 7 with Flash Player 11.3, of course Flash Player 10 has much lower limits, check this page for the details.

Here's the code I used for testing:

package
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.display.StageAlign;

    public class PNGTest extends Sprite
    {

        static var IMAGE_DIM = 18000;
        public function PNGTest()
        {
            this.stage.align = StageAlign.TOP_LEFT;
            var bmData = new BitmapData(IMAGE_DIM, IMAGE_DIM, false, 0xFF0000);
            var image:Bitmap = new Bitmap(bmData);
            this.addChild(image);
        }
    }
}

If you need an image larger than what's supported by the Flash Player version you are targeting, just split up the image. You could copy the image data into a ByteArray as well, don't know what the maximum size of that would be. See How to convert bytearray to image or image to bytearray? for some example code.

Community
  • 1
  • 1
raju-bitter
  • 8,906
  • 4
  • 42
  • 53
1

Check the async PNGencoder from inspirit.ru: http://blog.inspirit.ru/?p=378
The PNGencoder.swc is provided, and usage examples.
No limits on the size of the image, only takes some time to encode (possible to show a progress bar).

EDIT:
There is an upper limit for the dimensions (amount of pixels) of a BitmapData object, but not for the PNG, check the usage info at http://code.google.com/p/in-spirit/wiki/PNGEncoder, especially the getNextBitmapsRow callback

Specifically for your situation, instead of drawing your Sprite in 1 big BitmapData object, this PNGEncoder allows you to split up your big Sprite in several small BitmapData objects (e.g. from a Sprite of 35,000 x 60,000 pixels you can make 35 columns x 60 rows = 2100 BitmapData objects of 1000x1000 pixels), it does so with a callback mechanism: create and pass the first BitmapData object, the lib encodes it, and calls the callback when it is finished at which point you create and pass your next BitmapData to encode.

g10
  • 146
  • 1
  • 4
  • The problem isn't with the encoding of the PNG, but rather with making a BitmapData of that size. My current PNG encoder hasn't had any problems so far. – puggsoy Aug 21 '12 at 17:21
  • @puggsoy Please check the edit and the usage info example. Your needs seem to be: having a huge Sprite which should end up as an PNG image. Your problem: you cannot make a BitmapData object of that size. The solution: have several smaller BitmapData objects which together form the big result image. The PNGEncoder which I refer to makes this possible. – g10 Aug 21 '12 at 19:09
  • Ah, I see, you mean the feature to merge multiple images into a single PNG. That's pretty nice, I must admit, but it doesn't exactly answer my question. What I want to know is if there is a way to avoid using multiple BitmapDatas altogether. Whether I can export them as a single or multiple PNG doesn't concern me. Nevertheless, it is pretty nice, so thanks. – puggsoy Aug 21 '12 at 19:15
  • @puggsoy So you want 1 big Sprite which results in 1 big PNG, without the Sprite being converted to (one or more) Bitmap(data) first? I guess it will not be easily accomplished without the intermediate step. Although your Sprite consists of several Bitmaps, the positioning needs to be translated also. – g10 Aug 21 '12 at 19:29
  • Well I don't mind converting the Sprite to a single BitmapData, but as you can see it won't allow me to make one with the required dimensions. What's more is that if I make two BitmapDatas, each half of the size, it won't allow me that either. The only way to do it is to save half the sheet in a BitmapData, encode it, then dispose of the BitmapData and use the same BitmapData with the second half of the sheet. Then I save both halves as separate images. This is what I'm doing now, and it's sufficient, but I just want to know if there's a workaround to get it as one BitmapData. – puggsoy Aug 21 '12 at 21:22
  • @puggsoy You want it as 1 big BitmapData object OR you want it as 1 big PNG image? (you seem to assume that because there are several BitmapData objects, you automatically must end up with several PNG images, which is not the case)… – g10 Aug 21 '12 at 23:04
  • I realise that with the encoder you referred to, I can merge two BitmapDatas to get one PNG. What I wanted to know is if it is possible to get it as one big BitmapData. It's not essential but it would also be better since in my program, the dimensions of the sheet are dynamic, and being able to put any resulting sheet into a single BitmapData (instead of checking if it is too big, and splitting it if it is) is just overall more desirable. I realise your confusion since (accidentally) my question title isn't my actual question. However check the edit in the main question. – puggsoy Aug 22 '12 at 11:43
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/15663/discussion-between-g10-and-puggsoy) – g10 Aug 22 '12 at 13:11