Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reduce size of picture before post

I have a function to send a file (picture from camera or gallery) to a WebService. I would like to reduce the image size of fileUri before post (50% per example). The file is a gallery or camera image.

This is my postFile function :

public static void postFile(Context context, String url, String fileUri, AsyncHttpResponseHandler responseHandler) {
    if (myCookieStore == null)
    {
        myCookieStore = new PersistentCookieStore(context);
        client.setCookieStore(myCookieStore);
    }

    File myFile = new File(Uri.parse(fileUri).getPath());

    RequestParams params = new RequestParams();
    try {
        params.put("profile_picture", myFile);
    } catch(FileNotFoundException e) {
        Log.d("error", "error catch");
    }
    Log.d("absolute url", "" + "*" + getAbsoluteUrl(url) + "*");
    client.post(context, getAbsoluteUrl(url), params, responseHandler);
}

How can I do that ?

like image 379
Jéwôm' Avatar asked Apr 11 '17 10:04

Jéwôm'


2 Answers

There is this library, that can compress your images to kb from mb, it is very powerful i have used it alot of times, it works file uploads are superfast. link

Snippet : compressedImageFile = Compressor.getDefault(this).compressToFile(actualImageFile);

It internally uses google webp format, WebP is a modern image format that provides superior lossless and lossy compression for images on the web. Using WebP, webmasters and web developers can create smaller, richer images that make the web faster.

The library is great at size compression, it does a really good job, at large files that was based on my observations, like 2mb up, however there are some memory leaks that you need to address, i solved mine by using leak canary , though every developer should always use it. Overall it is awesome fork it and use as please.

like image 136
Remario Avatar answered Oct 19 '22 13:10

Remario


I used this code in many projects and always it gives me good results, i remember if i choose a image having size of 5-7MB(image from 12/13 MP camera) this code returns an image of size 1MB or less than 2MB.

public static boolean validateUri(Uri uri) {
        if (uri == null)
            return false;
        else {
            String path = uri.getPath();
            return !(uri.equals(Uri.EMPTY) || path == null || path.equals("null"));
        }
    }

First we need a full image and rotate if needed.

public static Bitmap getFullSizeImage(Context context, Uri uri) {
        String filePath;
        if (validateUri(uri) && uri.toString().contains("file"))
            filePath = uri.getPath();
        else
            filePath = getRealPathFromURI(context, uri, MediaStore.Images.Media.DATA);
        if (filePath == null)
            return null;
        try {
            int rotation = 0;
            ExifInterface exifInterface = new ExifInterface(filePath);
            int exifRotation = exifInterface.getAttributeInt(
                    ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_UNDEFINED);
            if (exifRotation != ExifInterface.ORIENTATION_UNDEFINED) {
                switch (exifRotation) {
                    case ExifInterface.ORIENTATION_ROTATE_180:
                        rotation = 180;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_270:
                        rotation = 270;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_90:
                        rotation = 90;
                        break;
                }
            }
            Matrix matrix = new Matrix();
            matrix.setRotate(rotation);
            // you can use other than 400 as required width/height
            Bitmap sourceBitmap = getBitmapFromPath(400, filePath);
            if (sourceBitmap == null)
                return null;
            return Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(),
                    sourceBitmap.getHeight(), matrix, true);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

Now we need a real path from URI

public static String getRealPathFromURI(Context context, Uri contentUri, String type) {
        Cursor cursor = null;
        String path = null;
        try {
            // String[] proj = { MediaStore.Images.Media.DATA };
            String[] projection = {type};
            cursor = context.getContentResolver().query(contentUri, projection, null, null, null);
            if (cursor == null)
                return null;
            int columnIndex = cursor.getColumnIndexOrThrow(type);
            cursor.moveToFirst();
            path = cursor.getString(columnIndex);
            // we choose image from drive etc.
            if (path == null)
                path = getDocumentRealPathFromUri(context, contentUri);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return path;
    }

If we choose a picture from drive etc. we still need a real path of given URI

public static String getDocumentRealPathFromUri(Context context, Uri contentUri) {
        Cursor cursor = context.getContentResolver().query(contentUri, null,
                null, null, null);
        if (cursor == null)
            return null;
        cursor.moveToFirst();
        String documentId = cursor.getString(0);
        documentId = documentId.substring(documentId.lastIndexOf(":") + 1);
        cursor.close();
        cursor = context.getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                null, MediaStore.Images.Media._ID + " = ? ",
                new String[]{documentId}, null);
        if (cursor == null)
            return null;
        cursor.moveToFirst();
        String path = cursor.getString(cursor
                .getColumnIndex(MediaStore.Images.Media.DATA));
        cursor.close();
        return path;
    }

Now we've a real path of selected image so we can get a bitmap from this path using sample size

public static Bitmap getBitmapFromPath(int size, String realPathFromURI) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(realPathFromURI, options);
        options.inSampleSize = calculateInSampleSizeUsingPower2(options, size, size);
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(realPathFromURI, options);
    }

    public static int calculateInSampleSizeUsingPower2(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        if (height > reqHeight || width > reqWidth) {
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;
            // calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth)
                inSampleSize *= 2;
        }
        return inSampleSize;
    }

At this point we've a compressed bitmap, further more we can again compress this bitmap if we perform Base64 operation on a given bitmap.

public static String convertToBase64(Bitmap bitmap) {
        if (bitmap == null)
            return null;
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)) {
            String base64 = encodeToString(byteArrayOutputStream.toByteArray(), DEFAULT);
            try {
                byteArrayOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return base64;
        }
        return null;
    }

On your sever end you can decode Base64 and convert back to file stream and save your image.

Example

Bitmap bitmap = getFullSizeImage(context, selectedPhotoUri);
if(bitmap != null){
    String base64Image = convertToBase64(bitmap);
    if (base64Image != null) {
        RequestParams params = new RequestParams();
        try {
            params.put("title", "your_image_name");
            params.put("profile_picture", base64Image);
        } catch(FileNotFoundException e) {
            Log.d("error", "error catch");
        }
    }
}

Note If you don't want to perform Base64 you can use your bitmap to convert into stream and send it to your server.

like image 1
Haris Qurashi Avatar answered Oct 19 '22 11:10

Haris Qurashi