0

I want to send a fax from my app. A fax document has a resolution of 1728 x 2444 pixels. So I create a bitmap, add text and/or pictures and encode it to CCITT (Huffman):

Bitmap image = Bitmap.createBitmap(1728, 2444, Config.ALPHA_8);
Canvas canvas = new Canvas(image);
canvas.drawText("This is a fax", 100, 100, new Paint());
ByteBuffer buffer = ByteBuffer.allocateDirect(image.getWidth() * image.getHeight());
image.copyPixelsToBuffer(buffer);
image.recycle();
encodeCCITT(buffer, width, height);

This works perfect on my Galaxy SII (64 MB heap size), but not at emulator (24 MB). After creating the second fax page I get "4223232-byte external allocation too large for this process...java.lang.OutOfMemoryError" while allocating the buffer.

I already reduced color depth from ARGB_8888 (4 byte per pixel) to ALPHA_8 (1 byte), because fax pages are monochrome anyway. I need this resolution and I need to have access to the pixels for encoding.

What is the best way?

almisoft
  • 2,153
  • 2
  • 25
  • 33

3 Answers3

0

Android doesn't support 1-Bpp bitmaps, and the Java heap size limit of 24/32/48MB is part of Android. Real devices can't allocate more than the Java heap limit no matter how much RAM they have. There appear to be only two possible solutions:

1) Work within the limitations of the Java heap.

2) Use native code (NDK).

In native code you can allocate the entire available RAM of the device. The only down side is that you will need to write your own code to edit and encode your bitmap.

BitBank
  • 8,500
  • 3
  • 28
  • 46
0

In addition to BitBank's already good answer, you have to null the reference if you want the Garbage collector to actually clean up your Bitmap's references. The documentation for that method states:

This is an advanced call, and normally need not be called, since the normal GC process will free up this memory when there are no more references to this bitmap.

DigCamara
  • 5,540
  • 4
  • 36
  • 47
0

instead of copy all pixels to a ByteBuffer, you can copy step by step. Here with a int[] array. So, you need less memory:

int countLines = 100;
int[] pixels = new int[width * countLines];
for (int y = 0; y < heigth; y += countLines) {
    image.getPixels(line, 0, width, 0, y, width, countLines);
    // do something with pixels...
    image.setPixels(line, 0, width, 0, y, width, countLines);
}
almisoft
  • 2,153
  • 2
  • 25
  • 33