Saturday 13 June 2015

Sending an image from an android app to a webserver


I thought to start with this topic because when I first started programming for android, this problem took a lot of time, so I thought to share this piece with all of you.

I have used httpmime-4.1 jar  in the android application to enable sending of the images.

It requires just three steps.

First, create a new android application and paste the below code in your activity_main.xml.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/iv_image"
        android:layout_width="wrap_content"
        android:layout_height="350dp"
        android:scaleType="centerCrop" />

    <ProgressBar
        android:id="@+id/pb_load"
        style="?android:attr/progressBarStyleLarge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />

    <Button
        android:id="@+id/btn_upload"
        android:layout_width="180dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="8dp"
        android:text="@string/upload"
        android:textSize="20sp" />

</LinearLayout>
Second, use the below code in your MainActivity.java


 public class MainActivity extends Activity {  
      private Bitmap bitmap;  
      private ImageView imageView;  
      private Button uploadButton;  
      private ProgressBar spinner;  
      @Override  
      protected void onCreate(Bundle savedInstanceState) {  
           super.onCreate(savedInstanceState);  
           setContentView(R.layout.activity_main);  
           spinner = (ProgressBar) findViewById(R.id.pb_load);  
           spinner.setVisibility(View.GONE);  
           InputStream is = getResources().openRawResource(R.drawable.cat);  
           bitmap = BitmapFactory.decodeStream(is); // This gets the image  
           // bitmap = BitmapFactory  
           // .decodeFile("/storage/emulated/0/DCIM/Camera/IMG_02.jpg");  
           imageView = (ImageView) findViewById(R.id.iv_image);  
           imageView.setImageBitmap(bitmap);  
           uploadButton = (Button) findViewById(R.id.btn_upload);  
           // CompressFormat set up to JPG, you can change to PNG or whatever you  
           // want;  
           // To send compressed image through the network,Write a compressed  
           // version of the  
           // bitmap to the specified ByteArray OutputStream.  
           ByteArrayOutputStream bos = new ByteArrayOutputStream();  
           bitmap.compress(Bitmap.CompressFormat.JPEG, 60, bos);  
           final byte[] data = bos.toByteArray();  
           uploadButton.setOnClickListener(new View.OnClickListener() {  
                @Override  
                public void onClick(View v) {  
                     // Create a media file name  
                     String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",  
                     Locale.ENGLISH).format(new Date());  
                     // Creates a new ByteArrayBody with byte array content and file  
                     // name  
                     ByteArrayBody bdb = new ByteArrayBody(data, "temp_" + timeStamp + ".jpg");  
                     new SendImageTask().execute(bdb);  
                }  
           });  
      }  
      private class SendImageTask extends AsyncTask < ByteArrayBody, Void, String > {  
           @Override  
           protected void onPreExecute() {  
                // To show the progress circle while uploading image  
                spinner.setVisibility(View.VISIBLE);  
                uploadButton.setVisibility(View.GONE);  
           }  
           protected String doInBackground(ByteArrayBody...params) {  
                String responseBody;  
                try {  
                     HttpClient httpClient = new DefaultHttpClient();  
                     HttpContext localContext = new BasicHttpContext();  
                     // here, change it to your api ;  
                     HttpPost httpPost = new HttpPost(  
                          "http://192.168.1.114:8080/upload");  
                     MultipartEntity entity = new MultipartEntity(  
                     HttpMultipartMode.BROWSER_COMPATIBLE);  
                     // sending a String param;  
                     entity.addPart("myParam", new StringBody("myValue"));  
                     // sending an Image;  
                     entity.addPart("myImage", params[0]);  
                     httpPost.setEntity(entity);  
                     HttpResponse response = httpClient.execute(httpPost,  
                     localContext);  
                     int httpStatusCode = response.getStatusLine().getStatusCode();  
                     Log.d(" http status: ", "" + httpStatusCode);  
                     if (HttpStatus.SC_OK == httpStatusCode) {  
                          responseBody = EntityUtils.toString(response.getEntity());  
                          return responseBody;  
                     } else {  
                          Log.d("unhandled httpStatusCode: ", "" + httpStatusCode);  
                          // Closes the connection.  
                          // Returns a content stream of the entity.  
                          response.getEntity().getContent().close();  
                          throw new IOException(response.getStatusLine()  
                               .getReasonPhrase());  
                     }  
                } catch (ClientProtocolException e) {  
                     return e.getMessage().toString();  
                } catch (IOException e) {  
                     return e.getMessage().toString();  
                }  
           }  
           protected void onPostExecute(String result) {  
                spinner.setVisibility(View.GONE);  
                uploadButton.setVisibility(View.VISIBLE);  
                Toast.makeText(getApplicationContext(), "Output: " + result,  
                Toast.LENGTH_SHORT).show();  
           }  
      }  
 }  

Your android application is ready to send image.

Now, in step three, write the script to run in your server or localhost to accept and save the image and expose that API to your android application.

Below is a python script using bottle framework :


from bottle import get, post, request,run,os # or route

def get_save_path_for_category():
    return "/home/uploadhere"

@get('/upload') #
def login():
    return '''
        <form action="/upload" method="post" enctype="multipart/form-data">
            Category:      <input type="text" name="category" />
            Select a file: <input type="file" name="myImage" />
            <input type="submit" value="Start upload" />
        </form>
    '''

@post('/upload')  # or @route('/upload', method='POST')
def do_upload():
    #category   = request.forms.get('category')
    upload     = request.files.get('myImage')
    name, ext = os.path.splitext(upload.filename)
    if ext not in ('.png','.jpg','.jpeg'):
        return 'File extension not allowed.'

    save_path = get_save_path_for_category()
    if not os.path.exists(save_path):
        os.makedirs(save_path)
    upload.save(save_path,overwrite=True) # appends upload.filename automatically
    return "File successfully saved to '{0}'.".format(save_path)

run(host='192.168.1.114', port=8080, debug=True)

You are done here.