Android uploading pictures to server in most efficient way - android

I need to get images along with other data (very similar to email with attachements) to the server. I also need to do it in reliable manner so I can retry, etc on failure.
Server is WCF REST server and I do lot of other communications with it(JSON) but just got this new requirement to upload images.
Since I use JSON to post data to my server - I use GSON on Android side to serialize data.
Here is how I got it implemented so far (everything else works this way but I just started with images)
User filling activity fields (text data)
User takes some picture(s) via camera intents. Currently I just use 1 file for pictures
I take picture from SDCard, load/resize it - dispaly on ImageView and store in byte[]
User submits - I take all data along with images from byte[] and put it into Java object
Call GSON converter and serialize object
Save object into SQLite
AsyncTask looks in SQLite for records, opens cursor and get's text
AsyncTask creates HttpConnection and posts text data to my server.
THE END
Now to my problems..
Obviously on #3 - I "explode" ram with my byte arrays. Sometime I even feel my Nexus S becomes sluggish. But by doing that - I avoid filling SD card or app folder with many files. I take picture and than grab it. Next picture will overwrite previous one.
Step #5 IS slow. I didn't try custom serializer on GSON and instead of serializing byte array into something like [1,-100,123,-12] I can get much smaller size with Base64 but still. It will be slow. And I can have up to 20 images...
Step #6 is no problem. But with certain size (I tried 300px image) I started to get error in step 7 on OpenCursor
07-06 20:28:47.113: ERROR/CursorWindow(16292): need to grow: mSize = 1048576, size = 925630, freeSpace() = 402958, numRows = 2
07-06 20:28:47.113: ERROR/CursorWindow(16292): not growing since there are already 2 row(s), max size 1048576
07-06 20:28:47.113: ERROR/Cursor(16292): Failed allocating 925630 bytes for text/blob at 1,1
So, this whole thing is not something I like. Ideally I want all data to be uploaded in single piece to server.
I was thinking maybe storing images timestamped on SD card and store only their name in DB. Than I would process them right before sending to server. And on success I would delete those images. This kind of logic will make SQLite schema much more complex but maybe there is no better way?!
I guess I'm looking for best practice to deal with images. How to do followin with minimal memory/CPU usage:
Take picture
Display thumbnail
Resize
Send to server
EDIT 1:
Currently I'm researching possibility of uploading whole shizang as a multi-part MIME message. That would require adding some JAR's to my Android package. Also I'm not sure how effective will be Apache code to load images and sending them(I guess better than my code)
http://okandroidletsgo.wordpress.com/2011/05/30/android-to-wcf-streaming-multi-part-binary-images/
And that I would have to deal with parsing all this on WCF side since there is no way to do it with built-on .NET framework.
http://antscode.blogspot.com/2009/11/parsing-multipart-form-data-in-wcf.html
PLEASE TELL ME IF YOU TRIED THIS!
EDIT 2:
MIME is no good. There is no point since it serializes binary using Base64 which is same thing..

Nobody answered but here is what I figured hard way:
Rule #1: When dealing with images - avoid using objects/memory. Sounds obvious but it's not. I figured that resizing image to 800x600 is OK. Anything bigger - you may consider just leaving it as is because it is possible to do http stream on bigger file but it's hard to work with OOM exceptions when you load images into memory for processing
Rule #2: When use GSON - use JsonWriter to populate stream. Otherwise memory will explode. Than pass that stream into HttpClient. JsonWriter will write in chunks and data will be sent as it process.
Rule #3: See rule #2. It will work OK for multiple small images. This way GSON will serialize them 1 by one and feed into stream. Each image WILL be loaded int memory anyway.
Rule #4: This is probably the best solution but requires more coordination with server. Images sent 1 by 1 before message sent to server. They sent as stream without any encoding. This way they don't have to be base64 encoded and they don't have to be loaded in memory on device. Size of transmission will be smaller as well. When all images sent - post main informational object and collect all package together on server.
Rule #5: Forget about storing BLOB in SQLite
Bottom line:
It is much cheaper in term of resources to send images WITHOUT any resizing. Resizing makes sense only when Image get's to about 800x600-ish
Sending multiple images in a single package makes sense when image get's small like 600x400-ish
As soon as you need to upload files - start thinking streams everywhere. DO NOT load stuff into memory.

Related

How to send big size image to a server in android?

I have to send a DNG file which has a size around 30 mb to my server and then I have to process DNG file in matlab and after that I need to get the results back from matlab to android device. I am new to sending images to a server and I do not know if is there any special way for big size images. I saw similar questions but I could not understand what to do for sending images to a server.
Could you please help me which steps should I follow respectively and which methods or libraries do I need to use ? Thanks.
If you'd like to send big files using HTTP, chunks are the way to go.
You would need a backend server supporting this kind of operation (either with some homemade recipe or with a standardized implementation).
You'd basically need an API to create the file description (including the expected size) which would return a handle on this future file (at least an ID). Then use PUT or PATCH and send the chunks one by one.

Android Image upload/download with Base64 into JSON causes Out of memory error

I currently encode and decode images to Base64. I overcame the initial issue with OOM's with the use of streams to encode the images into strings.
My issue now is that I cannot fathom how to add multiple Base64 encoded strings for multiple resolutions images (5620 x 3747 - 4.92MB or 3264 x 1836 - 1.35MB) to a JSON Object via Gson. Currently Gson throws an OOM exception only with 2 Base64 Strings from a 5312 x 2988 - 4.95 MB Image.
I understand that android may only be able to spare 16/20Mb per application, so this conversion must be way over the limit.
How can I write the Base64 String in a stream to a JSON object that will contain the specific values needed to post into my server?
Would it be easier to change my server to accept a Multi-Part request instead of a JSON based POJO with multiple Base64 Strings? I currently use Volley and there isn't an official Multi-Part Request as well as IO streaming.
If it's a matter of compression, how much compression should I apply to the image before encoding into a Base64 String? I ideally want to lose barely any quality but have optimal compression levels.
Bit more Information
I am uploading multiple different resolution images as it is a test for compatibility. For example, all the images that I am sending up have been taken on low resolution and extremely high resolution devices as my App relies on these images for functionality. I am trying to prove that any image (to a certain extent, mainly images captured on mobile devices) can be handled by my application.
I understand that some images may be so large that by loading them into memory will cause exceptions. This is something I will try and handle later.
In some cases the images that will be uploaded can span from 1 to 200.
I'm trying to look for the most optimal solution that will scale well.
... for multiple resolutions images (5620 x 3747 - 4.92MB or 3264 x 1836 - 1.35MB)...
Not sure if this is the file size or the memory needed to allocate the image in memory, but taking a look at the following link: http://www.scantips.com/basics1d.html, I see this:
For a 4000 x 2500 pixel image,
then: 4000 x 2500 pixels = 4000x2500 = 10 megapixels
4000x2500 x 3 = 30 million bytes (if 24-bit RGB)
30,000,000 bytes / (1024 x 1024) = 28.61 megabytes (MB)
This is simply how large the data is - For ANY 24-bit 10 megapixel
image, but JPG files compress it smaller (only while in the file).
I think that the images you're handling are taking much more memory than you expect.
Also, taking a look at this question and answer: https://stackoverflow.com/a/11402374/3393666, we know that a base64 representation of an image take up to 37% more memory than the original image size.
How can I write the Base64 String in a stream to a JSON object that will contain the specific values needed to post into my server?
I think you could do this (with small images not large ones) by simply adding the base64 representation of the image in a JSON object then posting it to the server.
Would it be easier to change my server to accept a Multi-Part request instead of a JSON based POJO with multiple Base64 Strings?
In my opinion that would be your best option to implement what you're trying to achieve.
I currently use Volley and there isn't an official Multi-Part Request as well as IO streaming.
You can take a look at this answer: https://stackoverflow.com/a/16803473/3393666, you can definitely can do it with volley, but if you want an alternative you can try with retrofit (http://square.github.io/retrofit/) they support Multipart our of the box.
eg:
#Multipart
#PUT("user/photo")
Call<User> updateUser(#Part("photo") RequestBody photo, #Part("description") RequestBody description);
I looked into using Volley as a mechanism to transport large JSON objects to a server and found this answer. This answer essentially proved that Volley would be a bad idea for what I wanted.
I switched to OkHttp and now use their streaming methods allowing the JSON to be streamed to the server and then read the response with a streamlined approach. I used the GSON library to parse the response as OKHttp allows the response JSON/Object to be streamed into a reader object which Gson then uses for internal streaming and parsing to an POJO class.
The ony reason why I did not switch to a Multi-Part request was due to the server side implementation being rigid and unchangeable to cover for Multi-Part requests, it strictly expected a JSON representation of data and files.
For handling Base64 Images on Android I severely reccomend not using the String representation and merely converting to Bytes to save on using an excessive amount of memory. I read this article on String memory usage and management. With the Bytes you may easily transport the data without leaving a massive footprint on memory.
For Displaying the images I still avoid the bytes to String conversion by using the Image library Glide. They allow you to pass in a byte[] which was of massive convenience.

Android - Efficient way to load multiple images from remote server

I have an Android application that would retrieve data (images+text) from a php remote server and display them in a GridView.
I am doing the operation in the background using Loaders. I have separate connections for images and texts since retrieving images would take longer and I want to display the texts immediately. The texts are encoded with Json on the server after being retrieved from MySQL. On the app, I am parsing the Json Objects and displaying the texts as I need.
The problem is with images. I am not sure if encoding the images with Json would be a good idea. Also the images are saved as blob in the database, in order to encode them with Json I need to use base64_encode() before which is not efficient. I have seen many posts about this, but it’s always a simple example when you have to get one image. In my case I’ll be retrieving up to 30 small-size images.
My question is, I can proceed with what I just presented, but it seems that there should be a better way to do this. What do you think about this? Am I going the wrong way?
Also I was thinking if I can display each image separately in the gridview once it is ready (not waiting for all the images to be ready) just like in the “Google Play App”’s GridView. What approach can I take to achieve this?
Thanks in advance folks!
Best approach in my eyes would be to download the image files as normal image files via a HTTP get request. Make sure it is threaded of course, and have a thread pool that you can queue up requests into, and have 2-3 threads go through and download.
In terms of saving them, I would personally move away from saving to blob in a database, and opt to save them to the persisted storage in your application's private directory. Saving the image files with their filename as their id in the database you have created will be much quicker for loading them back in.
You can also hold a reference to the ImageView, and have it display a place-holder initially, with a successful HTTP request replacing the bitmap of the ImageView with the one you have just downloaded/read in from storage.
You can also do some image caching within the HTTP request you make.
ImageView myImageView = findViewById(R.id.testImage);
URL url = new URL("http://www.website.com/image.jpg");
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Object response = connection.getContent();
if (response instanceof Bitmap) {
Bitmap bitmap = (Bitmap)response;
myImageView.setBitmap(bitmap);
}
It also may be helpful to lookup the uses of the LRUCache, which performs a lot of caching functionality for you.
Check out this link at the Android Developer site for a good in depth guide to image caching
Edit:
You can use the advice in Robert Rowntree's answer to load bitmaps more efficiently to cut down on your memory use as well. The link provided details loading of bitmaps using less memory, something that would work well if you are creating thumbnails from larger images downloaded over the web and saved off to local storage.
IMO - there are 2 issues , moving the images across the network to the client and getting them loaded.
Assuming that you are using http as the protocol, you should have a multithreaded solution for http as is available in apache httpclient package. That will get the pictures to the phone fast.
Then , you have to present the pics by getting them into memory and a cache. Here you can consider what 'gallery3D' app does with its grid and bitmaps but its pretty complicated to read thru that code.
check out - http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
check out code samples for loading thumbs from bitmaps.

How to work around Android Bitmap memory inefficiencies?

We are working on an native Android app that handles large images (5MP+) from the phone's gallery, eventually encoded base 64, JSONized and sent to an upstream server. We've used some of the guidance given in other StackOverflow questions. We've tried hard to keep memory usage to a minimum, following logcat closely, debugging, etc. And while we've gotten under control the "80% use case" we still are getting FATAL errors in certain cases (when the user picks a photo, then cancels, chooses a different one, for instance).
We've found that when importing a 5MP Bitmap, its size quadruples in the Heap (i.e. a 7Mb jpeg becomes 28Mb in memory). We've used tricks to convert to Base64 as efficiently as possible. We've made sure the JSON parser is not leaking and so forth.
So to get back to my original question, is there a way to circumvent Android's Bitmap handling?
eventually encoded base 64, JSONized and sent to an upstream server
Rewrite your Web app to support binary payloads, so that you do not have to do ridiculous stuff like this. Upload JSON-encoded metadata in one request, then upload the image in its original format in a separate request, if need be. Or, use multipart upload to do both in one shot, leaving the image in its original format.
We've found that when importing a 5MP Bitmap, its size quadruples in the Heap (i.e. a 7Mb jpeg becomes 28Mb in memory)
That is because PNGs, JPEGs, and the like are compressed, and the image needs to be uncompressed to be displayed.
is there a way to circumvent Android's Bitmap handling?
You do not say if you are trying to display the image or not. If you are, use BitmapFactory with an appropriate BitmapFactory.Options to scale the image.
If you are not trying to display the image, once you rewrite the Web app to accept a binary payload, you should not need to load the entire image into memory. Just upload it in the format that it already is in, reading in chunks at a time (e.g., 8KB) to write to the OutputStrem of your HTTP PUT (or whatever) for the upload.

Possible Methods to retrieve image from server

I am developing an application where it should get data from my server with respect to the ID Number , and also I need to take an image from database , according to the id number. So I went to an option of loading url image. There I could not able to get large size images. So I went to converting the image to base64 format and sending it through webservice. Even in that I was able to retrieve small size strings , but when I go for big size of images, the base64 string is bigger. So looking for possible answers, any way thanks in advance...
Sending photos in binary form over a HTTP connection is a solved problem. I suggest you go with an off-the-shelf web server and call it a day. To send reduced-size images, install a script that (in response to a URL that indicates desire for a thumbnail) will check for thumbnails; create them if they don't exist; and then serve as images in the standard manner. Don't worry about base64 unless you're dealing with really ancient services that don't understand pure binaries. If you do go the route of base64, don't worry about file-size expansion. Unless you're sending huge numbers of images, it's not that significant.
I had this problem and had to use ftp server. I put my image files into a ftp server and download each one I need.

Categories

Resources