Objective of the program: the user is able to place one picture on the top of camera preview and move it freely (image is big 1920x1080 pixels) and can store this two layers (picture and camera preview) pressing the photo button. So far he is only able to save one picture of this kind because when he takes the second one the out of memory error problem appears.
Solution It seems that the problem can be solved if you use recycle bitmap function when you dont need to use bitmaps anymore. Or you can resize them (didn't want to)... Are these good ideas?
Code:
private PictureCallback mPicture = new PictureCallback()
{
#Override
public void onPictureTaken(byte[] data, Camera camera)
{
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
mPreview.setDrawingCacheEnabled(true);
mPreview.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_AUTO);
Bitmap bitmap = mPreview.getDrawingCache();
bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
combination = overlay(bmp, bitmap);
if(pictureFile == null)
{
return;
}
try
{
FileOutputStream fos = new FileOutputStream(pictureFile);
combination.compress(CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "MyCameraApp");
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://"+ mediaStorageDir)));
}
catch(FileNotFoundException e)
{
Log.d(TAG, "File not found: "+e.getMessage());
}
catch(IOException e)
{
Log.d(TAG, "Error accessing file: "+e.getMessage());
}
}
};
public static Bitmap overlay(Bitmap bmp1, Bitmap bmp2)
{
Bitmap bmOverlay = Bitmap.createBitmap(bmp1.getWidth(), bmp1.getHeight(),bmp1.getConfig());
Canvas canvas = new Canvas(bmOverlay);
canvas.drawBitmap(bmp1, new Matrix(), null);
canvas.drawBitmap(bmp2, null, new Rect(0,0,bmp1.getWidth(), bmp1.getHeight()), null);
return bmOverlay;
}
private static File getOutputMediaFile(int type)
{
File mediaFile = null;
if(isSdPresent() == false)
{
Log.d(TAG, "There is no Sd card. Cannot use the camera");
}
else
{
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "World Cup Camera");
if(!mediaStorageDir.exists())
{
if(!mediaStorageDir.mkdirs())
{
Log.d("WorldCupApp", "failed to create directory");
return null;
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
if (type == MEDIA_TYPE_IMAGE)
{
mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_"+ timeStamp + ".jpg");
}
else
{
return null;
}
}
return mediaFile;
}
I heard about this code should I use?
private Bitmap decodeFile(File f)
{
try
{
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//The new size we want to scale to
final int REQUIRED_SIZE=70;
//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;
//Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
}
catch (FileNotFoundException e) {}
return null;
}
You can use android:largeHeap="true" inside the application tag on AndroidManifest when you're having outofmemory errors.
Related
I'm building an android tesseract app. It was reading the data fine until I was taking photos from the default camera app. Now, I needed to implement my own custom camera, that caused it to start giving wrong result.
public class getButtonClicked implements View.OnClickListener{
public void onClick(View arg0) {
DATA_PATH = Environment.getExternalStorageDirectory().toString() + "/MyOCRApp/";
File tessdata = new File(DATA_PATH);
if (!tessdata.isDirectory()){
throw new IllegalArgumentException("Data path must contain subfolder tessdata!");
}
TessBaseAPI baseApi = new TessBaseAPI();
baseApi.setDebug(true);
baseApi.init(DATA_PATH, lang);
if (newImg == null){
baseApi.setImage(imageBitmap);
}
else{
baseApi.setImage(newImg);
}
String recognizedText = baseApi.getUTF8Text();
// 1. Instantiate an AlertDialog.Builder with its constructor
AlertDialog.Builder builder = new AlertDialog.Builder(context);
// 2. Chain together various setter methods to set the dialog characteristics
builder.setMessage("Recognized Text:\n\n" + recognizedText);
// 3. Get the AlertDialog from create()
AlertDialog dialog = builder.create();
dialog.show();
//baseApi.end();
}
}
This is the code that calls the tesseract APIs.
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null){
Log.d("Error creating file" ,"!");
return;
}
int screenWidth = getResources().getDisplayMetrics().widthPixels;
int screenHeight = getResources().getDisplayMetrics().heightPixels;
bm = BitmapFactory.decodeByteArray(data, 0, (data != null) ? data.length : 0);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
// Notice that width and height are reversed
Bitmap scaled = Bitmap.createScaledBitmap(bm, screenHeight, screenWidth, true);
int w = scaled.getWidth();
int h = scaled.getHeight();
// Setting post rotate to 90
Matrix mtx = new Matrix();
mtx.postRotate(90);
// Rotating Bitmap
MainActivity.imageBitmap = Bitmap.createBitmap(scaled, 0, 0, w, h, mtx, true);
}else{// LANDSCAPE MODE
//No need to reverse width and height
Bitmap scaled = Bitmap.createScaledBitmap(bm, screenWidth,screenHeight , true);
MainActivity.imageBitmap = scaled;
}
Calendar c = Calendar.getInstance();
String time = Integer.toString(c.get(Calendar.DATE));
//MediaStore.Images.Media.insertImage(getContentResolver(), MainActivity.imageBitmap, time+"MyOCR", "Hello!!");
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/MyOCRApp");
if (! myDir.exists()){
if (! myDir.mkdirs()){
Log.d("MyCameraApp", "failed to create directory");
return;
}
}
String fname = "Image-" +time+ ".jpg";
File file = new File(myDir, fname);
if (file.exists())
file.delete();
try {
FileOutputStream out = new FileOutputStream(file);
MainActivity.imageBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
MediaStore.Images.Media.insertImage(getContentResolver(), file.getAbsolutePath(), file.getName(), file.getName());
} catch (Exception e) {
e.printStackTrace();
}
surfaceDestroyed(mSurfaceHolder);
}
};
This is the code in my camera class. I even debugged and checked that the picture was perfectly fine, when the tesseract APIs are called. I can't post photos, otherwise I have posted one. What should I do??
I am experimenting with tesseract on android as well. Try to rescale your image. An image taken by the camera activity maybe to big. Additionaly you probably have to pre-process the image (contrast, horizontal alignment of text, ...)
How can I call Bitmap Inside a onPictureTaken method ?. Image is not storing in a gallery until and unless I restart my phone
Please Help in re-arranging the code.
public static int getOrientation(Context context,Uri photoUri){
Cursor cursor = context.getContentResolver().query(photoUri,new String[] {MediaStore.Images.ImageColumns.ORIENTATION},null,null,null);
if(cursor.getCount()!=1){
return -1;
}
cursor.moveToFirst();
return cursor.getInt(0);
}
getCorrectlyOrientatedImage() is never used. Please help me in where can I call this function.
public static Bitmap getCorrectlyOrientatedImage(Context context, Uri photoUri)throws IOException{
InputStream is=context.getContentResolver().openInputStream(photoUri);
BitmapFactory.Options dbo = new BitmapFactory.Options();
dbo.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is,null,dbo);
is.close();
int rotatedWidth,rotatedHeight;
int orientation = getOrientation(context,photoUri);
if(orientation == 90 || orientation ==270){
rotatedWidth=dbo.outHeight;
rotatedHeight=dbo.outWidth;
}else{
rotatedWidth=dbo.outWidth;
rotatedHeight=dbo.outHeight;
}
Bitmap srcBitmap;
is = context.getContentResolver().openInputStream(photoUri);
if(rotatedWidth > MAX_IMAGE_DIMENSION || rotatedHeight > MAX_IMAGE_DIMENSION ){
float widthRatio = ((float) rotatedWidth) / ((float) MAX_IMAGE_DIMENSION);
float heightRatio = ((float) rotatedHeight) / ((float) MAX_IMAGE_DIMENSION);
float maxRatio = Math.max(widthRatio,heightRatio);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = (int) maxRatio;
srcBitmap = BitmapFactory.decodeStream(is, null, options);
}else{
srcBitmap = BitmapFactory.decodeStream(is);
}
is.close();
if(orientation > 0){
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
srcBitmap = Bitmap.createBitmap(srcBitmap,0,0,srcBitmap.getWidth(),srcBitmap.getHeight(),matrix,true);
}
return srcBitmap;
}
private PictureCallback mPicture = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
Log.d("onPictureTaken", "File is assigned to pictureFile");
if (pictureFile == null) {
Log.d(DEBUG_TAG, " Error creating a media file, check storage permissions:");
return;
}
try {
Bitmap bitmap=getCorrectlyOrientatedImage()
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "SELFie");
String path = mediaStorageDir.getPath() + File.separator + "IMG_Some_name.jpg";
SCamera.this.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + path)));
} catch (FileNotFoundException e) {
Log.d("DG_DEBUG", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("DG_DEBUG", "Error accessing file: " + e.getMessage());
}
}
};
Image is not storing in a SDcard Untill I reboot my phone and also image which is stored is stored in a wrong direction. If photo is taken in portrait , image is stored in landscape . How can store the image in correct orientation.
private static File getOutputMediaFile(int type){
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"SELFie");
if(!mediaStorageDir.exists()){
if(!mediaStorageDir.mkdir()){
Log.d(DEBUG_TAG,"Filed to create directory");
return null;
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE){
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
} else {
return null;
}
return mediaFile;
}
I know this question is a little old, but just in case someone faces the same issue, the solution is to save the image in a background thread as shown in this github link.
private PictureCallback mPicture = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
new SaveImageTask().execute(data);
}
};
private class SaveImageTask extends AsyncTask<byte[], Void, Void> {
#Override
protected Void doInBackground(byte[]... data) {
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
Log.d("onPictureTaken", "File is assigned to pictureFile");
if (pictureFile == null) {
Log.d(DEBUG_TAG, " Error creating a media file, check storage permissions:");
return null;
}
try {
Bitmap bitmap=getCorrectlyOrientatedImage()
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "SELFie");
String path = mediaStorageDir.getPath() + File.separator + "IMG_Some_name.jpg";
SCamera.this.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + path)));
} catch (FileNotFoundException e) {
Log.d("DG_DEBUG", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("DG_DEBUG", "Error accessing file: " + e.getMessage());
}
}
}
I'm trying to take a picture and add an overlay on top of it. Here is my code (only the callback) :
private PictureCallback mPicture = new PictureCallback() {
#Override
public void onPictureTaken(final byte[] data, Camera camera) {
if(!dirFile.exists()){
dirFile.mkdirs();
}
try {
String name = new SimpleDateFormat("ddMMyyyy_HHmmss").format(new Date()) + ".jpg";
picturePath = new File(dirFile, name);
new AsyncTask<Void, Void, Void>(){
FileOutputStream fos = new FileOutputStream(picturePath);
Bitmap photo;
#Override
protected Void doInBackground(Void... params) {
photo = BitmapFactory.decodeByteArray(data, 0, data.length).copy(Config.ARGB_8888, true);
Bitmap cadre = BitmapFactory.decodeResource(getResources(), R.drawable.cadre16001200);
Canvas canvas = new Canvas(photo);
canvas.drawBitmap(cadre, new Matrix(), null);
cadre.recycle();
photo.compress(CompressFormat.JPEG, 100, fos);
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
geotag(picturePath.toString());
return null;
}
protected void onPostExecute(Void result) {
dialog.dismiss();
mCamera.startPreview();
//Affiche la nouvelle photo
picture.setImageBitmap(photo);
};
}.execute();
} catch (FileNotFoundException e) {
Log.d("PhotoActivity", "File not found: " + e.getMessage());
}
}
};
I get the following error on my Samsung Galaxy S3 (android 4.1.2) , with an OutOfMemoryException
07-04 10:01:24.076: E/dalvikvm-heap(2980): Out of memory on a 7680016-byte allocation.
Weird thing is that it works perfectly on the Samsung Gio (android 2.2.1) with the same resolution of 1600x1200.
I googled a lot, and I can't use the main solution of downsizing the picture. It is a memory issue, but I don't know how I can reduce the memory usage.
EDIT : I found this, seems it was the real matter : https://stackoverflow.com/a/12377158/1343969
you should decode the bitmap before proccessing it to the UI, here's a code example
private Bitmap decodeFile(File f){
try {
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream stream1=new FileInputStream(f);
BitmapFactory.decodeStream(stream1,null,o);
stream1.close();
//Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE=70;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
FileInputStream stream2=new FileInputStream(f);
Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
stream2.close();
return bitmap;
} catch (FileNotFoundException e) {
}
catch (IOException e) {
e.printStackTrace();
}
return null;
}
You should simply call the empty constructor of Canvas and draw the photo on it. This would remove the copy() call and reduce the memory usage.
photo = BitmapFactory.decodeByteArray(data, 0, data.length);
Bitmap cadre = BitmapFactory.decodeResource(getResources(), R.drawable.cadre16001200);
Canvas canvas = new Canvas();
canvas.drawBitmap(photo, 0, 0, null);
canvas.drawBitmap(cadre, new Matrix(), null);
cadre.recycle();
photo.compress(CompressFormat.JPEG, 100, fos);
I am trying to integrate camera access to my android application.My requirements are making a preview of the photo taken and store the same on the SD card.But making a preview and storing on the sd card are working fine separately.But when i integrate both into a single application it doesnt work.And i am using the standard code given in the developer site for my storage on SD card.
here is my code
public void pickImage(View View) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name
startActivityForResult(intent, REQUEST_CODE);
}
private static Uri getOutputMediaFileUri(int type){
return Uri.fromFile(getOutputMediaFile(type));
}
private static File getOutputMediaFile(int type){
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "Sparikko");
// This location works best if you want the created images to be shared
// between applications and persist after your app has been uninstalled.
// Create the storage directory if it does not exist
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("Sparikko", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE){
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
} else {
return null;
}
return mediaFile;
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK)
try {
// We need to recyle unused bitmaps
if (bitmap != null) {
bitmap.recycle();
}
InputStream stream = getContentResolver().openInputStream(data.getData());
bitmap = BitmapFactory.decodeStream(stream);
stream.close();
imageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
super.onActivityResult(requestCode, resultCode, data);
}
I am getting a application is stopped unexpectedly error.And i used logcat to find where i could find the program control where the error happens.And i found that the error happens in InputStream stream = getContentResolver().openInputStream(data.getData()); line in the onActivityResult() function.Both funcationality works fine seperately bt giving error when combined.
after taking picture from camera you need to downscale bitmap to set on ImageView to show preview. refer below method:
private void showAttachedImagePreview(String imagePath)
{
Bitmap bitmap = null;
//= BitmapFactory.decodeFile(imagePath);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
try
{
bitmap = BitmapFactory.decodeFile(imagePath, options);
}
catch (OutOfMemoryError e)
{
e.printStackTrace();
bitmap=null;
try
{
options.inSampleSize = 2;
bitmap = BitmapFactory.decodeFile(imagePath, options);
}
catch (OutOfMemoryError e1)
{
e1.printStackTrace();
bitmap=null;
try
{
options.inSampleSize = 3;
bitmap = BitmapFactory.decodeFile(imagePath, options);
}
catch (OutOfMemoryError e2)
{
e2.printStackTrace();
bitmap=null;
try
{
options.inSampleSize = 4;
bitmap = BitmapFactory.decodeFile(imagePath, options);
}
catch (OutOfMemoryError e3)
{
e3.printStackTrace();
bitmap=null;
}
}
}
}
if(bitmap!=null)
{
commentAttachedImagePreview.setVisibility(ImageView.VISIBLE);
commentAttachedImagePreview.setImageBitmap(bitmap);
commentAttachedImageName.setVisibility(TextView.VISIBLE);
commentAttachedImageName.setText(new File(imagePath).getName());
deleteAttachedImage.setVisibility(ImageView.VISIBLE);
}
try
{
File file = new File(AppManager.getInstance().DATA_DIRECTORY, "tausif_tmp.png");
FileOutputStream outStream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, outStream);
outStream.flush();
outStream.close();
filePath = file.getPath();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
I have an Android app which is crashing on some phones, and not on others. It has about 5k downloads, and so far has received about 50 crash reports. However, based on the amount of ratings/comments I get from users saying that it's force crashing, I think the percentage of affected users is actually much higher.
As the issue doesn't affect my phone, I've been unable to reproduce the error and debug it as I would like to.
The app takes a picture from the camera, overlays a bitmap on it, and saves the resulting image to the SD card.
Below is my code for the onPictureTaken PictureCallback method.
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
captureBtn.setVisibility(ImageButton.INVISIBLE);
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null){
return;
}
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap mutableBitmap = null;
Bitmap finalBitmap = null;
byte[] byteArray = null;
try {
mutableBitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options).copy(Bitmap.Config.RGB_565, true);
Matrix matrix = new Matrix();
int width = mutableBitmap.getWidth();
int height = mutableBitmap.getHeight();
int newWidth = overlayView.getDrawable().getBounds().width();
int newHeight = overlayView.getDrawable().getBounds().height();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
matrix.postScale(scaleWidth, scaleHeight);
matrix.postRotate(90);
Bitmap resizedBitmap = Bitmap.createBitmap(mutableBitmap, 0, 0, mutableBitmap.getWidth(), mutableBitmap.getHeight(), matrix, true);
finalBitmap = resizedBitmap.copy(Bitmap.Config.RGB_565, true);
Canvas canvas = new Canvas(finalBitmap);
Bitmap overlayBitmap = null;
if (mWeaponType == wep1) {
overlayBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.wep1);
} else if (mWeaponType == wep2) {
overlayBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.wep2);
}
if (overlayBitmap != null) {
matrix = new Matrix();
matrix.postRotate(90);
Bitmap resizedOverlay = Bitmap.createBitmap(overlayBitmap, 0, 0, overlayBitmap.getWidth(), overlayBitmap.getHeight(), matrix, true);
canvas.drawBitmap(resizedOverlay, 0, 0, new Paint());
canvas.scale(50, 0);
canvas.save();
//finalBitmap is the image with the overlay on it
// rotate image to save in landscape mode
matrix = new Matrix();
matrix.postRotate(270);
finalBitmap = Bitmap.createBitmap(finalBitmap, 0, 0, finalBitmap.getWidth(), finalBitmap.getHeight(), matrix,
true);
// convert final bitmap to byte array
ByteArrayOutputStream stream = new ByteArrayOutputStream();
finalBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byteArray = stream.toByteArray();
}
}
catch(OutOfMemoryError e) {
//fail
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(byteArray);
fos.close();
// Notify system that SD card has been updated
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
Log.i(TAG, "Picture saved, intent broadcast that SD has been updated");
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
} catch (NullPointerException e) {
}
finally {
mCamera.startPreview();
captureBtn.setVisibility(ImageButton.VISIBLE);
}
}
};
I get a NullPointerException as follows:
java.lang.NullPointerException
at java.io.FileOutputStream.write(FileOutputStream.java:256)
at com.mypackage.MyActivity.onPictureTaken(MyActivity.java:215)
which is the
fos.write(byteArray);
line.
The getOutputMediaFile method listed above is as follows:
/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
File mediaStorageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
// Create the storage directory if it does not exist
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("HalfLife2 Booth", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE){
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
} else if(type == MEDIA_TYPE_VIDEO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"VID_"+ timeStamp + ".mp4");
} else {
return null;
}
return mediaFile;
}
I think that the problem may be in here somewhere, in trying to get an output media file. I've tried updating the app to use:
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "MyApp");
instead, and one user has reported the issue to be fixed, but several have reported that it persists.
Any ideas, anyone? I'm finding this a tricky one to debug/fix when I can't reproduce or get anywhere near it.
Make sure you are scaling your pictures in their raw format. I found that the raw images are HUGE on some phone models. I recommend scaling the image if it's very large because you will run your virtual machine out of memory.
Example:
imageRef = sd_card_path+"/"+ImageName;
BitmapFactory.Options resample = new BitmapFactory.Options();
resample.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imageRef, resample);
int width = resample.outWidth;
int height = resample.outHeight;
if(width*height > utility.IMAGE_SIZE_MIN){
int imageSizef = (int)(width*height/utility.IMAGE_SIZE_MIN);
String imageSize = imageSizef+"";
resample.inSampleSize = Integer.parseInt(imageSize);
resample.inJustDecodeBounds = false;
image.setImageBitmap(BitmapFactory.decodeFile(imageRef , resample));
}else{
image.setImageBitmap(BitmapFactory.decodeFile(imageRef ));
}
Given the Exception trace it would suggest that you are hitting an OutOfMemorryError and as such the byteArray is never getting populated so you are passing null to the fos.write method