134

I want to send an image from the android client to the Django server using Http Post. The image is chosen from the gallery. At present, I am using list value name Pairs to send the necessary data to the server and receiving responses from Django in JSON. Can the same approach be used for images (with urls for images embedded in JSON responses)?

Also, which is a better method: accessing images remotely without downloading them from the server or downloading and storing them in a Bitmap array and using them locally? The images are few in number (<10) and small in size (50*50 dip).

Any tutorial to tackle these problems would be much appreciated.

Edit: The images chosen from the gallery are sent to the server after scaling it to required size.

Nolan Amy
  • 10,785
  • 5
  • 34
  • 45
Primal Pappachan
  • 25,857
  • 22
  • 67
  • 84

5 Answers5

146

I'm going to assume that you know the path and filename of the image that you want to upload. Add this string to your NameValuePair using image as the key-name.

Sending images can be done using the HttpComponents libraries. Download the latest HttpClient (currently 4.0.1) binary with dependencies package and copy apache-mime4j-0.6.jar and httpmime-4.0.1.jar to your project and add them to your Java build path.

You will need to add the following imports to your class.

import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;

Now you can create a MultipartEntity to attach an image to your POST request. The following code shows an example of how to do this:

public void post(String url, List<NameValuePair> nameValuePairs) {
    HttpClient httpClient = new DefaultHttpClient();
    HttpContext localContext = new BasicHttpContext();
    HttpPost httpPost = new HttpPost(url);

    try {
        MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);

        for(int index=0; index < nameValuePairs.size(); index++) {
            if(nameValuePairs.get(index).getName().equalsIgnoreCase("image")) {
                // If the key equals to "image", we use FileBody to transfer the data
                entity.addPart(nameValuePairs.get(index).getName(), new FileBody(new File (nameValuePairs.get(index).getValue())));
            } else {
                // Normal string data
                entity.addPart(nameValuePairs.get(index).getName(), new StringBody(nameValuePairs.get(index).getValue()));
            }
        }

        httpPost.setEntity(entity);

        HttpResponse response = httpClient.execute(httpPost, localContext);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
starball
  • 20,030
  • 7
  • 43
  • 238
Piro
  • 2,476
  • 3
  • 17
  • 19
  • As I mentioned earlier, the images I am sending are small in size. So do I need to use MultiPartEntity to send them? – Primal Pappachan May 30 '10 at 01:03
  • 6
    I would most definitely recommend this. This way you probably can use Django features to receive the image and store it easily. One other way would be to encode the byte stream from the image to a base64 encoded string and decode it server side. But this would be too much of a hassle in my opinion and not the way to go. – Piro May 30 '10 at 01:16
  • The images chosen from the gallery are sent to the server after scaling it to 50*50 dip. So I don't have a path to add to list value name pairs. So only the second approach you mentioned seems possible. – Primal Pappachan May 30 '10 at 07:11
  • You could save the image to a temporary file or if you want to skip all this you could take a look at http://androidcodemonkey.blogspot.com/2010/03/how-to-base64-encode-decode-android.html. This describes how to use Base64 encode. You can just use that as a string and skip my MultipartEntity example. – Piro May 30 '10 at 11:03
  • I am sending the images using this approach only i.e Filebody but it gives OutOfMemory Exception while uploading images. Is there any way we can handle that. – sunil Jun 28 '10 at 04:46
  • 6
    Hey guys, is there any way to do this without MultipartEntity? I REALLY don't want to import all of Apache HC just for those 4 classes. :-( – Neil Traft Aug 01 '10 at 15:53
  • Not at the moment as far as I know. You could go with the base64 encoding and just post that as string data to your server and decode it on the backend. That way you don't need to import the .jar's. – Piro Aug 06 '10 at 17:47
  • To send image we can covert it to byte array, then create new ByteArrayBody (see [Interface ContentBody](http://hc.apache.org/httpcomponents-client-dev/httpmime/apidocs/org/apache/http/entity/mime/content/ContentBody.html)) and add it to multi-part entity. See my [post](http://t.co/MWfc2TF). – Vikas Jan 13 '11 at 09:13
  • For `FileBody` the `Content-Type` always seems to be `application/octet-stream` although I would need it to be `image/jpeg`. Any suggestions on how I could solve that? – vinzenzweber Mar 08 '11 at 09:09
  • 6
    Just add a 2nd parameter to `FileBody` with your desired Mime Type. E.g.: `new FileBody(new File (nameValuePairs.get(index).getValue()), "image/jpeg")` – Piro Mar 08 '11 at 22:25
  • 4
    It looks like multipartentity is deprecated? – Nanne Jan 05 '14 at 10:18
  • i cannot find apache-mime in the download link? is it not needed? – Illegal Argument Feb 25 '14 at 04:16
  • @IllegalArgument Seems it's coupled in httpmime-4.3.2.jar right now. So I guess you indeed don't need it anymore. Let me know if this is the case and I'll update the answer. Thanks for the heads up! – Piro Feb 25 '14 at 07:34
  • 1
    @Piro I was thinking about editing your answer too. Multipart entity is depreciated along with the string body version that you are using. The reason I am not editing is because i couldnot bind all data in namevaluepairs as you have done. – Illegal Argument Feb 25 '14 at 07:42
  • @IllegalArgument Alright, I'll look into it and see what has been changed. Thanks! – Piro Feb 25 '14 at 07:59
  • 1
    MultipartEntity deprecated use MultipartEntityBuilder. – Muhammad Babar Mar 27 '14 at 07:57
  • its giving filenotfoundexception .. please tell me how to pass the sdcard image – Kailash Dabhi Apr 04 '14 at 10:49
  • hi any one can provide some help i need to upload both profile image file and basic details to server using post methode please help me – Harsha Jan 03 '15 at 06:09
  • 1
    @Harsha just pass those details in as nameValuePairs. Only the one named 'image' will be treated as a file. Also, A THOUSAND TIMES UPVOTED!!! – Jimbali Jan 09 '15 at 19:25
15

Version 4.3.5 Updated Code

  • httpclient-4.3.5.jar
  • httpcore-4.3.2.jar
  • httpmime-4.3.5.jar

Since MultipartEntity has been deprecated. Please see the code below.

String responseBody = "failure";
HttpClient client = new DefaultHttpClient();
client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);

String url = WWPApi.URL_USERS;
Map<String, String> map = new HashMap<String, String>();
map.put("user_id", String.valueOf(userId));
map.put("action", "update");
url = addQueryParams(map, url);

HttpPost post = new HttpPost(url);
post.addHeader("Accept", "application/json");

MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setCharset(MIME.UTF8_CHARSET);

if (career != null)
    builder.addTextBody("career", career, ContentType.create("text/plain", MIME.UTF8_CHARSET));
if (gender != null)
    builder.addTextBody("gender", gender, ContentType.create("text/plain", MIME.UTF8_CHARSET));
if (username != null)
    builder.addTextBody("username", username, ContentType.create("text/plain", MIME.UTF8_CHARSET));
if (email != null)
    builder.addTextBody("email", email, ContentType.create("text/plain", MIME.UTF8_CHARSET));
if (password != null)
    builder.addTextBody("password", password, ContentType.create("text/plain", MIME.UTF8_CHARSET));
if (country != null)
    builder.addTextBody("country", country, ContentType.create("text/plain", MIME.UTF8_CHARSET));
if (file != null)
    builder.addBinaryBody("Filedata", file, ContentType.MULTIPART_FORM_DATA, file.getName());

post.setEntity(builder.build());

try {
    responseBody = EntityUtils.toString(client.execute(post).getEntity(), "UTF-8");
//  System.out.println("Response from Server ==> " + responseBody);

    JSONObject object = new JSONObject(responseBody);
    Boolean success = object.optBoolean("success");
    String message = object.optString("error");

    if (!success) {
        responseBody = message;
    } else {
        responseBody = "success";
    }

} catch (Exception e) {
    e.printStackTrace();
} finally {
    client.getConnectionManager().shutdown();
}
AZ_
  • 21,688
  • 25
  • 143
  • 191
11

The loopj library can be used straight-forward for this purpose:

SyncHttpClient client = new SyncHttpClient();
RequestParams params = new RequestParams();
params.put("text", "some string");
params.put("image", new File(imagePath));

client.post("http://example.com", params, new TextHttpResponseHandler() {
  @Override
  public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
    // error handling
  }

  @Override
  public void onSuccess(int statusCode, Header[] headers, String responseString) {
    // success
  }
});

http://loopj.com/

vonox7
  • 1,081
  • 13
  • 24
5

I struggled a lot trying to implement posting a image from Android client to servlet using httpclient-4.3.5.jar, httpcore-4.3.2.jar, httpmime-4.3.5.jar. I always got a runtime error. I found out that basically you cannot use these jars with Android as Google is using older version of HttpClient in Android. The explanation is here http://hc.apache.org/httpcomponents-client-4.3.x/android-port.html. You need to get the httpclientandroidlib-1.2.1 jar from android http-client library. Then change your imports from or.apache.http.client to ch.boye.httpclientandroidlib. Hope this helps.

DavidC
  • 185
  • 2
  • 10
-14

I usually do this in the thread handling the json response:

try {
  Bitmap bitmap = BitmapFactory.decodeStream((InputStream)new URL(imageUrl).getContent());
} catch (MalformedURLException e) {
  e.printStackTrace();
} catch (IOException e) {
  e.printStackTrace();
}

If you need to do transformations on the image, you'll want to create a Drawable instead of a Bitmap.