This question already has answers here:
Get the image as Thumbnail
(2 answers)
Closed 9 years ago.
My app is currently sending images from an Android device to a PHP script by converting the image into a bit array and then converting to base64. The base64 string is then sent in a HTTP request.
The problem is that is the image is big (like the ones taken from android camera) then the transfer fails. What i want to do is change the image size before it goes through the conversion process.
How can i do this? I've tried to google it but have had no luck so far.
If your image size is big then you have to need first scale in to small size then encode this by base64 class then you send this on your server.
For scale your image read this http://developer.sonymobile.com/2011/06/27/how-to-scale-images-for-your-android-application
or other post
Use jpeg compression!
('Cause I'm not sure how sending up a base64 encoded byte array is going to save you any space.)
May I jump in and assume you've got a stage where you've converted your image into an array of pixels instead? If not, I'll assume there is no reason why the obvious conversion from bytes to integers representing pixels applies. Then we'll convert it to a compressed jpeg.
final int[] pixels = yourpixels;
You'll also need width and height:
final int width = theWidth; etc...
Next, get hold of your output stream in your client:
final HttpURLConnection connection = doWhateverYouDoToOpenYourConnection();
final OutputStream httpOutputStream = connection.getOutputStream();
Now the crucial step is to use the compression methods of Android's bitmap library to stream the compressed image onto the http output stream:
final Bitmap androidBitmap = Bitmap.createBitmap(pixels, width, height,Config.ARGB_8888);
androidBitmap.compress(android.graphics.Bitmap.CompressFormat.JPEG, YOUR_QUALITY_INT, outputStream);
Start with something like YOUR_QUALITY_INT = 85 to see significant improvement in image size without much visible deformation.
If this fails, create a scaled bitmap from a scale matrix: documentation here. This reduces the width and height of your bitmap on creation, which obviously reduces request size.
Hope this helps.
Related
I am decoding an image(ARGB) that is 8000x8000 pixels, so in uncompressed form it reaches
(2 + 2 + 2 + 2) * (8000 * 8000) = 488 MB
and crashes the android. I don't want to sample the image because I am converting the bitmap to byte array and sending it in a PUT request. I have tried "decodeRegion" but I don't know how to stitch the data(i.e. byte arrays) back together , since they have the head info at start and just concatenating them isn't helping.
Use an HTTP client library that allows you to upload from a file or stream, so that you do not need to decode the image and try to hold it in memory. OkHttp has options for this; see this recipe for streaming a POST request, this recipe for POSTing a file, or this recipe for multipart POSTs. Those techniques should be adaptable to a PUT request.
Why are you reading in a large image, decoding it, then posting the byte array? That's the wrong way to do it.
If your API actually requires the decoded bytes, fix it. More likely it wants the file's raw data. In which case you just need to use any networking API that gives you an OutputStream, and read in the file's data 1 MB at a time, reading it from the File's InputStream and writing it to the socket's OutputStream
I need to compress an image to send it to my server. I am trying to do it this way:
private Bitmap compressImage(Bitmap bitmapImg){
ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmapImg.compress(Bitmap.CompressFormat.JPEG, 50, out);
Bitmap compressed = BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));
return compressed;
}
But when I compare the Byte count of the original Bitmap object and the compressed one, I get the same number:
Log.e("UNCOMPRESSED", Integer.toString(mBitmapImg.getByteCount()));
E/UNCOMPRESSED: 23970816
Log.e("COMPRESSED", Integer.toString(compressedBitmapImg.getByteCount()));
E/COMPRESSED: 23970816
How can I fix this to have a smaller file?
But when I compare the Byte count of the original Bitmap object and the compressed one, I get the same number:
The size of a Bitmap in memory is based only on its resolution (width and height in pixels) and bit depth (the number of bytes per pixel, for controlling how many colors can be used per pixel).
How can I fix this to have a smaller file?
You do not have a file. You have a Bitmap object in memory. An image file is usually stored in a compressed form. In particular, this is true for JPEG, PNG, WebP, and GIF, the four major image formats used in Android. So, for example, out.toByteArray() will be smaller than 23,970,816 bytes.
Moreover, you are not sending a Bitmap to the server. You are sending an image to the server. You need to read the documentation for the server, or talk to the server developers, to determine what image format(s) they support and how to send the image to the server (ideally, something efficient like an HTTP PUT).
If you want to reduce the in-memory size of the Bitmap, scale it to a lower-resolution image (e.g., via createScaledBitmap()).
You can change your bitmap format to RGB_565 from ARGB_8888. That'll reduce your bitmap's memory footprint to half, but, would lead to loss of quality as well. Unfortunately, that's the most you can do with Bitmap.
Having said that, the compression method that you're using should work fine for most situations. It's also the advocated method for a number of platforms. An example for Firebase is this.
I am working with a customizable database with pictures. Right now I am taking pictures as it is from the sdcard and encoding it in base64 String and then putting it in the database. but whenever I am trying decoding it and showing it in my view, I am getting Out of memory error. Can any one one tell me what is the best procedure to do it? Shall I change the size of the pictures before encoding it?
I want to re-size all of the pictures into 512*512.
Image to Base64 is very heavy operation in android. Consider saving the images on the external/internal memory and save the file path in the sqlite database.
You can convert your image to byte array then store values in sql by using BLOB type and vice versa.
As you mentioned you want to resize the images to 512*512, you can scale the image using below code,
Create bitmap from captured image and then use below line
Bitmap resizedBitmap = Bitmap.createScaledBitmap(myBitmap, 512, 512, false);
It will give you a smaller image, you can also consider compressing the image to reduce in size,
OutputStream imagefile = new FileOutputStream("/your/file/name.jpg");
// Write 'bitmap' to file using JPEG and 50% quality hint for JPEG:
bitmap.compress(CompressFormat.JPEG, 50, imagefile);
Now, you have two options,
Save the scaled and compressed image into a file and save the path of that file in db. (Better way)
Convert the scaled and compressed image to base64 string and save in db.
Althought base64 is , as many answers said, a heavy operation for android, if done properly, it should not be a problem.
There are many reasons a bitmap could be required to be saved to a DB , (photo of a invoice ticket, for example?), and this is the way i do it.
first, create a new , smaller bitmap like #Swapnil commented.
and second, correctly use the bitmap transformation methods, i've been using these (look below) two so far and haven't had any memory issue on many different devices.
link to my BitmapUtils transformation methods
I am uploading an image (JPEG) from android phone to server. I tried these two methods -
Method 1 :
int bytes=bitmap.getByteCount();
ByteBuffer byteBuffer=ByteBuffer.allocate(bytes);
bitmap.copyPixelsToBuffer(byteBuffer);
byte[] byteArray = byteBuffer.array();
outputStream.write(byteArray, 0, bytes-1);
Method 2 :
bitmap.compress(Bitmap.CompressFormat.JPEG,100,outputStream);
In method1, I am converting the bitmap to bytearray and writing it to stream. In method 2 I have called the compress function BUT given the quality as 100 (which means no loss I guess).
I expected both to give the same result. BUT the results are very different. In the server the following happened -
Method 1 (the uploaded file in server) :
A file of size 3.8MB was uploaded to the server. The uploaded file is unrecognizable. Does not open with any image viewer.
Method 2 (the uploaded file in server)
A JPEG file of 415KB was uploaded to the server. The uploaded file was in JPEG format.
What is the difference between the two methods. How did the size differ so much even though I gave the compression quality as 100? Also why was the file not recognizable by any image viewer in method 1?
I expected both to give the same result.
I have no idea why.
What is the difference between the two methods.
The second approach creates a JPEG file. The first one does not. The first one merely makes a copy of the bytes that form the decoded image to the supplied buffer. It does not do so in any particular file format, let alone JPEG.
How did the size differ so much even though I gave the compression quality as 100?
Because the first approach applies no compression. 100 for JPEG quality does not mean "not compressed".
Also why was the file not recognizable by any image viewer in method 1?
Because the bytes copied to the buffer are not being written in any particular file format, and certainly not JPEG. That buffer is not designed to be written to disk. Rather, that buffer is designed to be used only to re-create the bitmap later on (e.g., for a bitmap passed over IPC).
I need to encode an image to be JPEG and maximum file zise to be 300 K and send it as byte array. I make encoding :
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
image = baos.toByteArray();
do you know how to limit the file size to 300K? maybe the solution is to make image quality lower, but sometimes(when the image is smaller) I may not need this. Thanks
By repeatedly compressing with descending 'quality' values until the resulting byte[] length <= 300KB. There is no shortcut through this (AFAIK) but you can choose the quality values carefully and limit yourself to, say, a maximum of 4 compressions.
Quick answer is to use a trial and test solution to find a compression value which gives you a value close to less than 300k.
File sizes for JPEG are highly dependent on the detail of the image so unless you're pictures are going to be of the same detail (no all black images etc) then the best compression rating will be different.
Maybe use a binary search style algorithm to find a good solution? Start at 50, then if too big, go down to 25 otherwise go up to 75. Then whenever you're within say 270-300 just stop?