Am I correct in saying that if I take a full resolution picture with the camera, and save the bitmap as a jpg using bitmap.compress(), the inPreferredConfig parameter makes no difference at all to the final image?
I have tried specifying both, and the resulting images are the same 8-bit per channel jpgs (according to Photoshop) whether or not I use ARGB_8888 or RGB_565 modes to create the bitmap. They are both roughly the same file size. So the only way to save heap memory when displaying jpgs is to subsample it like the docs state?
So this is the code I am using, you can see I don't subsample it (scale factor is 1)
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
/* Figure out which way needs to be reduced less */
int scaleFactor = 1;
if ((targetW > 0) || (targetH > 0)) {
scaleFactor = Math.min(photoW/targetW, photoH/targetH);
}
/* Set bitmap options to scale the image decode target */
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPreferredConfig = Bitmap.Config.RGB_565;
bmOptions.inPurgeable = true;
/* Decode the JPEG file into a Bitmap */
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
String path = Environment.getExternalStorageDirectory().toString();
OutputStream fOut = null;
File file = new File(path, "TEST_IMAGE.jpg"); // the File to save to
try {
fOut = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 85, fOut); // saving the Bitmap to a file compressed as a JPEG with 85% compression rate
fOut.flush();
fOut.close(); // do not forget to close the stream
MediaStore.Images.Media.insertImage(getContentResolver(),file.getAbsolutePath(),file.getName(),file.getName());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Related
I want to rotate and save rotated bitmap to specific file path without compress it. Before i have used the below code for rotate, compress and store it to a specific file. Now i dnt want to compress my bitmap. Please suggest me an idea to rotate and save the bitmap into specified path.
public static void compressToStandard(String file) {
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file, bmOptions);
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = getInSampleSize(bmOptions);
try {
Bitmap bitmap = BitmapFactory.decodeFile(file, bmOptions);
bitmap = ExifUtils.rotateBitmap(file, bitmap);
Log.i("ImageUtils", "compressed bitmap size:" + bitmap.getWidth() + "x" + bitmap.getHeight());
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, new FileOutputStream(file));
} catch (Exception e) {
e.printStackTrace();
}
}
when i call this method. I will pass my image path to this method.
PNG is lossless so you can use Bitmap.CompressFormat.PNG
Compresion
Hint to the compressor, 0-100. 0 meaning compress for
small size, 100 meaning compress for max quality. Some
formats, like PNG which is lossless, will ignore the
quality setting
I'm trying to compress images selected by user from gallery for uploading. I saw that my camera pictures are over 5MB and I would like to compress them(same as facebook if possible). What I've been trying:
I let the user select the photo from gallery,get the uri and use this:
File file = new File(getRealPathFromURI(getActivity(), selectedImageUri));
long length = file.length();
Log.e("Filesize:", "Before: " + length);
if (file.getName().toLowerCase().endsWith("jpg")||file.getName().toLowerCase().endsWith("jpeg")){
Bitmap original;
try {
original = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), selectedImageUri);
length = sizeOf(original);
Log.e("Filesize:", "BeforeCompression: " + length);
ByteArrayOutputStream out = new ByteArrayOutputStream();
original.compress(Bitmap.CompressFormat.JPEG, 50, out);
Bitmap decoded = BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));
length = sizeOf(decoded);
Log.e("Filesize:", "AfterCompression: " + length);
} catch (IOException e) {
e.printStackTrace();
Log.e("Filesize:", "Error: " + e);
}
I did this to test if it was working first, but what I get in the console is:
/name.company.newapp E/Filesize:: Before: 4970874
/name.company.newapp E/Filesize:: BeforeConversion: 63489024
/name.company.newapp E/Filesize:: AfterConversion: 63489024
The size doesn't change at all. Is this the right approach ?
This happens because you're actually getting the size of memory used by the Bitmap object by calling sizeOf(bitmap) and not the actual file size.
As you should know, a bitmap operates with the number of pixels in an image. Even though you compress the image using a JPEG compression, the image's width and height do not change. Thus the number of pixels do not change and thus the Bitmap's size (in memory) would not change too.
However, if you save the compressed bitmap to a location in your hard disk and use File.length() to calculate the size of the compressed image, then you will notice the difference.
Please check the size before decoding and after compression:
length = sizeOf(original);
Also i would recommend you to flush and close the outputstream:
out.flush();
out.close();
Hope i could help!
Edit:
Please try the following method to decode your bitmap:
public static Bitmap decodeFile(File f,int WIDTH,int HEIGHT){
try {
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
final int REQUIRED_WIDTH=WIDTH;
final int REQUIRED_HEIGHT=HEIGHT;
//Find the correct scale value. It should be the power of 2.
int scale=1;
while(o.outWidth/scale/2>=REQUIRED_WIDTH && o.outHeight/scale/2>=REQUIRED_HEIGHT)
scale*=2;
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
You can change the width and height of your picture to make it smaller.
I use the following code to get a Blob back from my SQLite database and get back a bitmap. My problem is that the reconstructed bitmap is larger than the original picture (input). It seems that my BitmapFactory.Options isn't working, but I have no idea what is wrong, nor am I getting an error. What is wrong with this code?
byte[] blob = contact.getMP();
ByteArrayInputStream inputStream = new ByteArrayInputStream(blob);
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
bmpFactoryOptions.inScaled = false;
bmpFactoryOptions.outHeight = 240;
bmpFactoryOptions.outWidth = 320;
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, bmpFactoryOptions);
try {
FileOutputStream out = new FileOutputStream("mnt/sdcard/test5.png"); bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
} catch (Exception e) {
e.printStackTrace();
}
When I check the output my 320 x 240 picture is 427 x 320. I don't want to use Bitmap.createScaledBitmap because it messes up the quality.
you have to pass to decodeStream in order to work
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, bmpFactoryOptions);
I need for my Android application, take a picture of small size (> 1MB) with the camera.
But I can not resize the file obtained with the camera and then save it to the phone.
If someone has an idea to crop the photo or to ask the user to change camera settings.
thank you
Once you have the bitmap write it to a file using
File imageFile = new File(pathToSaveYourNewFile, whateverNameForNewSmallPicture.jpg);
OutputStream out = null;
out = new FileOutputStream(imageFile);
yourBitmapFromTheOriginalFile.compress(Bitmap.CompressFormat.JPG, 80, out);
out.flush();
out.close();
/* Set bitmap options to scale the image decode target */
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
/* Decode the JPEG file into a Bitmap */
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
/* Test compress */
File imageFile = new File(picturePath);
try{
OutputStream out = null;
out = new FileOutputStream(imageFile);
//Bitmap bitmap = BitmapFactory.decodeFile(picturePath);
bitmap.compress(Bitmap.CompressFormat.JPEG,80,out);
out.flush();
out.close();
}catch(Exception e){
Log.e("Dak","Erreur compress : "+e.toString());
}
If you can take the picture, you probably have it's name. Then you could simply open up the image again and resize the image, see http://www.anddev.org/resize_and_rotate_image_-_example-t621.html
I'm trying to read images from the SD CARD and save them in my custom directory resized to 1024 pixels, but always I got an OutOfMemory. I've tried most of examples I found here in stackoverflow about that "out of memory" staff...
I was asking me how the GalerĂa App manage images 4000 pixels so easily???
Thanks.
David.
I was asking me how the GalerĂa App manage images 4000 pixels so
easily?
It uses BitmapFactory.Options.inSampleSize in combination with the decoding methods of BitmapFactory to load a size-reduced thumbnail from the disk. It also tiles images and only load a certain part of an image if it is zoomed.
Please try the following code. Hope this would help.
Bitmap bMap = BitmapFactory.decodeFile(photoPath);
int orig_width = bMap.getWidth();
int orig_height = bMap.getHeight();
int aspect = orig_width / orig_height;
float aspectRatio = orig_width / orig_height;
int new_height = (int) (orig_height / (aspectRatio));
int new_width = (int) ((orig_width * aspectRatio)/2);
Bitmap scaled = Bitmap.createScaledBitmap(bMap, new_height, new_width, true);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
scaled.compress(CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
byte[] bitmapdata = bos.toByteArray();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 5;
File sdImageMainDirectory = Environment.getExternalStorageDirectory();
FileOutputStream fileOutputStream = null;
String tempFile = "tempImage";
int quality = 50;
Bitmap myImage = BitmapFactory.decodeByteArray(bitmapdata, 0,bitmapdata.length);
try {
fileOutputStream = new FileOutputStream(sdImageMainDirectory.toString() +"/" + tempFile + ".jpg");
BufferedOutputStream bosBufferedOutputStream = new BufferedOutputStream(fileOutputStream);
myImage.compress(CompressFormat.JPEG, quality, bosBufferedOutputStream);
bosBufferedOutputStream.flush();
bosBufferedOutputStream.close();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
On Android, mobile application is limited in memory, so nobody would ever think of loading such a huge Bitmap like that (4000px) to memory.
Just some tips for handling this situation:
Resize image to fit screen display (fitting view display is better)
Reduce quality to an acceptable level (whereas users' eyes cannot feel the differences, maybe)
Not displaying too much Bitmap images at the same time.
Avoiding the use of getPixel() and setPixel too much, it would lead to really really bad performance. Use getPixels() and setPixels() instead.
After done using Bitmap, recycle() it to release memory (GC knows what to do at this point).
Don't try to create so many references to Bitmap objects, you'd kill yourself afterward!!!
send:
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, o);
int REQUIRED_SIZE = 640;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while(true) {
if (width_tmp < REQUIRED_SIZE && height_tmp < REQUIRED_SIZE) break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
Bitmap bitmap = BitmapFactory.decodeFile(filePath, o2);
ByteArrayOutputStream bs2 = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 90, bs2);
getIntent().putExtra("byte_picture", bs2.toByteArray());
recive:
Bitmap photo = BitmapFactory.decodeByteArray(data.getByteArrayExtra("byte_picture"),0,data.getByteArrayExtra("byte_picture").length);