I'm making an app that allows a user to capture and image and then use that image on a puzzle. I can use the camera successfully but after image capture, when I'm supposed to be taken to the puzzle screen where the image is loaded from local storage, I get an FNF exception. (I have a section in the app that shows the images that the user can use for the puzzle and the newly captured image shows up there - after restarting the app since it has crashed).
My code is as follows
public static Bitmap decodeSampledBitmapFromPath(String filepath, int reqWidth, int reqHeight) throws FileNotFoundException {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filepath);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
return Bitmap.createScaledBitmap(BitmapFactory.decodeFile(filepath),
reqWidth, reqHeight, false);
}
Exception is thrown on the return line. Please help me resolve this. Thank you.
Edit: wrapped try catch around return line and now Logcat displays
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
at apps.mine.puzzle.Board.countTileSize(Board.java:60)
at apps.mine.puzzle.PlayPuzzleActivity.onCreate(PlayPuzzleActivity.java:138)
I had similar issue , this will fix it:
if(BitmapFactory.decodeFile(Image[position])!=null)
{
Bitmap bitmap=Bitmap.createScaledBitmap(BitmapFactory.decodeFile(Image[position]), 32, 32, true);
imageView.setImageBitmap(bitmap);
}
else
{
Log.d("TAG", "unable to decode");
}
the main cause of the issue is that decodeResource is returning you a null for one of the following reasons :
The image file is corrupt
No read permission
There is not enough memory to decode the file
The resource does not exist
Invalid options specified in the options variable.
UPADTE
if you don't want to decode the file twice as #Zoe pointed out, you can modify the code of decodeResource so it'll null-check without having to do it twice, like this :
public class BitmapScalingHelper
{
public static Bitmap decodeResource(Resources res, int resId, int dstWidth, int dstHeight)
{
Options options = new Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inJustDecodeBounds = false;
options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, dstWidth,
dstHeight);
options = new Options();
Bitmap unscaledBitmap = BitmapFactory.decodeResource(res, resId, options);
if(unscaledBitmap == null)
{
Log.e("ERR","Failed to decode resource" + resId + " " + res.toString());
return null;
}
return unscaledBitmap;
}
}
Related
Since android 10 there is some changes in accessing media files. After going through documentation https://developer.android.com/training/data-storage/shared/media i have been able to load the media content in to a bitmap, but i didn't get the orientation information. I know there is some restriction to the location information of the image, but does these exif restrictions also effect orientation information? If there is any other way to get an image's orientation information, please let me know. The code am using is given below (which is always returning 0 - Value for undefined). Thank you.
ContentResolver resolver = getApplicationContext().getContentResolver();
try (InputStream stream = resolver.openInputStream(selectedFileUri)) {
loadedBitmap = BitmapFactory.decodeStream(stream);
ExifInterface exif = new ExifInterface(stream);
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
}
BitmapFactory.decodeStream consumed the whole stream and closed it.
You should open a new stream first before trying to read the exif.
Firstly, consider the API used in different SDK version, please use the AndroidX ExifInterface Library
Secondly, ExifInterface for reading and writing Exif tags in various image file formats. Supported for reading: JPEG, PNG, WebP, HEIF, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF.
But you use it for bitmap, Bitmap does not have any EXIF headers. You already threw away any EXIF data when you loaded the Bitmap from wherever it came from. Use ExifInterface on the original source of the data, not the Bitmap
you can try to use the following code to get the info and remember to use the original stream.
public static int getExifRotation(Context context, Uri imageUri) throws IOException {
if (imageUri == null) return 0;
InputStream inputStream = null;
try {
inputStream = context.getContentResolver().openInputStream(imageUri);
ExifInterface exifInterface = new ExifInterface(inputStream);
int orienttation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)
switch (orienttation) {
case ExifInterface.ORIENTATION_ROTATE_90:
return 90;
case ExifInterface.ORIENTATION_ROTATE_180:
return 180;
case ExifInterface.ORIENTATION_ROTATE_270:
return 270;
default:
return ExifInterface.ORIENTATION_UNDEFINED;
}
}finally {
//here to close the inputstream
}
}
I want to find a face on an image from camera. But detector can't find faces. My app does photo and save it in file.
Below code which create file, start camera, and in onActivityResult in trying detect face and save file path to the room, its saving correctrly and showing in recycler view as expected, but face detector dont finding faces. how can i fix this?
private fun takePhoto() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (takePictureIntent.resolveActivity(activity?.packageManager!!) != null) {
val photoFile: File
try {
photoFile = createImageFile()
} catch (e: IOException) {
error { e }
}
val photoURI = FileProvider.getUriForFile(activity?.applicationContext!!, "com.nasibov.fakhri.neurelia.fileprovider", photoFile)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
takePictureIntent.putExtra("android.intent.extras.CAMERA_FACING", 1)
startActivityForResult(takePictureIntent, PhotoFragment.REQUEST_TAKE_PHOTO)
}
}
#Suppress("SimpleDateFormat")
private fun createImageFile(): File {
val date = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val fileName = "JPEG_$date"
val filesDir = activity?.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
val image = File.createTempFile(fileName, ".jpg", filesDir)
mCurrentImage = image
return mCurrentImage
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_TAKE_PHOTO && resultCode == Activity.RESULT_OK) {
val bitmap = BitmapFactory.decodeFile(mCurrentImage.absolutePath)
val frame = Frame.Builder().setBitmap(bitmap).build()
val detectedFaces = mFaceDetector.detect(frame)
mViewModel.savePhoto(mCurrentImage)
}
}
Android Face detection API tracks face in photos, videos using some landmarks like eyes, nose, ears, cheeks, and mouth.
Rather than detecting the individual features, the API detects the face at once and then if defined, detects the landmarks and classifications. Besides, the API can detect faces at various angles too.
https://www.journaldev.com/15629/android-face-detection
Android SDK contains an API for Face Detection: android.media.FaceDetector class. This class detects faces on the image. To detect faces call findFaces method of FaceDetector class. findFaces method returns a number of detected faces and fills the FaceDetector.Faces[] array. Please note, that findFaces method supports only bitmaps in RGB_565 format at this time.
Each instance of the FaceDetector.Face class contains the following information:
Confidence that it’s actually a face – a float value between 0 and 1.
Distance between the eyes – in pixels.
Position (x, y) of the mid-point between the eyes.
Rotations (X, Y, Z).
Unfortunately, it doesn’t contain a framing rectangle that includes the detected face.
Here is sample source code for face detection. This sample code enables a custom View that shows a saved image from an SD Card and draws transparent red circles on the detected faces.
class Face_Detection_View extends View {
private static final int MAX_FACES = 10;
private static final String IMAGE_FN = "face.jpg";
private Bitmap background_image;
private FaceDetector.Face[] faces;
private int face_count;
// preallocate for onDraw(...)
private PointF tmp_point = new PointF();
private Paint tmp_paint = new Paint();
public Face_Detection_View(Context context) {
super(context);
// Load an image from SD Card
updateImage(Environment.getExternalStorageDirectory() + "/" + IMAGE_FN);
}
public void updateImage(String image_fn) {
// Set internal configuration to RGB_565
BitmapFactory.Options bitmap_options = new BitmapFactory.Options();
bitmap_options.inPreferredConfig = Bitmap.Config.RGB_565;
background_image = BitmapFactory.decodeFile(image_fn, bitmap_options);
FaceDetector face_detector = new FaceDetector(
background_image.getWidth(), background_image.getHeight(),
MAX_FACES);
faces = new FaceDetector.Face[MAX_FACES];
// The bitmap must be in 565 format (for now).
face_count = face_detector.findFaces(background_image, faces);
Log.d("Face_Detection", "Face Count: " + String.valueOf(face_count));
}
public void onDraw(Canvas canvas) {
canvas.drawBitmap(background_image, 0, 0, null);
for (int i = 0; i < face_count; i++) {
FaceDetector.Face face = faces[i];
tmp_paint.setColor(Color.RED);
tmp_paint.setAlpha(100);
face.getMidPoint(tmp_point);
canvas.drawCircle(tmp_point.x, tmp_point.y, face.eyesDistance(),
tmp_paint);
}
}
}
I continuously get OutOfMemory exceptions trying to decode an image from camera in my Android app. There are many questions dealing with the problem, but my case is especially weird because I get the exception even when just trying to get the bounds with options.inJustDecodeBounds=true.
Here's the code that starts the camera:
protected void takePicture() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File image = new File(IMAGE_PATH, "camera.jpg");
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(image));
startActivityForResult(takePictureIntent, 0);
}
Here's the code that triggers the exception:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK ) {
String rawImageName = new String(IMAGE_PATH + "/camera.jpg");
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(rawImageName); // The exception is thrown here
.
.
.
}
}
I tried to decode the image using a very high sampling rate, but still I get the same exception:
options.inSampleSize = 20;
options.inJustDecodeBounds = false;
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap photo = BitmapFactory.decodeFile(rawImageName); // Again the exception
Except for that, the application seems to run correctly and there is enough free memory. I can open correctly the image in the gallery app. Moving the image to a different directory didn't help. Any ideas what could cause it? What could possibly cause the exception while decoding with inJustDecodeBounds = true?
You need to pass the options to the decode call:
BitmapFactory.decodeFile(rawImageName, options);
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = 4; // 1/4
o2.inPurgeable = true;
Bitmap b=BitmapFactory.decodeFile(imagePath,o2);
try this. and also resize your image and make bitmap objects null after use.
give call to System.gc(); it doesn call gc but it gives hint.
also dont make lots of bitmap objects. reuse the same bitmap object and make it null after use.
I am creating this game for Android with Java. I am using this code: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html for resizing Bitmaps, I am using .PNG format on all my images. It works really well except that the Bitmaps quality drops quite a lot, even when I scale it down from a larger image. Is this solvable?
You can try out this code.
public static Bitmap shrinkBitmap(String p_file, int p_width, int p_height)
{
BitmapFactory.Options m_bmpFactoryOptions = new BitmapFactory.Options();
m_bmpFactoryOptions.inJustDecodeBounds = true;
Bitmap m_bitmap = BitmapFactory.decodeFile(p_file, m_bmpFactoryOptions);
int m_heightRatio =
(int) Math.ceil(m_bmpFactoryOptions.outHeight / (float) p_height);
int m_widthRatio =
(int) Math.ceil(m_bmpFactoryOptions.outWidth / (float) p_width);
if (m_heightRatio > 1 || m_widthRatio > 1)
{
if (m_heightRatio > m_widthRatio)
{
m_bmpFactoryOptions.inSampleSize = m_heightRatio;
}
else
{
m_bmpFactoryOptions.inSampleSize = m_widthRatio;
}
}
m_bmpFactoryOptions.inJustDecodeBounds = false;
m_bitmap = BitmapFactory.decodeFile(p_file, m_bmpFactoryOptions);
return m_bitmap;
}
EDITED:
Here i have tried out other way also.
Can you please let me know how you are scaling .PNGs so that i can get the idea.
I have the following problem:
String explosion_type = this.prefs.getString("explosion_type", "ring_explosion");
BitmapFactory.Options optionsExplosion = new BitmapFactory.Options();
optionsExplosion.inPurgeable = true;
this._explosionSprite = BitmapFactory.decodeResource(_context.getResources(),
com.forwardapps.liveitems.R.drawable.explosion, optionsExplosion);
I'm trying to use a String in place of the resource name, that way I can hotswap resources in the preference menu. This method causes the app to crash.
What is the proper way of implementing a situation like this? (Without making it too complicated or using if statements)
Use method getIdentifier on Resources object to fetch id of a drawable:
String explosion_type = this.prefs.getString("explosion_type", "ring_explosion");
Log.i("imagename", explosion_type);
BitmapFactory.Options optionsExplosion = new BitmapFactory.Options();
optionsExplosion.inPurgeable = true;
int imageResource = getResources().getIdentifier(explosion_type, "drawable", getPackageName());
this._explosionSprite = BitmapFactory.decodeResource(_context.getResources(), imageResource, optionsExplosion);