5

I need to send an image taken from the Camera over network. The image is too large to create a bitmap needed to use bitmap.compress(); It looks like the Gmail application can attach images from the camera while maintaining their large pixel size but with a great reduction their file size.

This won't work because I getBitmap() will return an Image to large to allocate and I don't want to sub sample it down to a smaller size.

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    getBitmap().compress(Bitmap.CompressFormat.JPEG, 70, baos);

Any ideas on how I can do the same without exceeding my total memory?

Update:

For anyone coming back to this thread I followed Phil's answer and used Apache MultiPartEntity to get the job done easily. (It handles streaming files from disk to network for you) http://hc.apache.org/httpcomponents-client-ga/httpmime/apidocs/org/apache/http/entity/mime/MultipartEntity.html

sgarman
  • 6,152
  • 5
  • 40
  • 44

5 Answers5

3

Probably it'll make a sense to use zipping before sending over network? InflaterInputStream on a sender side and DeflaterOutputStream on receiving side looks like workable combination.

ADDENDUM Try to use another approach:

FileOutputStream fos = new FileOutputStream(file); //intermediate file to store compressed image
InputStream is=this.getStream(imageUri); //image uri taken from camera
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize=2; //try to decrease decoded image
options.inPurgeable=true; //purgeable to disk
Bitmap bitmap=BitmapFactory.decodeStream(is, null, options);
bitmap.compress(Bitmap.CompressFormat.JPEG, 70, fos); //compressed bitmap to file
Barmaley
  • 16,638
  • 18
  • 73
  • 146
  • Thanks for the suggestion, but I actually want to compress the image using image compression, ie Bitmap.CompressFormat.JPEG. I think that will take care of a lot of the size issue, I'm just not sure how to do that when I can't create the bitmap first. – sgarman Mar 31 '11 at 05:29
  • If I'm not mistaken, increasing the inSampleSize will decrease the image resolution. I would like to keep the image res intact, just as the gmail app does when attaching photos. Thanks for your continued help. – sgarman Mar 31 '11 at 06:40
2

As you haven't defined quite what 'send over the network' means here, it's difficult to give specific advice.

However, if you want to send a lossless image (or with less loss than has already occurred), I don't think you'll be able to compress much more, as JPEG already compresses. It uses lossy compression, so if you increase the JPEG compression, you lose details (although maybe not ones you'd notice, as it's based on frequencies not pixels)

If you just need to send over the network, then why not just open an InputStream, and spool data directly to the network?

Hope this helps - if you can provide more details, I'll update the answer.

Best wishes,

Phil Lello

Phil Lello
  • 8,377
  • 2
  • 25
  • 34
0

You can use the lower version of the image i.e. of resolution 512x384 (mini thumbnail). Check this answer on how to get the mini thumbnails.

The thumbnails are already compressed to 80%.

Community
  • 1
  • 1
Karan
  • 12,724
  • 6
  • 40
  • 33
  • Thank you for your response, I do not want a smaller resolution image, I want the full resolution just with image compression. – sgarman Apr 12 '11 at 07:33
  • What is the actual image resolution ? – Karan Apr 12 '11 at 07:40
  • Typically I'm working with items from the Gallery which are often photos. The actual resolution fluctuates from device to device based on their camera. Images around 2000x1600 are normally not possible to render as a Bitmap in full. – sgarman Apr 12 '11 at 07:43
  • I think, you need to check the compression algorithm used in the Android. Also find out the formula to calculate the size of compressed image with particular compress ratio. From this formula, you will be able to calculate the compression ratio and use that to compress your image. – Karan Apr 12 '11 at 07:48
0

I think that you can only do this in native code, where you can allocate a lot more memory. This means that you would need to use and compile a native library such as libjpeg, or some full-fledged package such as ImageMagick in order to support reading from various images formats.

With this, you wouldn't use the Bitmap class at all for compressing. Your native code would take care of both reading and writing image files. If you manage to compile the library, your native code shouldn't be more than a few dozens lines.

Unless you know C and have already played with JNI and the Android NDK, this isn't going to be easy. Especially, compiling third-party libraries for Android can be tricky at times.

But I believe that going native is the only solution here.

olivierg
  • 10,200
  • 4
  • 30
  • 33
  • Actually, libjpeg is part of the android image (in /system/libs/libjpeg.so on 2.2 anyway), but a JNI wrapper isn't. – Phil Lello Apr 15 '11 at 18:37
  • This is a private aspect of the system. libjpeg could be here or not, it could be modified or not. You can't rely on it. So the only choice is to bundle your own version of libjpeg or equivalent. Of course, one could reuse the version and makefiles which comes with the Android sources, to ease compiling. Regarding a Java wrapper, if that was available (and there certainly are Java jpeg packages), it wouldn't solve the memory limit problem. I'm pretty sure you need to go native here. – olivierg Apr 15 '11 at 22:08
0

Probably, pre-splitting the image; compressing each individual one and restoring at the end sounds logical.

Here are few attempts,

http://kalanir.blogspot.com/2010/02/how-to-split-image-into-chunks-java.html

And

http://www.anddev.org/multimedia-problems-f28/chunk-of-a-big-big-image-t6211.html

Priyank
  • 10,503
  • 2
  • 27
  • 25