Reduce image size before publishing

I have a function to send a file (camera or gallery image) to WebService. I would like to reduce the fileUri image fileUri before publishing (50% for example). A file is an image of a gallery or camera.

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 this?

+5
source share
7 answers

There is this library that can compress your images to kb with mb, it is very powerful, I used it many times, it works, downloading files is super-fast. link

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

It internally uses the google webp format, WebP is a modern image format that provides superior lossless compression and image loss for images on the Internet. Using WebP, webmasters, and web developers can create smaller, richer images that speed your browsing experience.

The library does a great job of compressing in size, it does a really good job, in large files that were based on my observations, for example, 2 MB, however there are some memory leaks that you need to address, I decided, canaries, although every developer should always use it. All in all it is an awesome plug and use as please.

+5
source

The image we captured or taken from the gallery is too large. Now the image size per day exceeds even 10 MB. Therefore, it is very important to use compressed images in the application, since we can exclude an exception from memory.

Use the code below to compress the image.

 // return file name of compressed image from imageUri public String compressImage(String imageUri) { String filePath = getRealPathFromURI(imageUri); Bitmap scaledBitmap = null; BitmapFactory.Options options = new BitmapFactory.Options(); // by setting this field as true, the actual bitmap pixels are not loaded in the memory. Just the bounds are loaded. If // you try the use the bitmap here, you will get null. options.inJustDecodeBounds = true; Bitmap bmp = BitmapFactory.decodeFile(filePath, options); int actualHeight = options.outHeight; int actualWidth = options.outWidth; // max Height and width values of the compressed image is taken as 816x612 float maxHeight = 816.0f; float maxWidth = 612.0f; float imgRatio = actualWidth / actualHeight; float maxRatio = maxWidth / maxHeight; // width and height values are set maintaining the aspect ratio of the image if (actualHeight > maxHeight || actualWidth > maxWidth) { if (imgRatio < maxRatio) { imgRatio = maxHeight / actualHeight; actualWidth = (int) (imgRatio * actualWidth); actualHeight = (int) maxHeight; } else if (imgRatio > maxRatio) { imgRatio = maxWidth / actualWidth; actualHeight = (int) (imgRatio * actualHeight); actualWidth = (int) maxWidth; } else { actualHeight = (int) maxHeight; actualWidth = (int) maxWidth; } } // setting inSampleSize value allows to load a scaled down version of the original image options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight); // inJustDecodeBounds set to false to load the actual bitmap options.inJustDecodeBounds = false; // this options allow android to claim the bitmap memory if it runs low on memory options.inPurgeable = true; options.inInputShareable = true; options.inTempStorage = new byte[16 * 1024]; try { // load the bitmap from its path bmp = BitmapFactory.decodeFile(filePath, options); } catch (OutOfMemoryError exception) { exception.printStackTrace(); } try { scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight,Bitmap.Config.ARGB_8888); } catch (OutOfMemoryError exception) { exception.printStackTrace(); } float ratioX = actualWidth / (float) options.outWidth; float ratioY = actualHeight / (float) options.outHeight; float middleX = actualWidth / 2.0f; float middleY = actualHeight / 2.0f; Matrix scaleMatrix = new Matrix(); scaleMatrix.setScale(ratioX, ratioY, middleX, middleY); Canvas canvas = new Canvas(scaledBitmap); canvas.setMatrix(scaleMatrix); canvas.drawBitmap(bmp, middleX - bmp.getWidth() / 2, middleY - bmp.getHeight() / 2, new Paint(Paint.FILTER_BITMAP_FLAG)); // check the rotation of the image and display it properly ExifInterface exif; try { exif = new ExifInterface(filePath); int orientation = exif.getAttributeInt( ExifInterface.TAG_ORIENTATION, 0); Log.d("EXIF", "Exif: " + orientation); Matrix matrix = new Matrix(); if (orientation == 6) { matrix.postRotate(90); Log.d("EXIF", "Exif: " + orientation); } else if (orientation == 3) { matrix.postRotate(180); Log.d("EXIF", "Exif: " + orientation); } else if (orientation == 8) { matrix.postRotate(270); Log.d("EXIF", "Exif: " + orientation); } scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true); } catch (IOException e) { e.printStackTrace(); } FileOutputStream out = null; String filename = getFilename(); try { out = new FileOutputStream(filename); // write the compressed bitmap at the destination specified by filename. scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out); } catch (FileNotFoundException e) { e.printStackTrace(); } return filename; } 

Method getFilename () :: It creates a folder in the SDCard used to store images.

 public String getFilename() { File file = new File(Environment.getExternalStorageDirectory().getPath(), "MyFolder/Images"); if (!file.exists()) { file.mkdirs(); } String uriSting = (file.getAbsolutePath() + "/" + System.currentTimeMillis() + ".jpg"); return uriSting; } 

Method getRealPathFromURI (imageUri) :: Gives the actual path to the image file from its contentUri ::

 private String getRealPathFromURI(String contentURI) { Uri contentUri = Uri.parse(contentURI); Cursor cursor = getContentResolver().query(contentUri, null, null, null, null); if (cursor == null) { return contentUri.getPath(); } else { cursor.moveToFirst(); int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); return cursor.getString(index); } } 

The calculateInSampleSize :: method calculates the correct value for inSampleSize based on the actual and required sizes:

 public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int heightRatio = Math.round((float) height/ (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; } final float totalPixels = width * height; final float totalReqPixelsCap = reqWidth * reqHeight * 2; while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) { inSampleSize++; } return inSampleSize; } 

Hope this helps you.

+2
source

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

 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 necessary.

 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 way from the 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 select a picture from disk, etc., we still need the real path of the 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 have a real path to the selected image, so we can get a bitmap from this path using the 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 have a compressed bitmap, and even more we can compress this bitmap again if we perform the 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 terminal, you can decode Base64 and convert it back to a 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 do not want to run Base64, you can use a bitmap to convert to a stream and send it to your server.

+1
source

Try this feature. This will reduce the size of the bitmap to 512 if its width or height is greater than 512

 public static Bitmap resizeBitmap(Bitmap bm) { if (bm.getWidth() > maxSize || bm.getHeight() > maxSize) { if (bm.getWidth() > bm.getHeight()) { newWidth = maxSize; newHeight = (bm.getHeight() * maxSize) / bm.getWidth(); bm = Bitmap.createScaledBitmap(bm, newHeight, newWidth, true); return bm; } else { newHeight = maxSize; newWidth = (bm.getWidth() * maxSize) / bm.getHeight(); bm = Bitmap.createScaledBitmap(bm, newHeight, newWidth, true); return bm; } } return bm; } 

You just need to pass the bitmap to this method.

Method for obtaining a raster image from a URI

 BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 8; bitmap = BitmapFactory.decodeFile(fileUri.getPath(), options); 
0
source

Use this option to change the width and height of the image.

 public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) { int width = bm.getWidth(); int height = bm.getHeight(); float scaleWidth = ((float) newWidth) / width; float scaleHeight = ((float) newHeight) / height; Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false); return resizedBitmap; } 

you can use this to resize ... This is the best example .....

  private Bitmap decodeFile(File f){ try { //Decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream(new FileInputStream(f),null,o); //The new size we want to scale to final int REQUIRED_SIZE=70; //Find the correct scale value. It should be the power of 2. int scale=1; while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE) scale*=2; //Decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize=scale; return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); } catch (FileNotFoundException e) {} return null; } 
0
source

If the camera image is JPEG, you can use the bitmap compression method, for example:

 Bitmap bitmap = BitmapFactory.decodeStream(...uri); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { int compression_factor = 50; // represents 50% compression bitmap.compress(Bitmap.CompressFormat.JPEG, compression_factor, baos); byte[] image = baos.toByteArray(); // now update web service asynchronously... ... } finally { baos.close(); } 
0
source

Convert image to bitmap, then use below method

  public static Bitmap scaleBitmap(Bitmap bitmap, int newWidth, int newHeight) { Bitmap scaledBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888); float scaleX = newWidth / (float) bitmap.getWidth(); float scaleY = newHeight / (float) bitmap.getHeight(); float pivotX = 0; float pivotY = 0; Matrix scaleMatrix = new Matrix(); scaleMatrix.setScale(scaleX, scaleY, pivotX, pivotY); Canvas canvas = new Canvas(scaledBitmap); canvas.setMatrix(scaleMatrix); canvas.drawBitmap(bitmap, 0, 0, new Paint(Paint.FILTER_BITMAP_FLAG)); return scaledBitmap; } 
0
source

Source: https://habr.com/ru/post/1266583/


All Articles