您的位置:首页 > 移动开发

Whatsapp like Image Compression in Android with demo Ambalika Saha June 28, 2013

2015-11-06 10:34 1176 查看
from: http://voidcanvas.com/whatsapp-like-image-compression-in-android/




JavaScript

jQuery

Ember.js

Node.js

React.js

Angular.js

ECMA Script 6

Polymer.js

Css

Products

Smartjax.js

3dEye.js

PairSelect.js

Tips n Tricks

Random

Tutorial

News

Advertise With US

Contact Us

Whatsapp like Image Compression in Android with demo

Ambalika Saha June 28, 2013

The images captured by the recent cameras often exceed 2 MB. Using such images frequently results in OutOfMemoryError. Also, due to landscape/portrait orientation, the images often are displayed as rotated. To deal with these issues we need to compress the
image and give proper rotation before loading it to memory. The following method compresses image (similar to whatsapp), while maintaining its aspect ratio and also preventing significant loss to its quality.

A demo project implementing this compression can be downloaded from
here.

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;

}

The method getFilename():: It creates a folder in the SDCard used to store the 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;

}

The method getRealPathFromURI(imageUri):: Gives the actual filepath of the image 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 method calculateInSampleSize:: calculates a proper value for inSampleSize based on the actual and required dimensions:

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;
}


Tweet



Article by Ambalika Saha

Ambalika, Currently working as a software developer is a B.Tech in Computer Science.

Related Posts



Steps to Improve the Performance of Web Application



3dEye.js, a plugin to create 360 degree 3d panoramic...

Rakesh Rocky

thanks Ambalika Saha. Very useful one. Can u please tell me the exact ratio or pixel of compression, i mean the rate of compression. thanks again. mail me at
rakeshsundar@rocketmail.com

ambalika saha

In this approach, the max height and width of the output image is maintained at around 800px and 600px respectively [float maxHeight = 816.0f; float maxWidth = 612.0f;] The final height and width are decided depending upon the aspect ratio(width:height)
of the image. The extent of compression required to achieve this ia calculated by the method “calculateInSampleSize”. The method returns an integer value “inSampleSize”. This “inSampleSize” decides the extent of compression. For example if inSampleSize=2,
the image will be compressed to half; inSampleSize = 4 means the image the will be compressed to one-fourth. So when we are loading the image from the path, it loads a scaled down version.

Rakesh Rocky

wow! thanks. this will be very helpful in my project.

Rakesh Rocky

by the way, whats ur opinion about this code, developed by me:

Bitmap bitmap = ((BitmapDrawable)myicon).getBitmap();

int h=bitmap.getHeight(); //can be of float type too

int w=bitmap.getWidth();

h=h/4; //depends on compression rate/file size/pixels (dynamic)

w=w/4; //like inSampleSize in ur code

bitmap=Bitmap.createScaledBitmap(bitmap, w,h , true);

in this case the image will be compressed to 1/4th. this code maintains aspect ratio and also prevents significant loss to quality.

ambalika saha

Yeah!!! This approach too is right, infact lot simple, but it depends upon your requirements. “createScaledBitmap” is no doubt a wonder function but sometimes in applications that deals with hundreds of images, it may give that dreaded “outOfMemory” error.
Also if you zoom an image created by “createdScaledBitmap” the distortion is awfully visible. So, it all depends upon your necessity and functionality.

Rakesh Rocky

thank u. can u pls help me one more time. my project also requires video conferencing. how can i achieve video conferencing in android? Any advice will b very useful…

anand chavan

Anand chavan

Raman Kumar Sharma

Hello Ambalika,

Thanks for a useful tutorial.

Can you please tell me how to compress the video.

mail me at sahil0shrma@gmail.com

Hemant Chand Dungriyal

above method works fine except crop the height when image orientation is 270 and 90 degree. So is there any solution for prevent cropping image

Hemant Chand Dungriyal

Hi Ambalika,

issue on matrix. When orientation is 90 and 270 degree then it rotate the image with cut upper and lower section.

Venkat

Very nice post, but i have one exception from getRealPathFromURI – it says Failed to read row 0, column -1 from a CursorWindow

Rudresh Agarwal

Hello Ambika, I am a part of a startup organisation working on a product to help teachers communicate with students better via images, video and audio using mobile apps. We would require your help regarding compression technology. Please do reply soon.

Hrithik r

In few devices when I take picture from camera actualHeight,actualHeight are being returned as null.

int actualHeight = options.outHeight; // null

int actualHeight = options.outWidth; // null

Any work around for this ?

James

good Jobs!! god bless u


sarath kumar

Thanks @ambalikasaha:disqus Is it possible to compress video files using same technique without loss quality

Sanket Patel

Thanks Ambika for such a useful post.

I am using your code in my project. But i am getting a problem if i select 5 images from Gallery>Camera, and try to call your method compressImage() for those 5 image paths. OutOfMemoryError occurred at bellow code.

try

{

scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Bitmap.Config.ARGB_8888);

} catch (OutOfMemoryError exception) {

exception.printStackTrace();

}

And because of this application doesn’t works properly. Could you please help me?

Pratham Bane

Which video compression technique used by whatsapp,viber,hike,line.??

Pratham Bane

Which Video compression technique used by whatsapp, line,viber,hike??

Tamanna Khan

I downloaded your project but it is giving error at : Uri contentUri = Uri.parse(contentURI);

Tejas

Hello Ambalika,

You have not provided any comments for the Canvas object that is used. What does that part of code do ?

Sergii Z.

it seems that better to use :

float imgRatio = actualWidth / *(float)* actualHeight;

otherwise you’ll get wrong result of division?

hon lung lhimark lau

Is it possible to show the compressed images in Gallery?

Great if you would share the methodology as well

Stefano Occhi

It’s a fantastic sample! Thanks! Can we “return” to the original full size image?

rudresh sp

hello Ambika, i want to re size an image using fingers onTouch, i mean zoom in and out and re size the image ,also set max zoom in , zoom out value..but image not supposed to move

pls help me rudresh.soft@gmail.com,

Neeraj Singh

Best Thanks Its Work for me as i aspect.

Shivam Pasricha

Thanks it was very helpfull example alot thanks

Nsereko Louis

i have tried to change the bitmap to a base64 string and send it to the server as a string. but on decoding it fails, why could this be

Shrey Promact

This is really good work on Image compression. I really appreciate it. I have one suggestion. I also need video compression as whats app do. Please provide me any link or guide for video compression if you have.

Thanks a lot.






Recent Posts

Angular 2.0 tutorial: templates with working examples
Scaffold and make “Hello World” with
AngularJs 2 – TypeScript and plain JavaScript
What’s new in Angular 2.0? Why it’s rewritten – addressing few confusions
Setup and configure NGINX in aws EC2 linux/ubuntu instance
How to take commits from a different repository : Git cherry-pick & format-patch
Introduction to ECMA Script 6 – New features with examples
Timezone specific / local string to local Date object in JavaScript
Repeat youtube in loop – No page refresh or multi load – no browser plugin or 3rd
party site
ECMA Script 6 variable declaration with var, let & const – let vs var
ES6 Playgrounds: Run and test ECMA Script 6 online, in terminal or using plugins

© 2015
Void Canvas | All Rights Reserved.
Back to Top ↑
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: