Getting Out of Memory Error onPictureTaken BitmapFactory.decodeByteArray - android

I am getting a weird OOM error on decoding the bytearray I get when taking a picture. My code is as below. Please tell if there is a better way to do it.
#Override
public void onPictureTaken(byte[] data, Camera camera) {
// TODO something with the image data
// Restart the preview and re-enable the shutter button so that we can take another picture
camera.startPreview();
inPreview = true;
shutterButton.setEnabled(true);
System.gc();
Bitmap bitmap = BitmapFactory.decodeByteArray(data , 0, data.length);
Matrix matrix = new Matrix();
matrix.postRotate(90);
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, false);
if(bitmap != null){
boolean fileSaved = Funcs.saveImage(getActivity(),resizedBitmap, "moizali");
if(fileSaved){
((BaseActivity)getActivity()).goToPhotoEditActivity("moizali");
}
}
}

Related

Efficient way of converting InputImage to Bitmap

I have to convert com.google.mlkit.vision.common.InputImage to equivalent Bitmap image in android using Java. Right now I am using the following code.
// iImage is an object of InputImage
Bitmap bmap = Bitmap.createBitmap(iImage.getWidth(), iImage.getHeight(), Bitmap.Config.RGB_565);
bmap.copyPixelsFromBuffer(iImage.getByteBuffer());
The above code is NOT converting the InputImage to Bitmap. Can anyone please suggest me the efficient way of converting InputImage to Bitmap.
You can create bitmap from byteBuffer, that can be received by call the method getByteBuffer().In the offical quick start example of ML Kit Vission you can find the vay how to achieve this. Below is a piece of code that can solve your problem:
Method getBitmap() thats converts NV21 format byte buffer to bitmap:
#Nullable
public static Bitmap getBitmap(ByteBuffer data, FrameMetadata metadata) {
data.rewind();
byte[] imageInBuffer = new byte[data.limit()];
data.get(imageInBuffer, 0, imageInBuffer.length);
try {
YuvImage image =
new YuvImage(
imageInBuffer, ImageFormat.NV21, metadata.getWidth(), metadata.getHeight(), null);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, metadata.getWidth(), metadata.getHeight()), 80, stream);
Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
stream.close();
return rotateBitmap(bmp, metadata.getRotation(), false, false);
} catch (Exception e) {
Log.e("VisionProcessorBase", "Error: " + e.getMessage());
}
return null;
}
Method rotateBitmap():
private static Bitmap rotateBitmap(
Bitmap bitmap, int rotationDegrees, boolean flipX, boolean flipY) {
Matrix matrix = new Matrix();
// Rotate the image back to straight.
matrix.postRotate(rotationDegrees);
// Mirror the image along the X or Y axis.
matrix.postScale(flipX ? -1.0f : 1.0f, flipY ? -1.0f : 1.0f);
Bitmap rotatedBitmap =
Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
// Recycle the old bitmap if it has changed.
if (rotatedBitmap != bitmap) {
bitmap.recycle();
}
return rotatedBitmap;
}
The full code can be seen by clicking on the link: https://github.com/googlesamples/mlkit/blob/master/android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/BitmapUtils.java

Rotate bitmap without outofMemoery exception on android

This is my code to rotate a image. Image is already down sampled and decoded. But this throws an exception because it creates an additional copy of the image. How can I generate the image safely?
public Bitmap rotateBitmap(Bitmap image, int angle) {
if (image != null) {
Matrix matrix = new Matrix();
matrix.postRotate(angle, (image.getWidth()) / 2,
(image.getHeight()) / 2);
return Bitmap.createBitmap(image, 0, 0, image.getWidth(),
image.getHeight(), matrix, true);
}
return null;
}

Rotate a bitmap using render script android

When I use following code, it ends up with outofmemory exception. After doing researh Render script looks like a good candidate. Where can I find sample code for similar operation and how can integrate it to my project.
public Bitmap rotateBitmap(Bitmap image, int angle) {
if (image != null) {
Matrix matrix = new Matrix();
matrix.postRotate(angle, (image.getWidth()) / 2,
(image.getHeight()) / 2);
return Bitmap.createBitmap(image, 0, 0, image.getWidth(),
image.getHeight(), matrix, true);
}
return null;
}
Basically rotating bitmap is a task of rotating 2D array without using additional memory. And this is the correct implementation with RenderScript: Android: rotate image without loading it to memory .
But this is not necessary if all you want is just to display rotated Bitmap. You can simply extend ImageView and rotate the Canvas while drawing on it:
canvas.save();
canvas.rotate(angle, X + (imageW / 2), Y + (imageH / 2));
canvas.drawBitmap(imageBmp, X, Y, null);
canvas.restore();
What about ScriptIntrinsic, since it's just a built-in RenderScript kernels for common operations you cannot do nothing above the already implemented functions: ScriptIntrinsic3DLUT, ScriptIntrinsicBLAS, ScriptIntrinsicBlend, ScriptIntrinsicBlur, ScriptIntrinsicColorMatrix, ScriptIntrinsicConvolve3x3, ScriptIntrinsicConvolve5x5, ScriptIntrinsicHistogram, ScriptIntrinsicLUT, ScriptIntrinsicResize, ScriptIntrinsicYuvToRGB. They do not include functionality to rotate bitmap at the moment so you should create your own ScriptC script.
Try this code..
private Bitmap RotateImage(Bitmap _bitmap, int angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
_bitmap = Bitmap.createBitmap(_bitmap, 0, 0, _bitmap.getWidth(), _bitmap.getHeight(), matrix, true);
return _bitmap;
}
Use this code when select image from gallery.
like this..
File _file = new File(file_name);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
Bitmap bitmap = BitmapFactory.decodeFile(file_name, options);
try {
ExifInterface exif = new ExifInterface(file_name);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
bitmap = RotateImage(bitmap, 90);
} else if (orientation ==ExifInterface.ORIENTATION_ROTATE_270) {
bitmap = RotateImage(bitmap, 270);
}
} catch (Exception e) {
e.printStackTrace();
}
image_holder.setImageBitmap(bitmap);

Mirror the front facing camera in Android

When you take a picture with the front facing camera in Android the preview is reflected along the Y axis to make the image seen appear as if the user was looking in the mirror. I want to undo this effect (apply a second reflection) or just stop the one thats done automatically.
I though to use this:
Camera mCamera;
....
mCamera.setPreviewCallback(...);
But I dont really know what to do with the overriding of
onPreviewFrame(byte[] data, Camera camera){...}
Whats the best way I can achieve what I've described?
Note I am trying to apply this effect to the live preview, not images that are already taken.
First when you open your camera instance with Camera.open() you should open front camera with Camera.open(getSpecialFacingCamera())
private int getSpecialFacingCamera() {
int cameraId = -1;
// Search for the front facing camera
int numberOfCameras = Camera.getNumberOfCameras();
for (int i = 0; i < numberOfCameras; i++) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
cameraId = i;
break;
}
}
return cameraId;
}
Then in your callback method where camera data is converting in to image
you can use this code to keep it normal
public void onPictureTaken(byte[] data, Camera camera){
Bitmap newImage = null;
Bitmap cameraBitmap;
if (data != null) {
cameraBitmap = BitmapFactory.decodeByteArray(data, 0, (data != null) ? data.length : 0);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
// use matrix to reverse image data and keep it normal
Matrix mtx = new Matrix();
//this will prevent mirror effect
mtx.preScale(-1.0f, 1.0f);
// Setting post rotate to 90 because image will be possibly in landscape
mtx.postRotate(90.f);
// Rotating Bitmap , create real image that we want
newImage = Bitmap.createBitmap(cameraBitmap, 0, 0, cameraBitmap.getWidth(), cameraBitmap.getHeight(), mtx, true);
}else{// LANDSCAPE MODE
//No need to reverse width and height
newImage = Bitmap.createScaledBitmap(cameraBitmap, screenWidth, screenHeight, true);
cameraBitmap = newImage;
}
}
}
you can pass newImage in canvas and create jpeg image and save it on device.
Do not forgot Camera is deprecated in Api level 21...
You can use Matrix to flip the image data, something like:
byte[] baImage = null;
Size size = camera.getParameters().getPreviewSize();
ByteArrayOutputStream os = new ByteArrayOutputStream();
YuvImage yuv = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
yuv.compressToJpeg(new Rect(0, 0, size.width, size.height), 100, os);
baImage = os.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length);
Matrix matrix = new Matrix();
matrix.preScale(-1.0f, 1.0f);
Bitmap mirroredBitmap = Bitmap.createBitmap(bitmap, 0, 0, size.width, size.height, matrix, false);

Saving the image to file is getting compressed in android

I am new to android.I have an application which has functionality to upload image from the gallery or take image from camera. Below I have written the code where I get the image.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode!=0){
if(PICK_MEDIA_FROM_GALLERY == requestCode){
if(null != data){
Uri uri = data.getData();
//String type = getMimeType(uri);
filePath = getRealPathFromURI(uri);
checkFileSupport(filePath);
}
}else{
if(ACTION_TAKE_PHOTO == requestCode){
checkFileSupport(filePath);
}else if(ACTION_TAKE_VIDEO == requestCode){
handleCameraVideo();
}
}
}
}
This function is used to fix the write orientation for the image.
public Bitmap fixOrientation(Bitmap bmp) {
try {
ExifInterface exif = new ExifInterface(filePath);
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
if (orientation==6)
{
Matrix matrix = new Matrix();
matrix.postRotate(90);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
}
else if (orientation==8)
{
Matrix matrix = new Matrix();
matrix.postRotate(270);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
}
else if (orientation==3)
{
Matrix matrix = new Matrix();
matrix.postRotate(180);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return bmp;
}
I set Image to imageview using the function
private void setImagePreview(final String realPath) throws IOException {
Display display = getWindowManager().getDefaultDisplay();
Bitmap bitmap = ImageUtils.getThumbnailBitmap(realPath, display.getWidth());
if(null!=bitmap){
//rotate image and save in the same filepath
bitmap = fixOrientation(bitmap);
FileOutputStream fOut = new FileOutputStream(filePath);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
fOut.flush();
fOut.close();
RelativeLayout tempLayout = (RelativeLayout) findViewById(R.id.previewLayout);
tempLayout.setVisibility(View.VISIBLE);
ImageView previewImageView = (ImageView) findViewById(R.id.previewImageView);
previewImageView.setImageBitmap(bitmap);
}
}
I have the an image in Camera.
When I select that image from Gallery for the first time,
When I try Changing the attachment and select the same picture the view appears like this
How can I solve this issue?Can anyone please help me out?
Your code seems to be OK. Whenever I resize the image I use BitmapFactory.Options class. See this class.
What Bitmap bitmap = ImageUtils.getThumbnailBitmap(realPath, display.getWidth()); returns? A full bitmap or a Thumbnail? Thumbnail is a pretty small.
It seems that you are changing the original image instead of copy of the image. Get the file path and create your image by yourself. And, to avoid OutOfMemoryException use BitmapFactory.Options property InSampleSize. I am not sure about property. Just Google out and you will find.
I hope this helps you solve your problem.
Your second image quality seems worse than the first one. You can check whether you set ImageView width and height wrap_content? If yes, try to set a fixed value for test. and whether the two bitmap sizes are same, width and height?

Categories

Resources