Abdul Fatir
Abdul Fatir

Reputation: 6357

Upload Large Image in Base64 to Server

I take a picture using the android.hardware.Camera API. I then convert it to a Bitmap of half the actual size, compress it to a JPEG of quality 80, convert it to Base64 and send it to the server as follows.

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream.toByteArray();
String encoded = Base64.encodeToString(byteArray, Base64.NO_WRAP);
String json_response = "";

try {
    URL url = new URL("https://example.com/api_endpoint");
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setReadTimeout(15000);
    conn.setConnectTimeout(15000);
    conn.setRequestMethod("POST");
    conn.setDoInput(true);
    conn.setDoOutput(true);
    OutputStream os = conn.getOutputStream();
    BufferedWriter writer = new BufferedWriter(
            new OutputStreamWriter(os, "UTF-8"));
    writer.write("?reg=" + regCode);
    writer.write("&img=" + encoded);
    writer.flush();
    writer.close();
    os.close();
    Log.d("Auth", conn.getResponseCode() + "");
    InputStreamReader in = new InputStreamReader(conn.getInputStream());
    BufferedReader br = new BufferedReader(in);
    String text = "";
    while ((text = br.readLine()) != null) {
        json_response += text;
    }
    conn.disconnect();
} catch (IOException e) {
    Log.d(getClass().getName(), "" + e.getMessage());
}  

This works as expected. Now, If I don't resize the image and keep the quality 100%, how should I go about to avoid an OutOfMemoryError? My application requires the image to be in the full resolution and best quality possible.

My questions are:

  1. Is the way I am uploading the correct way?
  2. How to send Image is best quality without OutOfMemoryError i.e. how to optimize RAM usage in this process?

Upvotes: 0

Views: 4697

Answers (3)

GensaGames
GensaGames

Reputation: 5788

I think problem not with downloading to server. If I understand correctly, you getting image from camera and sending it. Note, that if you using simple request intent, that returns in onActivityResult() - Bitmap Image - this may be point of OutOfMemoryException...

Solution it's use another form on Intent() method, (that can get storage path in his parameters) for getting photo from camera, that doesn't return Bitmap image. But save photo to path, which you specified. And now you can do anything with photo in path, without OutOfMemoryException...

Sample starting correct Intent:

File destination = new   File(Environment.getExternalStorageDirectory(),
                             "image.jpg");

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                 intent.putExtra(MediaStore.EXTRA_OUTPUT,
                 Uri.fromFile(destination));
startActivityForResult(intent, CAMERA_PICTURE);

Let me know, this helps...

Upvotes: 0

toantran
toantran

Reputation: 1819

If you have the control over the API endpoint. Then try to implement the POST request to accept multi-part uploading from client side.

On client-side, have something like this to upload the image to API (with Okhttp client)

  private static final String IMGUR_CLIENT_ID = "...";
  private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");

  private final OkHttpClient client = new OkHttpClient();

  public void run() throws Exception {
    // Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
    RequestBody requestBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("title", "Square Logo")
        .addFormDataPart("image", "logo-square.png",
            RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
        .build();

    Request request = new Request.Builder()
        .header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
        .url("https://api.imgur.com/3/image")
        .post(requestBody)
        .build();

    Response response = client.newCall(request).execute();
    if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

    System.out.println(response.body().string());
  }

Upvotes: 1

John Pangilinan
John Pangilinan

Reputation: 1031

Here is my image/file uploader class:

public class ImageUploader extends AsyncTask<String, String, String> {

    File imageFile = null;
    String fileName = null;

    public ImageUploader(File imageFile, String fileName){
        this.imageFile = imageFile;
        this.fileName = fileName;
    }

    @Override
    protected String doInBackground(String... params) {
        String url_str = params[0];

        String lineEnd = "\r\n";
        String twoHyphens = "--";
        String boundary = "*****";
        String Tag="fSnd";

        try {
            URL url = new URL(url_str);
            HttpURLConnection c = (HttpURLConnection) url.openConnection();

            c.setRequestMethod("POST");

            c.setDoInput(true);
            c.setDoOutput(true);

            c.setRequestProperty("Connection", "Keep-Alive");
            c.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);

            c.connect();

            DataOutputStream dos = new DataOutputStream(c.getOutputStream());

            dos.writeBytes(twoHyphens + boundary + lineEnd);
            dos.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\"" + this.fileName + "\"" + lineEnd);
            dos.writeBytes(lineEnd);

            FileInputStream fin = new FileInputStream(imageFile);

            int bytesAvailable = fin.available();

            int maxBufferSize = 1024;
            int bufferSize = Math.min(bytesAvailable, maxBufferSize);
            byte[ ] buffer = new byte[bufferSize];

            int bytesRead = fin.read(buffer, 0, bufferSize);

            while (bytesRead > 0)
            {
                dos.write(buffer, 0, bufferSize);
                bytesAvailable = fin.available();
                bufferSize = Math.min(bytesAvailable,maxBufferSize);
                bytesRead = fin.read(buffer, 0,bufferSize);
            }


            dos.writeBytes(lineEnd);
            dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

            fin.close();
            dos.flush();
            dos.close();

            StringBuilder response = new StringBuilder();
            BufferedReader reader = new BufferedReader(new InputStreamReader(c.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }

            return response.toString();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (ProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {

        }

        return null;
    }
}

Usage:

new ImageUploader(pictureFile, "sample.jpg"){
    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        Toast.makeText(getApplicationContext(), s, Toast.LENGTH_LONG).show();
    }
}.execute("http://example/upload.php");

PHP:

<?php
    $file = explode('.', $_FILES['file']['name']);
    $ext = $file[count($file) - 1];
    $name = substr($_FILES['file']['name'], 0, (strlen($ext) + 1) * -1);
    $location = 'images/';
    $cntr = 1;
    $tmp_name = $name;
    if(move_uploaded_file($_FILES['file']['tmp_name'], $location.$tmp_name.'.'.$ext)){
        echo "Image was uploaded.";
    }else{
        echo "Image was not uploaded.";
    }
?>

Upvotes: 2

Related Questions