How Can I Capture Multiple Images and send the images to next Activity and display them using CameraX [Android Studio]

1.4k views Asked by At

Am using the latest cameraX

def camerax_version = "1.0.0-beta11"

I able to take picture and save image to External Storage in a folder using this below code

File photoFile = new File(outputDirectory, "Image_" + System.currentTimeMillis() + ".jpg");

            ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(photoFile).build();

            imageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(getBaseContext()), new ImageCapture.OnImageSavedCallback() {
                @Override
                public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
                    Uri.fromFile(photoFile);
                    Toast.makeText(getBaseContext(), "Image Saved" + photoFile.getAbsolutePath(), Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onError(@NonNull ImageCaptureException exception) {
                    Toast.makeText(getBaseContext(), "Error Saving Image" + photoFile.getAbsolutePath(), Toast.LENGTH_SHORT).show();
                }
            });

Now the point is on how to extract the image before saving it to external storage. What I want to achieve is to capture multiple images and save it in buffer and send those images to next Activity and display them in a imageView using list or something.

Now this can be achieved using onImageCapturedCallback on imageCapture which gives me a ImageProxy which then have to convert to Byte Array. But this process apples to only small size and single image. How can I achieve this for higher resolution and multiple images.

Below is the code I used to capture ImageProxy and set imageCapture to "YUV", Sadly it didn't work at all

    imageCapture.takePicture(ContextCompat.getMainExecutor(getBaseContext()), new ImageCapture.OnImageCapturedCallback() {
        @Override
        public void onCaptureSuccess(@NonNull ImageProxy image) {
            super.onCaptureSuccess(image);
            @SuppressLint("UnsafeExperimentalUsageError") Image cimage = image.getImage();
            Image.Plane[] planes = cimage.getPlanes();
            ByteBuffer yBuffer = planes[0].getBuffer();
            ByteBuffer uBuffer = planes[1].getBuffer();
            ByteBuffer vBuffer = planes[2].getBuffer();

            int ySize = yBuffer.remaining();
            int uSize = uBuffer.remaining();
            int vSize = vBuffer.remaining();

            byte[] nv21 = new byte[ySize + uSize + vSize];

            yBuffer.get(nv21,0,ySize);
            vBuffer.get(nv21,ySize,vSize);
            uBuffer.get(nv21,ySize + vSize,uSize);

            YuvImage yuvImage = new YuvImage(nv21,ImageFormat.NV21,cimage.getWidth(),cimage.getHeight(),null);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            yuvImage.compressToJpeg(new Rect(0,0,yuvImage.getWidth(),yuvImage.getHeight()),100,out);
            byte[] imageBytes = out.toByteArray();

            Intent intent = new Intent(MainActivity.this,MainActivity2.class);
            intent.putExtra("image",imageBytes);
            MainActivity.this.startActivity(intent);

        }

        @Override
        public void onError(@NonNull ImageCaptureException exception) {
            super.onError(exception);
        }
    });

Can I add Image to ArrayList and then sent them over?

Thanks in Advance..

4

There are 4 answers

0
Hiraeths On

The easiest way that I found was this

preview.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Bitmap scaledBitmap = null;

                ContextWrapper cw = new ContextWrapper(getApplicationContext());
                String PATH = Environment.getExternalStorageDirectory() + "/download/";
                File file = new  File(PATH + "myImage.jpeg");

                if (file.exists()) {
                    myImage.setImageDrawable(Drawable.createFromPath(file.toString()));
                }
                else {
                    myImage.setImageDrawable(Drawable.createFromPath(null));
                    Toast.makeText(nextPage.this, "Not found", Toast.LENGTH_LONG).show();
                }
            }
        });

You can change the path according to your code.

0
mmdreza baqalpour On

There are two ways that I did for my project. The code is in kotlin language. You can understand it easily.

val image = imageProxy.image
val bitmap = Bitmap.createBitmap(image.width, image.height, 
Bitmap.Config.ARGB_8888)

If it didn't work you can use a YuvtoRgbConvertor I have the full kotlin code if you want or you can write your own. then you can convert the bitmap like this.

val convertor = YuvToRgbConvertor
convertor.yuvToRgb(image , bitmap)

That is what I have done for my project.

0
Sam On

What I suggest you is to store in an array list. and then pass an array list to other activities.

What you have to do is create an array list and store uri.tostring in the array list

String newurl=uri.toString
`arraylist.add(newurl)`

This way you can add multiple image URLs in ArrayList and display with the help of the Picasso library. No need to fetch images from the database.

6
Charles Raj On

First you need to close the image after capturing inside the takepicture callback image.close() will close the current image . the create ArrayList globaly and add the imageURL in the arraylist . After theat you can send the arraylist to any activity by intent.

 imageCapture.takePicture(ContextCompat.getMainExecutor(getBaseContext()), new ImageCapture.OnImageCapturedCallback() {
    @Override
    public void onCaptureSuccess(@NonNull ImageProxy image) {
        super.onCaptureSuccess(image);
        @SuppressLint("UnsafeExperimentalUsageError") Image cimage = image.getImage();
        Image.Plane[] planes = cimage.getPlanes();
        ByteBuffer yBuffer = planes[0].getBuffer();
        ByteBuffer uBuffer = planes[1].getBuffer();
        ByteBuffer vBuffer = planes[2].getBuffer();

        int ySize = yBuffer.remaining();
        int uSize = uBuffer.remaining();
        int vSize = vBuffer.remaining();

        byte[] nv21 = new byte[ySize + uSize + vSize];

        yBuffer.get(nv21,0,ySize);
        vBuffer.get(nv21,ySize,vSize);
        uBuffer.get(nv21,ySize + vSize,uSize);

        YuvImage yuvImage = new YuvImage(nv21,ImageFormat.NV21,cimage.getWidth(),cimage.getHeight(),null);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        yuvImage.compressToJpeg(new Rect(0,0,yuvImage.getWidth(),yuvImage.getHeight()),100,out);
        byte[] imageBytes = out.toByteArray();

        Intent intent = new Intent(MainActivity.this,MainActivity2.class);
        intent.putExtra("image",imageBytes);
        MainActivity.this.startActivity(intent);
        image.close();
    }

    @Override
    public void onError(@NonNull ImageCaptureException exception) {
        super.onError(exception);
    }
});

I think this will help you, any doubts just refer here to my blog post

This is the function for converting the ImageProxy to bitmap

 // output of the image capture image proxy to bitmap
public Bitmap imageProxyToBitmap(ImageProxy image) {
    ByteBuffer buffer = image.getPlanes()[0].getBuffer();
    buffer.rewind();
    byte[] bytes = new byte[buffer.capacity()];
    buffer.get(bytes);
    byte[] clonedBytes = bytes.clone();
    return BitmapFactory.decodeByteArray(clonedBytes, 0, clonedBytes.length);
}

And save the bitmap to your local storage

    // used for save the files internal storage , can view in the gallery or internal storage
public String saveTOInternamMemory(Activity activity, Bitmap bitmapImage){

    File myPath = getInternalStorageDir(internalStorageDir,imageFormat,Environment.DIRECTORY_PICTURES);

    Log.d(TAG, "directory: " + myPath.getAbsolutePath());

    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream(myPath);
        // Use the compress method on the BitMap object to write image to the OutputStream
        bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
        Log.d(TAG, "bit exception: Success" );
    } catch (Exception e) {
        Log.d(TAG, "bit exception: " + e.getMessage());
        e.printStackTrace();
    } finally {
        try {
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
            Log.d(TAG, "io exce: " + e.getMessage());
        }
    }
    Log.d(TAG, "absolute path " + myPath.getAbsolutePath());
    return myPath.getAbsolutePath();
}