I'm trying to compress a Bitmap which is taken from either the user's gallery or camera and store it as a profile picture in a Parse Server.
The issue is the bitmap will NOT compress. The image saves perfectly fine and is useable in the database, but the file size is massive for just a profile picture.
Here's my current code:
//Compressing
ByteArrayOutputStream stream = new ByteArrayOutputStream();
profilePictureBitmap.compress(Bitmap.CompressFormat.PNG, 20, stream);
byte[] image = stream.toByteArray();
//Saving
String imageName = username + "_profile_picture.png";
final ParseFile file = new ParseFile(imageName, image);
file.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if(e == null) {
user.put("profilePicture", file);
user.signUpInBackground();
}
}
}
I'm using a image picker library that gets the path of the image. I then turn it into a bitmap.
Heres my code to retrieve the image:
ArrayList<Image> images = data.getParcelableArrayListExtra(ImagePickerActivity.INTENT_EXTRA_SELECTED_IMAGES);
if(images.size() > 0) {
Image image = images.get(0);
File imgFile = new File(image.getPath());
if(imgFile.exists()){
profilePictureBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
profilePictureImage.setImageBitmap(profilePictureBitmap);
}
}
If there is any ideas on how to fix this I would greatly appreciate it.
Thanks :]
Image image = images.get(0);
File imgFile = new File(image.getPath());
if(imgFile.exists()){
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 2; // one quarter of original size
profilePictureBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(), opts);
profilePictureImage.setImageBitmap(profilePictureBitmap);
}
Docs for inSampleSize:
If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory. The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded bitmap. For example, inSampleSize == 4 returns an image that is 1/4 the width/height of the original, and 1/16 the number of pixels. Any value <= 1 is treated the same as 1. Note: the decoder uses a final value based on powers of 2, any other value will be rounded down to the nearest power of 2.
Related
I am converting an android Image captured in my application to a bitmap. I am doing this by getting the image buffer from the pixel plane of the image and then using BitMapFactory to decode it into a Bitmap. However, doing so seems to change the resolution of the Image from 1920 x 1440 to 1800 x 1600, cropping out the top and bottom of the image in the process. The code for the method is shown here.
`protected void getImageFromBuffer(ImageReader reader){
Image image = null;
image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
System.out.println("Getting Image Ready");
synchronized (this){
image_to_upload = new byte[buffer.capacity()];
buffer.get(image_to_upload);
Bitmap storedBitmap = BitmapFactory.decodeByteArray(image_to_upload, 0, image_to_upload.length, null);
Matrix mat = new Matrix();
mat.postRotate(jpegOrientation); // angle is the desired angle you wish to rotate
storedBitmap = Bitmap.createBitmap(storedBitmap, 0, 0, storedBitmap.getWidth(), storedBitmap.getHeight(), mat, true);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
storedBitmap.compress(Bitmap.CompressFormat.JPEG,70, byteArrayOutputStream);
image_to_upload = byteArrayOutputStream.toByteArray();
image_ready = true;
System.out.println("Image Ready");
}
}`
Debugging shows that the height and width of the Image are correct before the buffer is converted to a bitmap, but the bitmap dimensions are wrong immediately after decodeByteArray. Can anyone suggest why this may be? I have checked the dimensions before applying the matrix transformation.
EDIT: To add further details, I have tried using BitmapFactory.Options() to disable scaling or to set the target density and neither have any impact on the resulting Bitmap, it is always size 1800 x 1600.
You can change some options that affects the result resolution of your bitmap by using the Options param to the decodeByteArray:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDensity = DisplayMetrics.DENSITY_XXHIGH;//for example
BitmapFactory.decodeByteArray(image_to_upload, 0, image_to_upload.length, options);
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
Here's what I'm trying to do:
Myapp calls the camera app, takes a picture, sends the pic path back to Myapp to be displayed in an ImageView and to then be shared to Instagram. I want the displayed bitmap to be of the same dimensions as what Instagram uses so no unexpected cropping will happen when going from Myapp to Instagram.
Here's what I've tried so far when returning from the camera:
(note: INSTAGRAM_FORMAT_W == INSTAGRAM_FORMAT_H == 1080)
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.outHeight = INSTAGRAM_FORMAT_H;
bmOptions.outWidth = INSTAGRAM_FORMAT_W;
bmOptions.inMutable = true;
Bitmap photo = (Bitmap) BitmapFactory.decodeFile(path, bmOptions);
photo = Bitmap.createScaledBitmap(photo, INSTAGRAM_FORMAT_H, INSTAGRAM_FORMAT_W, false);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
photo.compress(Bitmap.CompressFormat.JPEG, 40, bytes);
This distorts the image to fit the square format; not optimal
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.outHeight = INSTAGRAM_FORMAT_H;
bmOptions.outWidth = INSTAGRAM_FORMAT_W;
bmOptions.inMutable = true;
Bitmap photo = (Bitmap) BitmapFactory.decodeFile(path, bmOptions);
int baseX = (photo.getWidth() - INSTAGRAM_FORMAT_W)/2;
int baseY = (photo.getHeight() - INSTAGRAM_FORMAT_H)/2;
Bitmap photoResized = Bitmap.createBitmap(photo,baseX,baseY,INSTAGRAM_FORMAT_W,INSTAGRAM_FORMAT_H);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
photoResized.compress(Bitmap.CompressFormat.JPEG, 40, bytes);
This crops too much off what the user sees thru the camera app, it is also bigger than the Instagram size which results in additional cropping when going to Instagram; not optimal
I was digging thru BitmapFactory.Options and possible parameters for Bitmap.createBitmap but I'm pretty lost in terms of what best practice is for when/where the formatting occurs, how to deal with variable pixel density of the screen (if needed) and variable camera definition (if applicable).
I could use a helping hand folks. Thanks
I am facing a few problems here. I have a socket server and my app uploads images to it. Now if I say I have 1 million customers each one 1mb for image, I should leave 1 terabyte for just profile images, which is too much. I am seeking a way to convert all image files to max 100 kb size, is such thing possible? If so what should I search for?
And also I'm selecting image files from disk, like this:
File file = new File("storage/sdcard/LifeMatePrivate/ProfileImage
/ProfileImage,imagechange_1,"+imagenamer+".jpg")
But as you see it just selects images with prefix.jpg. Is there a way I can the file with any extension? Thanks.
public void SaveImage(View v){
System.out.println(path);
String Path = path;
//File file=new File("storage/sdcard/Pictures/reza2.jpg");
Bitmap bitmap = BitmapFactory.decodeFile("storage/sdcard/Pictures
/reza2.jpg");
// you can change the format of you image compressed for what do you
want;
//now it is set up to 640 x 960;
Bitmap bmpCompressed = Bitmap.createScaledBitmap(bitmap, 640, 960, true);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// CompressFormat set up to JPG, you can change to PNG or whatever you
want;
bmpCompressed.compress(CompressFormat.PNG, 100, bos);
// Intent returnIntent = new Intent();
// returnIntent.putExtra("result",Path);
// setResult(RESULT_OK,returnIntent);
// Log.i("Image",path);
finish();
}
this code is inside an activity stared with StartActivityForResult
Try this to compress your images..
Bitmap bitmap = BitmapFactory.decodeFile(imagefilepath);
// you can change the format of you image compressed for what do you want;
//now it is set up to 640 x 960;
Bitmap bmpCompressed = Bitmap.createScaledBitmap(bitmap, 640, 960, true);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// CompressFormat set up to JPG, you can change to PNG or whatever you want;
bmpCompressed.compress(CompressFormat.JPEG, 100, bos);
now bmpCompressed is a compressed file format
There is 2 ways to scale a bitmap :
With given size :
Bitmap yourBitmap;
Bitmap resized = Bitmap.createScaledBitmap(yourBitmap, newWidth, newHeight, true);
Sampling image using :
BitmapFactory.decodeFile(file, options)
Here is my code:
File file = new File(Path to Jpeg File size is 700kb);
InputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream(file));
}
catch (Exception e) {
// TODO: handle exception
}
bitmap =BitmapFactory.decodeStream(in);
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
Please help i get error in this copy line i want to make its ARGB_8888 image.Need Help :(
You need to reduce the memory usage.
From you code, you first decode stream to one bitmap, and then copy it, which means you create two large bitmap objects.
You don't need to decode and then copy it, you can try
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888
// You can try value larger than 1
options.inSampleSize = 2 // If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory.
// Decode bitmap
bitmap = BitmapFactory.decodeStream(in, null, options)
In this case, there's only one bitmap created. And you set inSampleSize to large values to reduce the loaded bitmap size.