I am trying to send an image from android client to .NET based server, I am doing it using HTTP POST, will there be any significant difference if I use a stream for file upload or send the data as a base64 string, ie convert the string into base64, send and at the server side convert the base64 string back to image, what difference does it make?
There are a few (small) advantages to streaming instead of converting to base64. One is that the conversion to base64 will increase the byte load by about 30% going over the wire. Then there's the extra processing (and programming) involved in the conversion at both ends.
Having said that, I'd recommend base64 over streaming because, in the end, the programming will be much easier I think. Boxing up and sending an HTTP message, even if it contains a boat-load of base64 characters, should be child's play compared to getting that whole stream-send/stream-response business working on Android, right? How hard is it to concatenate into JSON a big string of characters? That's why I'd go with base64.
Related
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.
I want my mobile application to be able to upload an image to my server, in my case it's a Rails 3.2.11 with nginx.
I read alot about Base64 encoding on client side and then decoding on the server side.
Why not just use binary upload with multipart headers on the http request?
Are the any pros / cons for each technic?
Base64 converts your data to an ASCII representation of the binary data. It allows you to embed your data in text streams such as JSON for example. Base64 increases the size of the data transferred by 33%.
multipart/form-data is the standard way of transferring binary data in HTTP requests. It allows you to use specific encodings / content types for each part you'd like to transfer. In my opinion, you should stick to multipart uploads unless you have specific requirements or device/SDK capabilities.
'Why not just use binary upload with multipart headers on the http request?' indeed why not ;)
Base64 image representation can be directly placed within html to render an image.
Binary takes up less space. And benefits from greater network effects and standardization. E.g. if you want to use amazon simple secure storage S3 you have to store a binary file. You can't store a string you would need a key/value store e.g. redis.
I want to send a picture from my mobile to my server, and i know how to send it using base64 but i've heard that base64 is not recommended to use because base64 encoding increases the size of image by 37%, which in case slows down the performance of server because there will be too many images shared by users on the server.
can anyone recommend me the efficient technique than base64 encoding for the mobile based image sharing application (client-server app)?
You could simply POST your image (in regular UTF-8 encoding) as explained here: NSData and Uploading Images via POST in iOS. You will need to have some server-side servlet or php page to decode the image and save it.
You can use FTP, for uploading and downloading images from iPhone. The main advantage of using FTP over other methods is that we can set the bytes width per second to certain limit and can detect how much data has been transferred till Particular event.
Here is the code given by apple documentation to illustrate the uploading and downloading of any data (image, pdf, video or audio anything) over FTP.
http://developer.apple.com/iphone/library/documentation/Networking/Conceptual/CFNetwork/CFFTPTasks/CFFTPTasks.html#//apple%5Fref/doc/uid/TP30001132-CH9-SW1
Also refer this PDF for better understanding
http://developer.apple.com/iphone/library/documentation/Networking/Conceptual/CFNetwork/CFNetwork.pdf
Is there any way to send a huge data encoded to a 64-based String? It throws a 'outofmemory' exception when converting the data to string.
Cheers,
Stone
Apparently you got beyond memory borders even before ksoap got involved. Your data is just too freaking big when converted into base64 string. if you can not reduce amount of data tranfered, you shall switch to some streaming technique - like writing base64 data to stream / socked without allocating string. Or slice up your data in manageable pieces.
Or rethink your service architecture
My Base64 encoded data is very Large and comes dynamic not fixed fetch from web server for every transaction. So i need to fetch encode data partly and decode partly from base64 encoded data. Base64 encoded data is tiff image data.
For develop this functionality i create one function in which all base64 encoded data download partly from web server and store in txt file.when all data are stored in txt file. then i start decode data partly and create tiff image file.
base64 encoded data not stored partly (means not download partly) and come only once trip from web server then partly base64 decode working fine and tiff image download successfully...
But when store base64 encode data partly(download from web server partly) and comes more times trip or loop for downloading data and storing and partly base64 decode then tiff image not download... not working
I am not sure, whether I understand your problem, but I will try:
Whenever you decode base64 image sent in 1 go it works, but when you receive parts of it in few instalments, decode fails. If that is the case, you have to be clever about gluing your received parts together. Please remember that each character of Base64 encoding represents 7 bits of information not 8. You cannot simply append received characters into one big file, array or string. Does your server use base64 padding when sending chunks?
Please remember that Android does not support TIFF natively. Try using PNG or JPEG.
It would make much more sense, if the server sent it as binary data and you opened the stream on the connection and decoded the image from that stream on the fly using BitmapFactory class