How to reduce an Image file size - android

I use this function to reduce the size of image before uploading it,But using below method my file size is increasing
Before use below code my file size---> 157684
after using this code my file size ----->177435
Can some one help me please how can i reduce file size before upload to server
code:
public File saveBitmapToFile(File file){
try {
// BitmapFactory options to downsize the image
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
o.inSampleSize = 6;
// factor of downsizing the image
FileInputStream inputStream = new FileInputStream(file);
//Bitmap selectedBitmap = null;
BitmapFactory.decodeStream(inputStream, null, o);
inputStream.close();
// The new size we want to scale to
final int REQUIRED_SIZE=75;
// 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;
}
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
inputStream = new FileInputStream(file);
Bitmap selectedBitmap = BitmapFactory.decodeStream(inputStream, null, o2);
inputStream.close();
// here i override the original image file
file.createNewFile();
FileOutputStream outputStream = new FileOutputStream(file);
selectedBitmap.compress(Bitmap.CompressFormat.JPEG, 100 , outputStream);
return file;
} catch (Exception e) {
return null;
}
}

This what I use to reduce my image size without compressing :
public static Bitmap getResizedBitmap(Bitmap bitmap, int newWidth, int newHeight) {
Bitmap scaledBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
float ratioX = newWidth / (float) bitmap.getWidth();
float ratioY = newHeight / (float) bitmap.getHeight();
float middleX = newWidth / 2.0f;
float middleY = newHeight / 2.0f;
Matrix scaleMatrix = new Matrix();
scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);
Canvas canvas = new Canvas(scaledBitmap);
canvas.setMatrix(scaleMatrix);
canvas.drawBitmap(bitmap, middleX - bitmap.getWidth() / 2, middleY - bitmap.getHeight() / 2, new Paint(Paint.FILTER_BITMAP_FLAG));
return scaledBitmap;
}
You just need to enter correct new height and width to fit your needs

We want to make thumbnail of an image, so we need to first take the ByteArrayOutputStream and then pass it into Bitmap.compress() method.
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
youBitmapImage.compress(Bitmap.CompressFormat.JPEG, 90, bytes);
more about the function, from the docs

If your output file is larger:
it can mean that scale is wrong. And you save the file with 100% quality so it can grow
compression on the input file is extremely heavy and even though you scale it, using no compression on the output still generates a larger file

Change this line:
selectedBitmap.compress(Bitmap.CompressFormat.JPEG, 100 , outputStream);
to
int mCompressedSize = 50; // 0 is lowest and 100 original
selectedBitmap.compress(Bitmap.CompressFormat.PNG, mCompressedSize, outputStream);
Hope this will help.

Try
int compressionRatio = 2; //1 == originalImage, 2 = 50% compression, 4=25% compress
File file = new File (imageUrl);
try {
Bitmap bitmap = BitmapFactory.decodeFile (file.getPath ());
bitmap.compress (Bitmap.CompressFormat.JPEG, compressionRatio, new FileOutputStream (file));
}
catch (Throwable t) {
Log.e("ERROR", "Error compressing file." + t.toString ());
t.printStackTrace ();
}

Related

android reduce image size without original image get changed

I have wrote a function that do reduce image size then upload it
everything works very well except original image will lost it quality
it should only reduce uploaded image size not the original one
this is my function
public void ReduceAndUpload(File file)
{
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
o.inSampleSize = 6;
BitmapFactory.decodeFile(file.getPath(), o);
int Scale = 1;
while (o.outWidth / Scale / 2 >= 75 && o.outHeight / Scale / 2 >= 75)
{
Scale *= 2;
}
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = Scale;
Bitmap SelectedBitmap = BitmapFactory.decodeFile(file.getPath(), o2);
ByteArrayOutputStream OutputStream = new ByteArrayOutputStream();
SelectedBitmap.compress(Bitmap.CompressFormat.JPEG, 100, OutputStream);
String ImageEncode = Base64.encodeToString(OutputStream.toByteArray(), 0);
DoUpload(ImageEncode);
}
whats wrong ?
Full Code: http://paste.ubuntu.com/20529512/

How to compress Bitmap as JPEG with least quality loss on Android?

This is not a straightforward problem, please read through!
I want to manipulate a JPEG file and save it again as JPEG. The problem is that even without manipulation there's significant (visible) quality loss.
Question: what option or API am I missing to be able to re-compress JPEG without quality loss (I know it's not exactly possible, but I think what I describe below is not an acceptable level of artifacts, especially with quality=100).
Control
I load it as a Bitmap from the file:
BitmapFactory.Options options = new BitmapFactory.Options();
// explicitly state everything so the configuration is clear
options.inPreferredConfig = Config.ARGB_8888;
options.inDither = false; // shouldn't be used anyway since 8888 can store HQ pixels
options.inScaled = false;
options.inPremultiplied = false; // no alpha, but disable explicitly
options.inSampleSize = 1; // make sure pixels are 1:1
options.inPreferQualityOverSpeed = true; // doesn't make a difference
// I'm loading the highest possible quality without any scaling/sizing/manipulation
Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/image.jpg", options);
Now, to have a control image to compare to, let's save the plain Bitmap bytes as PNG:
bitmap.compress(PNG, 100/*ignored*/, new FileOutputStream("/sdcard/image.png"));
I compared this to the original JPEG image on my computer and there's no visual difference.
I also saved the raw int[] from getPixels and loaded it as a raw ARGB file on my computer: there's no visual difference to the original JPEG, nor the PNG saved from Bitmap.
I checked the Bitmap's dimensions and config, they match the source image and the input options: it's decoded as ARGB_8888 as expected.
The above to control checks prove that the pixels in the in-memory Bitmap are correct.
Problem
I want to have JPEG files as a result, so the above PNG and RAW approaches wouldn't work, let's try to save as JPEG 100% first:
// 100% still expected lossy, but not this amount of artifacts
bitmap.compress(JPEG, 100, new FileOutputStream("/sdcard/image.jpg"));
I'm not sure its measure is percent, but it's easier to read and discuss, so I'm gonna use it.
I'm aware that JPEG with the quality of 100% is still lossy, but it shouldn't be so visually lossy that it's noticeable from afar. Here's a comparison of two 100% compressions of the same source.
Open them in separate tabs and click back and forth between to see what I mean. The difference images were made using Gimp: original as bottom layer, re-compressed middle layer with "Grain extract" mode, top layer full white with "Value" mode to enhance badness.
The below images are uploaded to Imgur which also compresses the files, but since all of the images are compressed the same, the original unwanted artifacts remain visible the same way I see it when opening my original files.
Original [560k]:
Imgur's difference to original (not relevant to problem, just to show that it's not causing any extra artifacts when uploading the images):
IrfanView 100% [728k] (visually identical to original):
IrfanView 100%'s difference to original (barely anything)
Android 100% [942k]:
Android 100%'s difference to original (tinting, banding, smearing)
In IrfanView I have to go below 50% [50k] to see remotely similar effects. At 70% [100k] in IrfanView there's no noticable difference, but the size is 9th of Android's.
Background
I created an app that takes a picture from Camera API, that image comes as a byte[] and is an encoded JPEG blob. I saved this file via OutputStream.write(byte[]) method, that was my original source file. decodeByteArray(data, 0, data.length, options) decodes the same pixels as reading from a File, tested with Bitmap.sameAs so it's irrelevant to the issue.
I was using my Samsung Galaxy S4 with Android 4.4.2 to test things out.
Edit: while investigating further I also tried Android 6.0 and N preview emulators and they reproduce the same issue.
After some investigation I found the culprit: Skia's YCbCr conversion. Repro, code for investigation and solutions can be found at TWiStErRob/AndroidJPEG.
Discovery
After not getting a positive response on this question (neither from http://b.android.com/206128) I started digging deeper. I found numerous half-informed SO answers which helped me tremendously in discovering bits and pieces. One such answer was https://stackoverflow.com/a/13055615/253468 which made me aware of YuvImage which converts an YUV NV21 byte array into a JPEG compressed byte array:
YuvImage yuv = new YuvImage(yuvData, ImageFormat.NV21, width, height, null);
yuv.compressToJpeg(new Rect(0, 0, width, height), 100, jpeg);
There's a lot of freedom going into creating the YUV data, with varying constants and precision. From my question it's clear that Android uses an incorrect algorithm.
While playing around with the algorithms and constants I found online I always got a bad image: either the brightness changed or had the same banding issues as in the question.
Digging deeper
YuvImage is actually not used when calling Bitmap.compress, here's the stack for Bitmap.compress:
libjpeg/jpeg_write_scanlines(jcapistd.c:77)
skia/rgb2yuv_32(SkImageDecoder_libjpeg.cpp:913)
skia/writer(=Write_32_YUV).write(SkImageDecoder_libjpeg.cpp:961)
[WE_CONVERT_TO_YUV is unconditionally defined]
SkJPEGImageEncoder::onEncode(SkImageDecoder_libjpeg.cpp:1046)
SkImageEncoder::encodeStream(SkImageEncoder.cpp:15)
Bitmap_compress(Bitmap.cpp:383)
Bitmap.nativeCompress(Bitmap.java:1573)
Bitmap.compress(Bitmap.java:984)
app.saveBitmapAsJPEG()
and the stack for using YuvImage
libjpeg/jpeg_write_raw_data(jcapistd.c:120)
YuvToJpegEncoder::compress(YuvToJpegEncoder.cpp:71)
YuvToJpegEncoder::encode(YuvToJpegEncoder.cpp:24)
YuvImage_compressToJpeg(YuvToJpegEncoder.cpp:219)
YuvImage.nativeCompressToJpeg(YuvImage.java:141)
YuvImage.compressToJpeg(YuvImage.java:123)
app.saveNV21AsJPEG()
By using the constants in rgb2yuv_32 from the Bitmap.compress flow I was able to recreate the same banding effect using YuvImage, not an achievement, just a confirmation that it's indeed the YUV conversion that is messed up. I double-checked that the problem is not during YuvImage calling libjpeg: by converting the Bitmap's ARGB to YUV and back to RGB then dumping the resulting pixel blob as a raw image, the banding was already there.
While doing this I realized that the NV21/YUV420SP layout is lossy as it samples the color information every 4th pixel, but it keeps the value (brightness) of each pixel which means that some color info is lost, but most of the info for people's eyes are in the brightness anyway. Take a look at the example on wikipedia, the Cb and Cr channel makes barely recognisable images, so lossy sampling on it doesn't matter much.
Solution
So, at this point I knew that libjpeg does the right conversion when it is passed the right raw data. This is when I set up the NDK and integrated the latest LibJPEG from http://www.ijg.org. I was able to confirm that indeed passing the RGB data from the Bitmap's pixels array yields the expected result. I like to avoid using native components when not absolutely necessary, so aside of going for a native library that encodes a Bitmap I found a neat workaround. I've essentially taken the rgb_ycc_convert function from jcolor.c and rewrote it in Java using the skeleton from https://stackoverflow.com/a/13055615/253468. The below is not optimized for speed, but readability, some constants were removed for brevity, you can find them in libjpeg code or my example project.
private static final int JSAMPLE_SIZE = 255 + 1;
private static final int CENTERJSAMPLE = 128;
private static final int SCALEBITS = 16;
private static final int CBCR_OFFSET = CENTERJSAMPLE << SCALEBITS;
private static final int ONE_HALF = 1 << (SCALEBITS - 1);
private static final int[] rgb_ycc_tab = new int[TABLE_SIZE];
static { // rgb_ycc_start
for (int i = 0; i <= JSAMPLE_SIZE; i++) {
rgb_ycc_tab[R_Y_OFFSET + i] = FIX(0.299) * i;
rgb_ycc_tab[G_Y_OFFSET + i] = FIX(0.587) * i;
rgb_ycc_tab[B_Y_OFFSET + i] = FIX(0.114) * i + ONE_HALF;
rgb_ycc_tab[R_CB_OFFSET + i] = -FIX(0.168735892) * i;
rgb_ycc_tab[G_CB_OFFSET + i] = -FIX(0.331264108) * i;
rgb_ycc_tab[B_CB_OFFSET + i] = FIX(0.5) * i + CBCR_OFFSET + ONE_HALF - 1;
rgb_ycc_tab[R_CR_OFFSET + i] = FIX(0.5) * i + CBCR_OFFSET + ONE_HALF - 1;
rgb_ycc_tab[G_CR_OFFSET + i] = -FIX(0.418687589) * i;
rgb_ycc_tab[B_CR_OFFSET + i] = -FIX(0.081312411) * i;
}
}
static void rgb_ycc_convert(int[] argb, int width, int height, byte[] ycc) {
int[] tab = LibJPEG.rgb_ycc_tab;
final int frameSize = width * height;
int yIndex = 0;
int uvIndex = frameSize;
int index = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int r = (argb[index] & 0x00ff0000) >> 16;
int g = (argb[index] & 0x0000ff00) >> 8;
int b = (argb[index] & 0x000000ff) >> 0;
byte Y = (byte)((tab[r + R_Y_OFFSET] + tab[g + G_Y_OFFSET] + tab[b + B_Y_OFFSET]) >> SCALEBITS);
byte Cb = (byte)((tab[r + R_CB_OFFSET] + tab[g + G_CB_OFFSET] + tab[b + B_CB_OFFSET]) >> SCALEBITS);
byte Cr = (byte)((tab[r + R_CR_OFFSET] + tab[g + G_CR_OFFSET] + tab[b + B_CR_OFFSET]) >> SCALEBITS);
ycc[yIndex++] = Y;
if (y % 2 == 0 && index % 2 == 0) {
ycc[uvIndex++] = Cr;
ycc[uvIndex++] = Cb;
}
index++;
}
}
}
static byte[] compress(Bitmap bitmap) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] argb = new int[w * h];
bitmap.getPixels(argb, 0, w, 0, 0, w, h);
byte[] ycc = new byte[w * h * 3 / 2];
rgb_ycc_convert(argb, w, h, ycc);
argb = null; // let GC do its job
ByteArrayOutputStream jpeg = new ByteArrayOutputStream();
YuvImage yuvImage = new YuvImage(ycc, ImageFormat.NV21, w, h, null);
yuvImage.compressToJpeg(new Rect(0, 0, w, h), quality, jpeg);
return jpeg.toByteArray();
}
The magic key seems to be ONE_HALF - 1 the rest looks an awful lot like the math in Skia. That's a good direction for future investigation, but for me the above is sufficiently simple to be a good solution for working around Android's builtin weirdness, albeit slower. Note that this solution uses the NV21 layout which loses 3/4 of the color info (from Cr/Cb), but this loss is much less than the errors created by Skia's math. Also note that YuvImage doesn't support odd-sized images, for more info see NV21 format and odd image dimensions.
Please use the following method:
public String convertBitmaptoSmallerSizetoString(String image){
File imageFile = new File(image);
Bitmap bitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath());
int nh = (int) (bitmap.getHeight() * (512.0 / bitmap.getWidth()));
Bitmap scaled = Bitmap.createScaledBitmap(bitmap, 512, nh, true);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
scaled.compress(Bitmap.CompressFormat.PNG, 90, stream);
byte[] imageByte = stream.toByteArray();
String img_str = Base64.encodeToString(imageByte, Base64.NO_WRAP);
return img_str;
}
Below is my Code:
public static String compressImage(Context context, String imagePath)
{
final float maxHeight = 1024.0f;
final float maxWidth = 1024.0f;
Bitmap scaledBitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeFile(imagePath, options);
int actualHeight = options.outHeight;
int actualWidth = options.outWidth;
float imgRatio = (float) actualWidth / (float) actualHeight;
float maxRatio = maxWidth / maxHeight;
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;
}
}
options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight);
options.inJustDecodeBounds = false;
options.inDither = false;
options.inPurgeable = true;
options.inInputShareable = true;
options.inTempStorage = new byte[16 * 1024];
try {
bmp = BitmapFactory.decodeFile(imagePath, options);
} catch (OutOfMemoryError exception) {
exception.printStackTrace();
}
try {
scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Bitmap.Config.RGB_565);
} 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);
assert scaledBitmap != null;
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));
if (bmp != null) {
bmp.recycle();
}
ExifInterface exif;
try {
exif = new ExifInterface(imagePath);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
Matrix matrix = new Matrix();
if (orientation == 6) {
matrix.postRotate(90);
} else if (orientation == 3) {
matrix.postRotate(180);
} else if (orientation == 8) {
matrix.postRotate(270);
}
scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
} catch (IOException e) {
e.printStackTrace();
}
FileOutputStream out = null;
String filepath = getFilename(context);
try {
out = new FileOutputStream(filepath);
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return filepath;
}
public static 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;
}
public static String getFilename(Context context) {
File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
+ "/Android/data/"
+ context.getApplicationContext().getPackageName()
+ "/Files/Compressed");
if (!mediaStorageDir.exists()) {
mediaStorageDir.mkdirs();
}
String mImageName = "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg";
return (mediaStorageDir.getAbsolutePath() + "/" + mImageName);
}

After merging images the quality decreased, Android

I have two images and I want to set one upon another.
However after merging I get low quality file.
This is my original topImage (96x96) pixels:
This is my bottomIamge (74x74) pixels:
You can see that quality is pretty good.
When I run under mentioned code I get merged Image (74x74):
Now you can see that topImage lost his quality.
Here is relevant code:
// load bottom image from assets:
InputStream is;
Bitmap bottomImage;
try {
is = context.getAssets().open("images/avatar1.png");
} catch (IOException e1) {
int resID = context.getResources().getIdentifier("unknown_item", "drawable", context.getPackageName());
is = context.getResources().openRawResource(resID);
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inMutable = true;
bottomImage = BitmapFactory.decodeStream(is,null,options);
try {
is.close();
is = null;
} catch (IOException e) {
}
Bitmap topImage = null;
String base64Img = null;
// get byte array from String (base64).
byte[] backToBytes = Base64.decode(base64Img, Base64.DEFAULT);
// here I verified that image I got from byte array still has good quality
//writeToStorage(backToBytes, "test.png");
// create Bitmap
topImage = BitmapFactory.decodeByteArray(backToBytes, 0, backToBytes.length, null);
// scale the image
topImage = Bitmap.createScaledBitmap(topImage, 74, 74, false); // set fixed size 74x74 image
topImage = Bitmap.createBitmap(topImage, topImage.getWidth()/4, 0, topImage.getWidth()/2, topImage.getHeight());
// shift it:
Canvas comboImage = new Canvas(bottomImage);
// Then draw the second on top of that
comboImage.drawBitmap(topImage, 0f, 0f, null);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bottomImage.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
String base64String = Base64.encodeToString(byteArray, Base64.DEFAULT);
If I'll draw base64String I get merged Image
Do I miss something?
Does Bitmap.createScaledBitmap(topImage, 37, 74, false); scales to 37x74 pixels?
Thanks,
For now I use this way (based on THIS answer):
// this method should replace Bitmap.createScaledBitmap
private Bitmap scaleBitmap(Bitmap bitmap, int newWidth, int newHeight){
Bitmap scaledBitmap = Bitmap.createBitmap(newWidth, newHeight, Config.ARGB_8888);
float ratioX = newWidth / (float) bitmap.getWidth();
float ratioY = newHeight / (float) bitmap.getHeight();
float middleX = newWidth / 2.0f;
float middleY = newHeight / 2.0f;
Matrix scaleMatrix = new Matrix();
scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);
Canvas canvas = new Canvas(scaledBitmap);
canvas.setMatrix(scaleMatrix);
canvas.drawBitmap(bitmap, middleX - bitmap.getWidth() / 2, middleY - bitmap.getHeight() / 2, new Paint(Paint.FILTER_BITMAP_FLAG));
return scaledBitmap;
}
And now I can replace:
topImage = Bitmap.createScaledBitmap(topImage, 74, 74, false);
with:
topImage = scaleBitmap(topImage, 74, 74);
was:
now:
Its not the same quality but seems better
You cannot keep the quality when scaling by not hall number(2,3,4,5). In your case you are scaling 96 pixels to 74.
You can either change the scale to 48 pixels(x2) or keep it 96 pixels.
Also watch this video that explain what is anti-aliacing, and how it can help you.

image rotation not working on Samsung Galaxy Nexus android

I've tested this code snippet on about 25 devices and it works great on all of them except a Samsung Galaxy Nexus that I'm trying to test with now.
Here is the method and I apologize for not trimming it down to find the exact spot that's throwing the exception, but eclipse's debugging is doodoo.
private void setupImageView() {
imageLocation = currentPhotoPath;
// Get the dimensions of the View
Display display = getWindowManager().getDefaultDisplay();
Point size = getDisplaySize(display);
int targetW = size.x;
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imageLocation, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW / targetW, photoH / targetW);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(imageLocation, bmOptions);
//int rotationForImage = getRotationForImage(imageLocation);
int rotationForImage = (whichCamera == 0 ? 90 : 270);
if (rotationForImage != 0) {
int targetWidth = rotationForImage == 90 || rotationForImage == 270 ? bitmap.getHeight() : bitmap.getWidth();
int targetHeight = rotationForImage == 90 || rotationForImage == 270 ? bitmap.getWidth() : bitmap.getHeight();
Bitmap rotatedBitmap = Bitmap.createBitmap(targetWidth, targetHeight, bitmap.getConfig());
Canvas canvas = new Canvas(rotatedBitmap);
Matrix matrix = new Matrix();
matrix.setRotate(rotationForImage, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
canvas.drawBitmap(bitmap, matrix, new Paint());
bitmap.recycle();
bitmap = rotatedBitmap;
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 40, bytes);
try
{
File f = new File(imageLocation);
f.createNewFile();
//write the bytes in file
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
fo.close();
}
catch(java.io.IOException e){}
}
imageView.setImageBitmap(bitmap);
}
anyone know what Samsung does differently with the nexus that would cause this to throw an exception? It works fine on a Galaxy S III
It looks like something in the if block you mention is throwing an NPE - that's the real bug here. Don't worry about the Activity/ResultInfo stuff, that is downstream and triggered by the NPE. Go line by line and look for the null reference :-)
Regarding Eclipse - sadly I don't have much experience there. For Android I personally use IntelliJ and the debugging works well. Are you able to debug other Java code (even a simple Hello, World)?

Pick image from sd card, resize the image and save it back to sd card

I am working on an application, in which I need to pick an image from sd card and show it in image view. Now I want the user to decrease/increase its width by clicking a button and then save it back to the sd card.
I have done the image picking and showing it on ui. But unable to find how to resize it.Can anyone please suggest me how to achieve it.
Just yesterday i have done this
File dir=Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
Bitmap b= BitmapFactory.decodeFile(PATH_ORIGINAL_IMAGE);
Bitmap out = Bitmap.createScaledBitmap(b, 320, 480, false);
File file = new File(dir, "resize.png");
FileOutputStream fOut;
try {
fOut = new FileOutputStream(file);
out.compress(Bitmap.CompressFormat.PNG, 100, fOut);
fOut.flush();
fOut.close();
b.recycle();
out.recycle();
} catch (Exception e) {}
Also don't forget to recycle your bitmaps: It will save memory.
You can also get path of new created file String: newPath=file.getAbsolutePath();
Solution without OutOfMemoryException in Kotlin
fun resizeImage(file: File, scaleTo: Int = 1024) {
val bmOptions = BitmapFactory.Options()
bmOptions.inJustDecodeBounds = true
BitmapFactory.decodeFile(file.absolutePath, bmOptions)
val photoW = bmOptions.outWidth
val photoH = bmOptions.outHeight
// Determine how much to scale down the image
val scaleFactor = Math.min(photoW / scaleTo, photoH / scaleTo)
bmOptions.inJustDecodeBounds = false
bmOptions.inSampleSize = scaleFactor
val resized = BitmapFactory.decodeFile(file.absolutePath, bmOptions) ?: return
file.outputStream().use {
resized.compress(Bitmap.CompressFormat.JPEG, 75, it)
resized.recycle()
}
}
Try using this method:
public static Bitmap scaleBitmap(Bitmap bitmapToScale, float newWidth, float newHeight) {
if(bitmapToScale == null)
return null;
//get the original width and height
int width = bitmapToScale.getWidth();
int height = bitmapToScale.getHeight();
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(newWidth / width, newHeight / height);
// recreate the new Bitmap and set it back
return Bitmap.createBitmap(bitmapToScale, 0, 0, bitmapToScale.getWidth(), bitmapToScale.getHeight(), matrix, true);
}
You can use Bitmap.createScaledBitmap (Bitmap src, int dstWidth, int dstHeight, boolean filter)
I found this useful library for this achievement: https://github.com/hkk595/Resizer
Here my static method:
public static void resizeImageFile(File originalImageFile, File resizedImageFile, int maxSize) {
Bitmap bitmap = BitmapFactory.decodeFile(originalImageFile.getAbsolutePath());
Bitmap resizedBitmap;
if (bitmap.getWidth() > bitmap.getHeight()) {
resizedBitmap = Bitmap.createScaledBitmap(bitmap, maxSize, maxSize * bitmap.getHeight() / bitmap.getWidth(), false);
} else {
resizedBitmap = Bitmap.createScaledBitmap(bitmap, maxSize * bitmap.getWidth() / bitmap.getHeight(), maxSize, false);
}
FileOutputStream fileOutputStream;
try {
fileOutputStream = new FileOutputStream(resizedImageFile);
resizedBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
bitmap.recycle();
resizedBitmap.recycle();
} catch (Exception e) {
e.printStackTrace();
}
}
You should ideally use multitouch instead of using a button to increase/decrease width. Here's an amazing library. Once the user decides to save the image, the image translation matrix must be stored persistently (in your sqlite database). Next time the user opens the image, you need to recall the matrix and apply it to your image.
I've actually done this before.

Categories

Resources