I am using Android Intent to take a photo.
startActivityForResult(intent, 0);
This opens the native camera and i can take a picture.
In the Activity where the picture is returned to , in the onActivityResult method , I can get a hold of the returned Bitmap like so.
if (requestCode == 0 && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
I then wish to convert this to a Mat to do some openCV image processing.
I am attempting to convert like this.
Mat src = new Mat(imageBitmap.getHeight(), imageBitmap.getWidth(), CvType.CV_8UC4);
Utils.bitmapToMat(imageBitmap, src);
The line above causes a crash with the following stack trace .
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.i330155.testing123, PID: 16349
java.lang.UnsatisfiedLinkError: No implementation found for long org.opencv.core.Mat.n_Mat(int, int, int) (tried Java_org_opencv_core_Mat_n_1Mat and Java_org_opencv_core_Mat_n_1Mat__III)
at org.opencv.core.Mat.n_Mat(Native Method)
at org.opencv.core.Mat.<init>(Mat.java:37)
at com.example.testing123.MainActivity.onActivityResult(MainActivity.java:48)
at android.app.Activity.dispatchActivityResult(Activity.java:7022)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4248)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4295)
at android.app.ActivityThread.-wrap20(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1583)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6290)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
After searching i found the following post.
http://answers.opencv.org/question/52722/what-is-the-correct-way-to-convert-a-mat-to-a-bitmap/
Which says that.
mat is a valid input Mat object of the types 'CV_8UC1', 'CV_8UC3' or 'CV_8UC4'.
bmp is a valid Bitmap object of the same size as the Mat and of type 'ARGB_8888' or 'RGB_565'.
As you can see in the constructor for the Mat I supply these args.
I have checked the config of the imageBitmap , which confirms that it is indeed
a 'RGB_565'.
What am i missing here? I dont understand why this does not work.
Thanks in advance.
import android.content.Intent;
import android.graphics.Bitmap;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import org.opencv.android.Utils;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.imgproc.Imgproc;
public class MainActivity extends AppCompatActivity {
Button button ;
ImageView mImageView ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.capture) ;
mImageView = (ImageView)findViewById(R.id.imageView) ;
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
startActivityForResult(intent, 0);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 0 && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
Bitmap.Config config = imageBitmap.getConfig();
//this is throwing error
Mat src = new Mat(imageBitmap.getHeight(), imageBitmap.getWidth(), CvType.CV_8UC3);
Utils.bitmapToMat(imageBitmap, src);
Imgproc.Canny(src, src, 10, 100);
Bitmap edgeBitmap = Bitmap.createBitmap(imageBitmap.getWidth(), imageBitmap.getHeight(), Bitmap.Config.ARGB_8888);
// Utils.matToBitmap(dest, edgeBitmap);
mImageView.setImageBitmap(imageBitmap);
}
}
}
When debugging this method call :
Mat src = new Mat(imageBitmap.getHeight(), imageBitmap.getWidth(),
CvType.CV_8UC3);
calls another method
nativeObj = n_Mat(rows, cols, type);
this n_Mat is declared like so.
// C++: Mat::Mat(int rows, int cols, int type)
private static native long n_Mat(int rows, int cols, int type);
and is highlighted in red.
The application no longer crashes and functions as expected.
This post covers it quite well.
No implementation found for long org.opencv.core.Mat.n_Mat() error Using OpenCV
org-opencv-core-mat-n-mat-error-using-opencv
Related
I am trying to create an app that can classify an image using TFlite, based upon a learned model created on Teachable Machine.
I am struggling to find a way to give the user an option to crop the image before it is classified. Here is my code for the Java class:
package com.example.app;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.media.ThumbnailUtils;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.app.R;
import com.example.app.ml.Model;
import org.tensorflow.lite.DataType;
import org.tensorflow.lite.support.tensorbuffer.TensorBuffer;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class MainActivity extends AppCompatActivity {
TextView result, confidence;
ImageView imageView;
Button picture;
int imageSize = 224;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
result = findViewById(R.id.result);
confidence = findViewById(R.id.confidence);
imageView = findViewById(R.id.imageView);
picture = findViewById(R.id.button);
picture.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Launch camera if we have permission
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, 1);
} else {
//Request camera permission if we don't have it.
requestPermissions(new String[]{Manifest.permission.CAMERA}, 100);
}
}
}
});
}
public void classifyImage(Bitmap image){
try {
Model model = Model.newInstance(getApplicationContext());
// Creates inputs for reference.
TensorBuffer inputFeature0 = TensorBuffer.createFixedSize(new int[]{1, 224, 224, 3}, DataType.FLOAT32);
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4 * imageSize * imageSize * 3);
byteBuffer.order(ByteOrder.nativeOrder());
int [] intValues = new int[imageSize * imageSize];
image.getPixels(intValues, 0, image.getWidth(), 0, 0, image.getWidth(), image.getHeight());
int pixel = 0;
for(int i = 0; i < imageSize; i++){
for(int j = 0; j < imageSize; j++){
int val = intValues[pixel++]; // RGB
byteBuffer.putFloat(((val >> 16 ) & 0xFF) * (1.f / 255.f));
byteBuffer.putFloat(((val >> 8 ) & 0xFF) * (1.f / 255.f));
byteBuffer.putFloat((val & 0xFF ) * (1.f / 255.f));
}
}
inputFeature0.loadBuffer(byteBuffer);
// Runs model inference and gets result.
Model.Outputs outputs = model.process(inputFeature0);
TensorBuffer outputFeature0 = outputs.getOutputFeature0AsTensorBuffer();
float[] confidences = outputFeature0.getFloatArray();
int maxPos = 0;
float maxConfidence = 0;
for(int i = 0; i < confidences.length; i++){
if(confidences[i] > maxConfidence){
maxConfidence = confidences[i];
maxPos = i;
}
}
String[] classes = {"Negative", "+/-100", "250", "500", "1000", ">=2000"};
result.setText(classes[maxPos]);
String s = "";
for(int i = 0; i < classes.length; i++){
s += String.format("%s: %.1f%%\n", classes[i], confidences[i] * 100);
}
confidence.setText(s);
// Releases model resources if no longer used.
model.close();
} catch (IOException e) {
// TODO Handle the exception
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
if (requestCode == 1 && resultCode == RESULT_OK) {
Bitmap image = (Bitmap) data.getExtras().get("data");
int dimension = Math.min(image.getWidth(), image.getHeight());
image = ThumbnailUtils.extractThumbnail(image, dimension, dimension);
imageView.setImageBitmap(image);
image = Bitmap.createScaledBitmap(image, imageSize, imageSize, false);
System.out.println(image);
classifyImage(image);
}
super.onActivityResult(requestCode, resultCode, data);
}
}
This is the video tutorial I followed: https://www.youtube.com/watch?v=jhGm4KDafKU
I found a tutorial to be able to crop an image from your gallery and display it in the image view, however I wasn't able to link this with my image classification. This is the part of the code I edited to try and link these together:
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 100 && resultCode == 101){
String result = data.getStringExtra("CROP");
Uri uri = data.getData();
if (result!=null){
uri = Uri.parse(result);
}
binding.imageView.setImageURI(uri);
// I added this:
try {
Bitmap image = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
int dimension = Math.min(image.getWidth(), image.getHeight());
image = ThumbnailUtils.extractThumbnail(image, dimension, dimension);
image = Bitmap.createScaledBitmap(image, imageSize, imageSize, false);
classifyImage(image);
} catch (IOException e) {
e.printStackTrace();
}
}
}
However, it always results in the activity crashing, these are the errors:
I/BitmapCropTask: Should crop: true
I/tflite: Initialized TensorFlow Lite runtime.
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.phoenixapp, PID: 21124
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=100, result=101, data=Intent { (has extras) }} to activity {com.example.phoenixapp/com.example.phoenixapp.Tensor}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at android.app.ActivityThread.deliverResults(ActivityThread.java:5301)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:5340)
at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:54)
at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7839)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at com.example.phoenixapp.Tensor.classifyImage(Tensor.java:113)
at com.example.phoenixapp.Tensor.onActivityResult(Tensor.java:184)
at android.app.Activity.dispatchActivityResult(Activity.java:8382)
at android.app.ActivityThread.deliverResults(ActivityThread.java:5294)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:5340)
at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:54)
at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7839)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
I/Process: Sending signal. PID: 21124 SIG: 9
Is there a simple solution to be able to perform image classification, whilst being able to crop the image beforehand?
Recently I have been working on android studio, I built a python image classification model and want to integrate it with an app. But when I click on predict button, the app crashes. Would be helpful if I can get the idea as to where things are going wrong.
Attached is the code and the error it throws -
Activitymain.java :-
package com.example.uni;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.example.uni.ml.ConvertedModel;
import org.tensorflow.lite.DataType;
import org.tensorflow.lite.support.image.TensorImage;
import org.tensorflow.lite.support.tensorbuffer.TensorBuffer;
import java.io.IOException;
import java.nio.ByteBuffer;
public class MainActivity extends AppCompatActivity {
private ImageView imgView;
private Button predict;
private Button select;
private TextView tv;
private Bitmap img;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imgView = (ImageView) findViewById(R.id.imageView);
tv = (TextView) findViewById(R.id.textView);
select = (Button) findViewById(R.id.button);
predict = (Button) findViewById(R.id.button2);
select.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent,12);
}
});
predict.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
img = Bitmap.createScaledBitmap(img,
500,
500,
true);
try {
ConvertedModel model = ConvertedModel.newInstance(getApplicationContext());
// Creates inputs for reference.
TensorBuffer inputFeature0 = TensorBuffer.createFixedSize(new int[]{1, 500, 500, 3}, DataType.FLOAT32);
TensorImage tensorImage = new TensorImage(DataType.FLOAT32);
tensorImage.load(img);
ByteBuffer byteBuffer = tensorImage.getBuffer();
inputFeature0.loadBuffer(byteBuffer);
// Runs model inference and gets result.
ConvertedModel.Outputs outputs = model.process(inputFeature0);
TensorBuffer outputFeature0 = outputs.getOutputFeature0AsTensorBuffer();
// Releases model resources if no longer used.
model.close();
tv.setText((int) outputFeature0.getFloatArray()[0]);
} catch (IOException e) {
/* TODO Handle the exception */
}
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 100)
{
imgView.setImageURI(data.getData());
Uri uri = data.getData();
try {
img = MediaStore.Images.Media.getBitmap(this.getContentResolver(),uri);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
In logcat I see this -
2021-11-05 13:23:38.040 24027-24027/com.example.uni I/tflite: Initialized TensorFlow Lite runtime.
2021-11-05 13:23:38.090 24027-24027/com.example.uni E/libc: Access denied finding property "ro.hardware.chipname"
2021-11-05 13:23:38.081 24027-24027/com.example.uni W/com.example.uni: type=1400 audit(0.0:232245): avc: denied { read } for name="u:object_r:vendor_default_prop:s0" dev="tmpfs" ino=14249 scontext=u:r:untrusted_app:s0:c48,c257,c512,c768 tcontext=u:object_r:vendor_default_prop:s0 tclass=file permissive=0
2021-11-05 13:23:38.841 24027-24027/com.example.uni E/com.example.un: Invalid ID 0x00000000.
2021-11-05 13:23:38.842 24027-24027/com.example.uni D/AndroidRuntime: Shutting down VM
2021-11-05 13:23:38.843 24027-24027/com.example.uni E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.uni, PID: 24027
android.content.res.Resources$NotFoundException: String resource ID #0x0
at android.content.res.Resources.getText(Resources.java:381)
at android.content.res.MiuiResources.getText(MiuiResources.java:97)
at android.widget.TextView.setText(TextView.java:6397)
at com.example.uni.MainActivity$2.onClick(MainActivity.java:85)
at android.view.View.performClick(View.java:7189)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119)
at android.view.View.performClickInternal(View.java:7166)
at android.view.View.access$3500(View.java:819)
at android.view.View$PerformClick.run(View.java:27682)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7592)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
2021-11-05 13:23:38.887 24027-24027/com.example.uni I/Process: Sending signal. PID: 24027 SIG: 9
Need suggestions as to what's going on and how to resolve it. I'm using android studio arctic fox 2020.3.1 patch 3.
The logcat already told you that it crashed at the setText() call. You called
tv.setText((int) outputFeature0.getFloatArray()[0]);
The int in setText(int) refers to a Resource ID defined in the string.xml (R.string.xxx).
If you are not getting the string from res, you should use setText(CharSequence) instead.
You probably want
tv.setText(String.format("%f",outputFeature0.getFloatArray()[0]));
(change "%f" to any decimal points or format you want)
I have created an app that basically takes a picture and saves it to the gallery. The only problem is that after the picture is taken it takes you to the screen where you can preview it with the two buttons that say okay and cancel. Once you click okay, the app quits. The image is still saved to the gallery but I want the app to stay open. I also want the app to display a bitmap of the image on an imageView that I have.
Here is my MainActivity.java
package com.example.app;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainActivity extends AppCompatActivity { <- Line 22
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = findViewById(R.id.button);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dispatchTakePictureIntent(); <- Line 34
}
});
}
static final int REQUEST_IMAGE_CAPTURE = 1;
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
// I AM UNSURE WHAT CODE TO PUT HERE. DOES ANYONE KNOW WHAT I SHOULD BE PUTTING HERE?
}
// Continue only if the File was successfully created
if (photoFile != null) {
//This is where the error is occurring but I do not know why.
Line 56 -> Uri photoURI = FileProvider.getUriForFile(this, "com.example.app", photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
ImageView imageView = findViewById(R.id.imageView);
imageView.setImageBitmap(imageBitmap);
}
}
String currentPhotoPath;
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = image.getAbsolutePath();
return image;
}
private void galleryAddPic() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(currentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
}
}
Here is my error message
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.app, PID: 22357
java.lang.IllegalArgumentException: Couldn't find meta-data for provider with authority com.example.app
at androidx.core.content.FileProvider.parsePathStrategy(FileProvider.java:606)
at androidx.core.content.FileProvider.getPathStrategy(FileProvider.java:579)
at androidx.core.content.FileProvider.getUriForFile(FileProvider.java:417)
--> at com.example.app.MainActivity.dispatchTakePictureIntent(MainActivity.java:56)
--> at com.example.app.MainActivity.access$000(MainActivity.java:22)
--> at com.example.app.MainActivity$1.onClick(MainActivity.java:34)
at android.view.View.performClick(View.java:7870)
at android.widget.TextView.performClick(TextView.java:14966)
at android.view.View.performClickInternal(View.java:7839)
at android.view.View.access$3600(View.java:886)
at android.view.View$PerformClick.run(View.java:29315)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:7777)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1047)
I/Process: Sending signal. PID: 22357 SIG: 9
There is a strange behaviour of assigning/modifying instance variable of the class inside Button OnClick() handlers.
As shown below, the instance variable "CurrentFile" is modified inside imgBtn.setOnClickListener() handlers. But when this variable is accessed in onActivityResult() method, this variable contains the value "null".
According to my understanding, the activity "GetPicActivity" will not be destroyed till the Camera activity returns. So, the instance variable "CurrentFile" should not be null.
Please help, if I am missing some basics.
import java.io.File;
import java.io.IOException;
import com.favoritepics.R;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.Toast;
public class GetPicActivity extends Activity {
protected static final int ID_REQ_IMAGE_CAPTURE = 1;
protected static final int ID_REQ_PICK_PHOTO = 0;
protected File currentFile = null; /// Goal is "to modify this variable inside Button onClick handlers"
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setBackgroundDrawable(
new ColorDrawable(android.graphics.Color.DKGRAY));
setContentView(R.layout.activity_get_pic);
// set handler image gallery
ImageButton imgBtn = (ImageButton) findViewById(R.id.imgGallery);
imgBtn.setOnClickListener(new ImageButton.OnClickListener() {
#Override
public void onClick(View v) {
// create intent to take picture on camera
Intent pickPhoto = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(pickPhoto, ID_REQ_PICK_PHOTO);
}
});
// set handler for camera image
imgBtn = (ImageButton) findViewById(R.id.imgCamera);
imgBtn.setOnClickListener(new ImageButton.OnClickListener() {
#Override
public void onClick(View v) {
Intent takePicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File tempDir = Environment.getExternalStorageDirectory();
File tempFile = null;
try {
currentFile = File
.createTempFile("_jpeg_", ".jpg", tempDir);
} catch (IOException exception) {
Toast.makeText(
GetPicActivity.this,
"Problem occured during creation of temp file! "
+ exception.getMessage(),
Toast.LENGTH_SHORT).show();
}
if (currentFile != null) {
takePicture.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(currentFile));
startActivityForResult(takePicture, ID_REQ_IMAGE_CAPTURE);
}
}
});
// set handler for cancel button
Button btnCancel = (Button) findViewById(R.id.btnCancel);
btnCancel.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case ID_REQ_IMAGE_CAPTURE:
if (resultCode == RESULT_OK) {
Intent newIntent = new Intent();
newIntent.putExtra("TYPE", requestCode);
newIntent.putExtra("PATH", currentFile.getAbsolutePath());
setResult(RESULT_OK, newIntent);
finish();
}
break;
default:
break;
}
}
}
click here to see Logcat messages
Steps what I intend to do:
1, Create a temporary file in External storage for the destination of Camera picture
2, Start Camera to take a picture by passing the URI of temporary file
3, OnActivityResult() from camera, return the (temporary) File path to previous activity for further process
But here what I see is,
As soon as the Camera is started & picture is taken, the GetPicActivity is created again. Because of this, the instance variable "CurrentFile" will be null & in OnActivityResult() , I could not get the File path of temporary file.
Why is the GetPicActivity destroyed after starting Camera?
When the camera is started, the Camera appears in the screen orientation "Landscape".
Even the orientation of already existing activity stack is changed to "Landscape" itseems.
So, When the result of Camera is returned to GetPicActivity method OnActivityResult(), the GetPicActivity is created again. But now, the instance variable "CurrentFile" is null. This, gives a NullPointerException.
The goal is to convert a Bitmap to a byte [], pass it between activities in a Bundle of data, then reconvert it back to a Bitmap at a later stage for display in an Imageview.
The issue is that whenever I try this, I just get a null bitmap and the non-descriptive, unhelpful log output:
12-07 17:01:33.282: D/skia(2971): --- SkImageDecoder::Factory returned null
I have looked at the following solutions:
Solution supplies the bitmap to byte[] code used
Highlighted that copyPixelsToBuffer() is essential over .compress
(Especially seeing as it is not necessary in this case).
I have run up the following test case which definitely narrows down the problem to the converting and restoring code. Based on my debugging, there is correct decoding, the byte array is the correct size and full, Bitmap configs are forced to be the same, decodeByteArray is just failing:
package com.example.debug;
import java.nio.ByteBuffer;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.view.Menu;
import android.widget.ImageView;
import android.widget.RelativeLayout;
public class MainActivity extends Activity {
RelativeLayout rl = null;
RelativeLayout.LayoutParams rlp = null;
ImageView ivBef = null;
ImageView ivAft = null;
Bitmap bmBef = null;
Bitmap bmAft = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// TEST
BitmapFactory.Options bmo = new BitmapFactory.Options();
bmo.inPreferredConfig = Config.ARGB_8888;
bmBef = BitmapFactory.decodeFile("/mnt/sdcard/Debug/001.png", bmo);
byte[] b = bitmapToByteArray(bmBef);
bmAft = BitmapFactory.decodeByteArray(b, 0, b.length, bmo);
LinearLayout ll = new LinearLayout(this);
ivBef = new ImageView(this);
ivBef.setImageBitmap(bmBef);
ivAft = new ImageView(this);
ivAft.setImageBitmap(bmAft);
ll.addView(ivBef);
ll.addView(ivAft);
setContentView(ll);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
public static byte[] bitmapToByteArray(Bitmap bm) {
// Create the buffer with the correct size
int iBytes = bm.getWidth() * bm.getHeight() * 4;
ByteBuffer buffer = ByteBuffer.allocate(iBytes);
// Log.e("DBG", buffer.remaining()+""); -- Returns a correct number based on dimensions
// Copy to buffer and then into byte array
bm.copyPixelsToBuffer(buffer);
// Log.e("DBG", buffer.remaining()+""); -- Returns 0
return buffer.array();
}
}
The before Imageview correctly displays the image, the after ImageView shows nothing (as you would expect with a null bitmap
You are passing Bitmap into Intent and get bitmap in next activity from bundle, but the problem is if your Bitmap/Image size is big at that time the image is not load in next activity.
Use below 2 Solutions to solve this issue.
1) First Convert Image into Byte Array and then pass into Intent and in next activity get byte array from Bundle and Convert into Image(Bitmap) and set into ImageView.
Convert Bitmap to Byte Array:-
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
Pass byte array into intent:-
Intent intent = new Intent(this, NextActivity.class);
intent.putExtra("picture", byteArray);
startActivity(intent);
Get Byte Array from Bundle and Convert into Bitmap Image:-
Bundle extras = getIntent().getExtras();
byte[] byteArray = extras.getByteArray("picture");
Bitmap bmp = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
ImageView image = (ImageView) findViewById(R.id.imageView1);
image.setImageBitmap(bmp);
2) First Save image into SDCard and in next activity set this image into ImageView.
The following method works perfectly with me, give it a try..
public byte[] convertBitmapToByteArray(Context context, Bitmap bitmap) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream(bitmap.getWidth() * bitmap.getHeight());
bitmap.compress(CompressFormat.PNG, 100, buffer);
return buffer.toByteArray();
}
try this:
bmBef = BitmapFactory.decodeFile("/mnt/sdcard/Debug/001.png", bmo);
ByteArrayOutputStream baos= new ByteArrayOutputStream();
bmBef .compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] byteArray = baos.toByteArray();