How to send image data to server from Android

11,355

Solution 1

You just need to do a Http-FileUpload which in a special case of a POST. There is no need to uuencode the file. No need to use a special lib/jar No need to save the object to disk (regardless that the following example is doing so)

You find a very good explanation of Http-Command and as your special focus "file upload" under

Using java.net.URLConnection to fire and handle HTTP requests

The file upload sample from there follows (watch "send binary file") and it is possible to add some companion data either


String param = "value";
File textFile = new File("/path/to/file.txt");
File binaryFile = new File("/path/to/file.bin");
String boundary = Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value.
String CRLF = "\r\n"; // Line separator required by multipart/form-data.

URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
PrintWriter writer = null;
try {
    OutputStream output = connection.getOutputStream();
    writer = new PrintWriter(new OutputStreamWriter(output, charset), true); // true = autoFlush, important!

    // Send normal param.
    writer.append("--" + boundary).append(CRLF);
    writer.append("Content-Disposition: form-data; name=\"param\"").append(CRLF);
    writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
    writer.append(CRLF);
    writer.append(param).append(CRLF).flush();

    // Send text file.
    writer.append("--" + boundary).append(CRLF);
    writer.append("Content-Disposition: form-data; name=\"textFile\"; filename=\"" + textFile.getName() + "\"").append(CRLF);
    writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
    writer.append(CRLF).flush();
    BufferedReader reader = null;
    try {
        reader = new BufferedReader(new InputStreamReader(new FileInputStream(textFile), charset));
        for (String line; (line = reader.readLine()) != null;) {
            writer.append(line).append(CRLF);
        }
    } finally {
        if (reader != null) try { reader.close(); } catch (IOException logOrIgnore) {}
    }
    writer.flush();

    // Send binary file.
    writer.append("--" + boundary).append(CRLF);
    writer.append("Content-Disposition: form-data; name=\"binaryFile\"; filename=\"" + binaryFile.getName() + "\"").append(CRLF);
    writer.append("Content-Type: " +     URLConnection.guessContentTypeFromName(binaryFile.getName()).append(CRLF);
    writer.append("Content-Transfer-Encoding: binary").append(CRLF);
    writer.append(CRLF).flush();
    InputStream input = null;
    try {
        input = new FileInputStream(binaryFile);
        byte[] buffer = new byte[1024];
        for (int length = 0; (length = input.read(buffer)) > 0;) {
            output.write(buffer, 0, length);
        }
        output.flush(); // Important! Output cannot be closed. Close of writer will close output as well.
    } finally {
        if (input != null) try { input.close(); } catch (IOException logOrIgnore) {}
    }
    writer.append(CRLF).flush(); // CRLF is important! It indicates end of binary boundary.

    // End of multipart/form-data.
    writer.append("--" + boundary + "--").append(CRLF);
} finally {
    if (writer != null) writer.close();
}

Regarding the second part of your question. When successful uploading the file (I use apache common files), it is not a big deal to deliver a blob as an image.

This is how to accept a file in a servlet

public void doPost(HttpServletRequest pRequest, HttpServletResponse pResponse)
        throws ServletException, IOException {
    ServletFileUpload upload = new ServletFileUpload();

    try {
        FileItemIterator iter = upload.getItemIterator (pRequest);

        while (iter.hasNext()) {
            FileItemStream item = iter.next();

            String fieldName = item.getFieldName();

                InputStream stream = item.openStream();
            ....
                stream.close();
            }
    ...

And this code delivers an image

public void doGet (HttpServletRequest pRequest, HttpServletResponse pResponse)  throws IOException {

    try {
        Blob img = (Blob) entity.getProperty(propImg);

        pResponse.addHeader ("Content-Disposition", "attachment; filename=abc.png");
        pResponse.addHeader ("Cache-Control", "max-age=120");

        String enc = "image/png";
        pResponse.setContentType (enc);
        pResponse.setContentLength (img.getBytes().length);
        OutputStream out = pResponse.getOutputStream ();
        out.write (img.getBytes());
        out.close();

I hope this code fragments help to answer your questions

Solution 2

1.You can encode the byte[] to base64 using:

http://commons.apache.org/codec/apidocs/org/apache/commons/codec/binary/Base64.html

2.Send that data with a HTTP POST request to your AppEngine servlet.

3.Configure AppEngine to accept a servlet.

4.Then you have the choice to save it to the Datastore or the Blobstore. -I prefer the blobstore for these kinds of things.

5.Decode the base64 string server side.

6.From there on you'l need to cut up your string into smaller pieces and write each piece to the blobstore.

Here's some code for writing it to the blobstore.

byte[] finalImageArray = null;

    try {
        finalImageArray = Base64.decode(finalImageData.getBytes()); //finalImageData is the string retrieved from the HTTP POST
    } catch (Base64DecoderException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }


    try{
        FileService fileService = FileServiceFactory.getFileService();

        AppEngineFile file = fileService.createNewBlobFile("image/png");

        FileWriteChannel writeChannel = fileService.openWriteChannel(file, true);

        int steps = (int) Math.floor(finalImageArray.length/1000);
        int current = 0;
        for(int i = 0; i < 1000; i++){
            writeChannel.write(ByteBuffer.wrap(Arrays.copyOfRange(finalImageArray, current, steps+current)));
            current = current + steps;
        }
        writeChannel.write(ByteBuffer.wrap(Arrays.copyOfRange(finalImageArray, current, finalImageArray.length)));  //The reason it's cut up like this is because you can't write the complete string in one go.

        writeChannel.closeFinally();

        blobKey = fileService.getBlobKey(file);

        if(blobKey == null)
            blobKey = retryBloBKey(file); //My own method, AppEngine tends to not return the blobKey once a while.

    }
    catch(Exception e){
        logger.log(Level.SEVERE,e.getMessage());
    }


            return blobKey.getKeyString();
  1. Write a servlet where you retrieve the image data with the provided key.

  2. Enjoy your beautiful code :)

//The reason i save it in binary is because that gives me options to play with the image api, you can also choose to save it in the base64 format.

Solution 3

As code is provided by three person so you can select any of them(or you will get a lot of example on google). There are three possiblity 1)first you have image in your sdcard

2)you are downloading image from server and then sending

3)Images are store in DataBase as blob

The best approach considering each case-

1)If your Image is store in sdcard then simply fecth image Convert into bitmap ->byteArray ->String and send to server

2)If you are downloading images from server and then sending to another URL.Then download all image URL store in DataBase Table.Later on when you need to send to server fetch url,download image and store in cache memory.then similarly send it server and refresh cache memory

3)Its recommend not to store a lot of image in DB.But in case you have neccessity of doing it then getBlob convert into byte array and send to server

Sending Image To server

Reading blob

Reading from sdcard

List<Integer> drawablesId = new ArrayList<Integer>();
int picIndex=12345;
 File sdDir = new File("/sdcard/pictures");
File[] sdDirFiles = sdDir.listFiles();
for(File singleFile : sdDirFiles)
{
Drawable.createFromPath(singleFile.getAbsolutePath());
/ you can create Bitmap from drawable
 }

Hope it will help you

Solution 4

Not exactly sure if this is what you want but this will submit an image in the same way that your browser would submit an image as part of a form. You will have to download httmime-4.1.3.jar and add it as a referenced library in your project.

        Bitmap bm;//whatever bitmap you are trying to send
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        bm.compress(CompressFormat.JPEG, 75, bos);
        byte[] data = bos.toByteArray();
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost postRequest = new HttpPost("http://yourwebsite.com/whatever");
        ByteArrayBody bab = new ByteArrayBody(data, "image name");
        MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
        reqEntity.addPart("photo", bab);//"photo" is the name of the field that the image is submitted as.
        postRequest.setEntity(reqEntity);
        try {
            HttpResponse response = httpClient.execute(postRequest);
        } catch (ClientProtocolException e) {
            Log.e("asdf", e.getMessage(), e);
        } catch (IOException e) {
            Log.e("asdf", e.getMessage(), e);
        }

Solution 5

  1. The Android Asynchronous Http library provides a method of uploading files to a web service. I've used it in my projects with great success.

  2. Sounds like you need a web service method that takes an ID parameter and returns a file. You would store your blobs in the database table indexed with ID so that they can be referenced.

Share:
11,355
mstath
Author by

mstath

Updated on June 15, 2022

Comments

  • mstath
    mstath almost 2 years

    I am trying to write an Android application that will take a picture, put the data (byte[]) in an object along with some metadata, and post that to an AppEngine server where it will get persisted in a datastore as a blob. I don't really want to save the image as a file on Android (unless it's absolutely necessary). I searched around for solutions but nothing clear or specific enough came up. My questions are:

    1. how do I post the object to my servlet? Specifically how to properly serialize the object and get the serialized output to an HttpPost or something similar.
    2. once I persist the blob in the datastore, how will I be able to retrieve it as an image to display on a webpage?

    Code examples would be very helpful. Also, if the approach I am taking is too complicated or problematic, please suggest other approaches (e.g. saving image as file, posting to server, then deleting).