Rotating scaling bitmap in android quality and speed - android

I find out that when i use
createbitmap()
ONLY for rotate bitmap and after this
createscaledbitmap()
ONLY for scale in Android SDK, the values of bitmap(JPEG coeff.in my case) are changed in case of rotating image! (lower quality)
So probably i need make rotate and scale in one call function createbitmap with object Matrix. (can me somebody tell more spec. info about Math in this case? I can not find anythink)
In this code I try it, but it returns different dimensions in rotatedBitmap not the dstWidth,dstHeight ; pixelIn:ยจ
NOTE:i need only 1d data token vector, :OUTPUT
public static int[] getPixels(String pathOfInputImage, int dstWidth,
int dstHeight) {
Bitmap resizedBitmap = null;
InputStream in = null;
int[] pixelIn;
boolean filter = false;
int inWidth = 0;
int inHeight = 0;
// calculate the scale - in this case = 0.4f
try {
in = new FileInputStream(pathOfInputImage);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (in == null) {
Log.v("--------Image ERROR--------",
"Image ERROR PIXEL FileInputStream( ");
}
// decode image size (decode metadata only, not the whole image)
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
// options.inDither = true;
// options.inPreferQualityOverSpeed = true;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, options);
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
in = null;
// save width and height
inWidth = options.outWidth;
inHeight = options.outHeight;
FileInputStream in2 = null;
// decode full image pre-resized
try {
in2 = new FileInputStream(pathOfInputImage);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Options options2 = new BitmapFactory.Options();
// options.inDither = true;
// options2.inPreferQualityOverSpeed = true;
options2.inPreferredConfig = Bitmap.Config.ARGB_8888;
// calc rought re-size (this is no exact resize)
options2.inSampleSize = Math.max(inWidth / dstWidth, inHeight
/ dstHeight);
// decode full
System.gc();// /????????????????????????????????
Bitmap roughBitmap = BitmapFactory.decodeStream(in2, null, options2);
float scaleWidth = ((float) dstWidth) / inWidth;
float scaleHeight = ((float) dstHeight) / inHeight;
if (roughBitmap == null) {
pixelIn = getPixelsZadniVratka(pathOfInputImage, dstWidth,
dstHeight);
} else {
// calc exact destination size
PhotoRecord p9 = new PhotoRecord();
int rot9 = p9.loadRotation(pathOfInputImage).roatate;
Matrix matrix = new Matrix();
matrix.postRotate(rot9);
matrix.postScale(scaleWidth, scaleHeight);
// Bitmap resizedBitmap2 = Bitmap.createScaledBitmap(roughBitmap,
// dstWidth, dstHeight, filter);
// /------------------------------------
Bitmap rotatedBitmap = Bitmap.createBitmap(roughBitmap, 0, 0,
roughBitmap.getWidth(), roughBitmap.getHeight(), matrix,
filter);
Log.v("--------TAG--------", "JE inWidth PROCESS?????( " + inWidth);
Log.v("--------TAG--------", "JE getHeight PROCESS?????( "
+ rotatedBitmap.getHeight());
Log.v("--------TAG--------", "JE getWidth PROCESS?????( "
+ rotatedBitmap.getWidth());
pixelIn = new int[dstWidth * dstHeight];
if (rotatedBitmap != null) {
rotatedBitmap.getPixels(pixelIn, 0, dstWidth, 0, 0, dstWidth,
dstHeight);
rotatedBitmap.recycle();
} else {
pixelIn = null;
}
}
return pixelIn;
}

Related

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 ?
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.
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.
Use this one to change image width and height
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 one for change the size ...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;
}
Try this function.It 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 have to pass the bitmap to this method.
The method to get the bitmap from URI is
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
bitmap = BitmapFactory.decodeFile(fileUri.getPath(),
options);
If the camera image is JPEG, you can use the Bitmap compression method, like:
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();
}
Convert the image into 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;
}

Scaling and loading the image from res\drawable-hdpi folder

In my Android app, To avoid the OOM (bitmap Out of Memory error), I am scaling and loading the image from the assets folder. I have some of my images in res\drawable-hdpi folder. Is there is any I can scale and load it as I do for the images in assets folder ?
#SuppressLint("NewApi")
public Drawable getAssetImage(String filename) throws IOException {
int dWidth,dHeight;
Display display = getWindowManager().getDefaultDisplay();
if ( Integer.valueOf(android.os.Build.VERSION.SDK_INT) < 13 ) {
dWidth = display.getWidth();
dHeight = display.getHeight();
} else {
Point size = new Point();
display.getSize(size);
dWidth = size.x;
dHeight = size.y;
}
AssetManager assets = getApplicationContext().getResources().getAssets();
InputStream buffer = null;
try {
buffer = new BufferedInputStream((assets.open(filename + ".png")));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
if (tabletSize) {
} else {
int tempSampleSize = calculateInSampleSize(options, (int)dWidth, (int)dHeight);
Log.i("ClassicalMemoryGame", "dWidth " + dWidth );
Log.i("ClassicalMemoryGame", "dHeight " + dHeight );
Log.i("ClassicalMemoryGame", "sample size - " + tempSampleSize );
if (tempSampleSize > 1) {
options.inSampleSize = tempSampleSize;
}
}
options.inJustDecodeBounds = false;
Bitmap temp = BitmapFactory.decodeStream(buffer, null, options);
Bitmap finalImage = Bitmap.createScaledBitmap(temp, (int) dWidth, (int) dHeight, true);
Drawable d = new BitmapDrawable(getResources(),finalImage);
return d;
}
You can use following method to do so:
public static Bitmap decodeScaledSampleBitmap(Resources res,
int resourceId,int width, int height)
{
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resourceId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options,
width, height);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap b = Bitmap.createScaledBitmap(
BitmapFactory.decodeResource(res, resourceId, options),
width, height, true);
return b;
}

Image rotate 90 degree using camera intent

Hello I am working on one android app where I need to capture the image using camera intent and set the bitmap in the imageview but here bitmap is rotated by 90 degree. I have checked many threads of stackoverflow like Photo rotate 90 degree while capture in some phones but did not work for me.
Here when I am executing this exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1); then it is returning 0 ORIENTATION_UNDEFINED and in my getImage function no condition is satisfying.
Intent cameraIntent = new Intent(
android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
capturedPhotoName = System.currentTimeMillis() + ".png";
File photo = new File(Environment.getExternalStorageDirectory(),
capturedPhotoName);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
imageUri = Uri.fromFile(photo);
startActivityForResult(cameraIntent, CAMERA_INTENT_REQUEST);
onActivityResult
Uri selectedImage = imageUri;
getContentResolver().notifyChange(selectedImage, null);
ContentResolver cr = getContentResolver();
Bitmap bitmap;
try {
bitmap = android.provider.MediaStore.Images.Media.getBitmap(cr,
selectedImage);
bitmap = Util.getImage(bitmap, selectedImage.toString());
mPictureImageView.setImageBitmap(bitmap);
} catch (Exception e) {
Log.e("New Issue Activity", e.toString());
}
/**
* Get the image orientation
*
* #param imagePath
* #return orietation angle
* #throws IOException
*/
public static Bitmap getImage(Bitmap bitmap, String path) throws IOException {
Matrix m = new Matrix();
ExifInterface exif = new ExifInterface(path);
int orientation = exif
.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
if ((orientation == ExifInterface.ORIENTATION_ROTATE_180)) {
m.postRotate(180);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), m, true);
return bitmap;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
m.postRotate(90);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), m, true);
return bitmap;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
m.postRotate(270);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), m, true);
return bitmap;
}
return bitmap;
}
I implemented one photo take activity which you can take the photo and set the orientation of the photo. It is supported by every device I tested including Samsung galaxy series, tablets, sony xperia series, tablets.
You can check out my accepted answer about rotation of images on this topic:
Camera capture orientation on samsung devices in android
If you also need to save and use that image that you have rotated, saving and using the photo functions additional to my answer I gave above:
savePhoto function:
public void savePhoto(Bitmap bmp) {
imageFileFolder = new File(Environment.getExternalStorageDirectory(),
cc.getDirectoryName());
imageFileFolder.mkdir();
FileOutputStream out = null;
Calendar c = Calendar.getInstance();
String date = fromInt(c.get(Calendar.MONTH))
+ fromInt(c.get(Calendar.DAY_OF_MONTH))
+ fromInt(c.get(Calendar.YEAR))
+ fromInt(c.get(Calendar.HOUR_OF_DAY))
+ fromInt(c.get(Calendar.MINUTE))
+ fromInt(c.get(Calendar.SECOND));
imageFileName = new File(imageFileFolder, date.toString() + ".jpg");
try {
out = new FileOutputStream(imageFileName);
bmp.compress(Bitmap.CompressFormat.JPEG, 70, out);
out.flush();
out.close();
scanPhoto(imageFileName.toString());
out = null;
} catch (Exception e) {
e.printStackTrace();
}
}
scanPhoto function:
public void scanPhoto(final String imageFileName) {
geniusPath = imageFileName;
msConn = new MediaScannerConnection(MyClass.this,
new MediaScannerConnectionClient() {
public void onMediaScannerConnected() {
msConn.scanFile(imageFileName, null);
}
#Override
public void onScanCompleted(String path, Uri uri) {
msConn.disconnect();
}
});
msConn.connect();
}
SavePhotoTask class:
class SavePhotoTask extends AsyncTask<byte[], String, String> {
#Override
protected String doInBackground(byte[]... jpeg) {
File photo = new File(Environment.getExternalStorageDirectory(),
"photo.jpg");
if (photo.exists()) {
photo.delete();
}
try {
FileOutputStream fos = new FileOutputStream(photo.getPath());
fos.write(jpeg[0]);
fos.close();
} catch (java.io.IOException e) {
}
return (null);
}
}
Try below code:-
Uri selectedImageURI = data.getData();
imageFile = new File(getRealPathFromURI(selectedImageURI));
ExifInterface exif = new ExifInterface(imageFile.toString());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
Bitmap bitmap = Utility.getOrientationFromExif(new Utility().compressImage1(imageFile.toString(),((Activity)context)),orientation);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG , 50 , bos);
Utility.java
public class Utility
{
public Bitmap compressImage1(String imageUri, Activity act)
{
String filePath = getRealPathFromURI(imageUri, act);
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 = decodeBitmap(Uri.parse(imageUri), 612, 816, act);
Bitmap bmp = BitmapFactory.decodeFile(filePath, options);
// setting inSampleSize value allows to load a scaled down version of
// the original image
options.inSampleSize = calculateInSampleSize(options, 612, 816);
// 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];
// load the bitmap from its path
bmp = BitmapFactory.decodeFile(filePath, options);
return bmp;
}
public static int calculateInSampleSize(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;
}
public static Bitmap getOrientationFromExif(Bitmap bitmap, int orientation)
{
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int newWidth = 612;
int newHeight = 816;
// calculate the scale - in this case = 0.4f
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
switch (orientation)
{
case ExifInterface.ORIENTATION_NORMAL:
return bitmap;
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
// matrix.setScale(-1, 1);
matrix.postScale(scaleWidth, scaleHeight);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
matrix.setRotate(180);
break;
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
matrix.setRotate(180);
// matrix.postScale(-1, 1);
matrix.postScale(scaleWidth, scaleHeight);
break;
case ExifInterface.ORIENTATION_TRANSPOSE:
matrix.setRotate(90);
// matrix.postScale(-1, 1);
matrix.postScale(scaleWidth, scaleHeight);
break;
case ExifInterface.ORIENTATION_ROTATE_90:
matrix.setRotate(90);
break;
case ExifInterface.ORIENTATION_TRANSVERSE:
matrix.setRotate(-90);
// matrix.postScale(-1, 1);
matrix.postScale(scaleWidth, scaleHeight);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
matrix.setRotate(-90);
break;
default:
return bitmap;
}
try
{
Bitmap bmRotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
bitmap.recycle();
return bmRotated;
}
catch (OutOfMemoryError e)
{
e.printStackTrace();
return null;
}
}
}
This function worked for me, try your luck.
public static Bitmap rotateImage(Bitmap bmp, String imageUrl) {
if (bmp != null) {
ExifInterface ei;
int orientation = 0;
try {
ei = new ExifInterface(imageUrl);
orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
} catch (IOException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
}
int bmpWidth = bmp.getWidth();
int bmpHeight = bmp.getHeight();
Matrix matrix = new Matrix();
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
matrix.postRotate(90);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
matrix.postRotate(180);
break;
default:
break;
// etc.
}
Bitmap resizedBitmap = Bitmap.createBitmap(bmp, 0, 0, bmpWidth,
bmpHeight, matrix, true);
return resizedBitmap;
} else {
return bmp;
}
}

Android - Capturing an image with the camera and adding an overlay with different aspect ratios

I'm trying to take an image captured from the camera and place a photoframe or overlay over it. The photoframe is basically a png image placed in an ImageView within a FrameLayout that also contains the SurfaceView. The problem is that I must scale either or both of the resulting bitmaps of the view containing the photo image and the photo frame image in order for the overlay to be placed in exactly the correct position over the captured photo image. But since they have different aspect ratios, I'm at a loss to figure out how to do this without either the photo or the overlay from getting distorted. Here is my code that handles the bitmap manipulations. In addition, I sometimes get OutofMemory exceptions due to the huge size of the bitmaps. I tried to use MappedByteBufferbut couldn't get that to work right either... sigh. Anyway, any suggestions on what I'm doing wrong or code samples that show a better way to accomplish this are greatly appreciated!
private void saveTempPhoto(byte[] data) {
// Need to flip back the photo frame on front facing camera.
if (this.isCameraFront)
this.flipPhotoFrame();
findViewById(R.id.close_button).setVisibility(View.INVISIBLE);
findViewById(R.id.flash_button).setVisibility(View.INVISIBLE);
findViewById(R.id.focus_button).setVisibility(View.INVISIBLE);
findViewById(R.id.take_photo).setVisibility(View.INVISIBLE);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
options.inDither = false;
options.inPurgeable = true;
options.inInputShareable = true;
options.inTempStorage = new byte[32 * 1024];
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inJustDecodeBounds = true;
Bitmap bitmapPhoto = null;
Bitmap bitmapPhotoFrame = null;
Bitmap bitmapCanvas = null;
View view = findViewById(R.id.top_photo_frame); //view containing the photoframe
try {
int photoFrameWidth = view.getWidth();
int photoFrameHeight = view.getHeight();
BitmapFactory.decodeByteArray(data, 0, data.length, options);
if (orientation == 90 || orientation == 270) {
//Swap height and width
int temp = options.outWidth;
options.outWidth = options.outHeight;
options.outHeight = temp;
}
// Calculate the best sample size to use based on the ratio of the captured image to the photoframe.
// This is done to prevent OutofMemoryExceptions from occurring, as the bitmap allocations can use up a lot of heap space.
float ratioWidth = (float)options.outWidth / (float)photoFrameWidth;
float ratioHeight = (float)options.outHeight / (float)photoFrameHeight;
float ratio = Math.min(ratioWidth, ratioHeight);
if (ratioWidth > 1 || ratioHeight > 1) {
double power = Math.log(ratio) / Math.log(2);
options.inSampleSize = (int) Math.pow(2, Math.round(power));
}
options.inJustDecodeBounds = false;
Bitmap bitmapPhotoPreRotate = BitmapFactory.decodeByteArray(data, 0, data.length, options);
int postRotation = isCameraFront ? -orientation : orientation;
if (orientation != 0) {
Matrix matrix = new Matrix();
matrix.postRotate(postRotation);
bitmapPhoto = Bitmap.createBitmap(bitmapPhotoPreRotate, 0, 0, bitmapPhotoPreRotate.getWidth(), bitmapPhotoPreRotate.getHeight(), matrix, true);
bitmapPhotoPreRotate.recycle();
}
else
bitmapPhoto = bitmapPhotoPreRotate;
Log.d("PhotoFrameActivity", String.format("Photo bitmap has width %d and height %d", bitmapPhoto.getWidth(), bitmapPhoto.getHeight()));
Log.d("PhotoFrameActivity", String.format("PhotoFrame bitmap has width %d and height %d", view.getWidth(), view.getHeight()));
int photoWidth = bitmapPhoto.getWidth();
int photoHeight = bitmapPhoto.getHeight();
Bitmap.Config photoConfig = bitmapPhoto.getConfig();
bitmapCanvas = Bitmap.createBitmap(photoWidth,
photoHeight, photoConfig);
if (bitmapCanvas != null) {
Canvas canvas = new Canvas(bitmapCanvas);
canvas.drawBitmap(bitmapPhoto, new Matrix(), null);
bitmapPhoto.recycle();
bitmapPhoto = null;
System.gc(); //Try to force GC here to free up some memory
bitmapPhotoFrame = Bitmap.createScaledBitmap(
this.loadBitmapFromView(view),
photoWidth,
photoHeight,
true);
canvas.drawBitmap(bitmapPhotoFrame, 0, 0, null);
bitmapPhotoFrame.recycle();
Log.d("PhotoFrameActivity", String.format("Combined bitmap has width %d and height %d", bitmapCanvas.getWidth(), bitmapCanvas.getHeight()));
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmapCanvas.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] jpegWithPhotoFrame = stream.toByteArray();
try {
createPhotoFile();
FileOutputStream fos = new FileOutputStream(photoFile);
fos.write(jpegWithPhotoFrame);
fos.close();
Log.d("PhotoFrameActivity", String.format("Image file saved to %s", photoFile.getPath()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (bitmapCanvas != null)
bitmapCanvas.recycle();
if (bitmapPhoto != null)
bitmapPhoto.recycle();
if (bitmapPhotoFrame != null)
bitmapPhotoFrame.recycle();
}
}
catch (OutOfMemoryError e) {
// Put up out of memory alert
AlertDialog dialogError = new AlertDialog.Builder(this).create();
dialogError.setButton(DialogInterface.BUTTON_POSITIVE,"OK",
new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
finish();
}
}
);
dialogError.setMessage("Out of memory!");
dialogError.show();
}
catch (Exception e) {
e.printStackTrace();
}
}

Import image from gallery in my application is changed its orientation when it is more than 1.5 mb in size

I have an Android application, where I am importing image from gallery. It is working fine for all images but for some images whose size is more than 1.5 mb has changed its orientation. I have attached a image of that application. I am using this code.
newImage=(ImageView)findViewById(R.id.newImage);
imagePath = getIntent().getStringExtra("ImagePath");
try {
ExifInterface exif = new ExifInterface(imagePath);
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try{
BitmapFactory.Options options=new BitmapFactory.Options();
options.inJustDecodeBounds=true;
InputStream is=new FileInputStream(new File(imagePath) );
Display display = getWindowManager().getDefaultDisplay();
final Point point = new Point();
try {
display.getSize(point);
} catch (java.lang.NoSuchMethodError ignore) { // Older device
point.x = display.getWidth();
point.y = display.getHeight();
}
int scrWidth = point.x;
int scrHeight = point.y;
originalBitmap=BitmapFactory.decodeStream(is,null,options);
int imageWidth = options.outWidth;
int imageHeight = options.outHeight;
if(imageHeight>imageWidth){
int newWidth=(scrWidth/2);
int newHeight=(int)((float)imageHeight*((float)newWidth/(float)imageWidth));
originalBitmap=BitmapLoader.loadBitmap(imagePath, newWidth, newHeight);
}else{
int newWidth=(scrWidth/2);
//int newHeight=imageHeight*(imageWidth/newWidth);
int newHeight=(int)((float)imageHeight*((float)imageWidth/(float)newWidth));
originalBitmap=BitmapLoader.loadBitmap(imagePath, newWidth, newHeight);
}
is.close();
//originalBitmap= Bitmap.createBitmap(originalBitmap, 0, 0, originalBitmap.getWidth(), originalBitmap.getHeight(), matrix, true);
newBitmap=originalBitmap;
options.inJustDecodeBounds=true;
temp=BitmapLoader.loadBitmap(imagePath, 1200, 1200);
}
catch (Exception e) {
// TODO: handle exception
}
if(originalBitmap!=null)
//originalImage.setImageBitmap(originalBitmap);
if(newBitmap!=null)
newImage.setImageBitmap(newBitmap);
}

Categories

Resources