Search code examples
androidandroid-camerascreenshotaugmented-realitycapture

How to capture image by custom button from already opened front camera


Im working on a augmented reality app which displays 3d models on the users face.I made a class which extends ArFragment in which i set the front camera to be opened once a model is selected.I made a custom button for capturing the image,but i dont know how to implement the capture of the image itself with the 3d model displayed and store it in the phone(preferably without the custom made buttons being shown in the picture).Tried some code found on internet for programatical screenshoting but it screenshots only the buttons(the arrow and the circle).Here is how the activity looks like:

enter image description here Here is the class that extends ArFragment:

public class CustomArFragment extends ArFragment {
@Override
protected Config getSessionConfiguration(Session session) {
    Config config = new Config(session);
    config.setAugmentedFaceMode(Config.AugmentedFaceMode.MESH3D);

    this.getArSceneView().setupSession(session);

    return config;
}

@Override
protected Set<Session.Feature> getSessionFeatures() {
    return EnumSet.of(Session.Feature.FRONT_CAMERA);
}

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    FrameLayout frameLayout = (FrameLayout) super.onCreateView(inflater, container, savedInstanceState);

    getPlaneDiscoveryController().hide();
    getPlaneDiscoveryController().setInstructionView(null);


    return frameLayout;

}
}

Here is the activity in which i set the 3d model:

public class ArActivity extends AppCompatActivity {
int pos;
private int[] images = {R.raw.glasses1, R.raw.glasses3, R.raw.glasses4, R.raw.glasses5,
        R.raw.glasses6, R.raw.glasses7, R.raw.glasses8, R.raw.glasses9, R.raw.glasses10};

private ModelRenderable modelRenderable;
private boolean isAdded = false;

@Override
protected void onCreate(Bundle savedInstanceState) {

    Bundle extras = getIntent().getExtras();
    if (extras != null) {
        pos = extras.getInt("pos");

    }

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_ar);

    CustomArFragment customArFragment = (CustomArFragment) getSupportFragmentManager().findFragmentById(R.id.arFragment);

    ModelRenderable
            .builder().setSource(this, images[pos])
            .build()
            .thenAccept(renderable -> {
                modelRenderable = renderable;
                modelRenderable.setShadowCaster(false);
                modelRenderable.setShadowReceiver(false);
            });

    customArFragment.getArSceneView().setCameraStreamRenderPriority(Renderable.RENDER_PRIORITY_FIRST);
    customArFragment.getArSceneView().getScene().addOnUpdateListener(frameTime -> {

        if (modelRenderable == null)
            return;

        Frame frame = customArFragment.getArSceneView().getArFrame();
        Collection<AugmentedFace> augmentedFaces = frame.getUpdatedTrackables(AugmentedFace.class);

        for (AugmentedFace augmentedFace : augmentedFaces) {

            if (isAdded)
                return;

            AugmentedFaceNode augmentedFaceNode = new AugmentedFaceNode(augmentedFace);
            augmentedFaceNode.setParent(customArFragment.getArSceneView().getScene());
            augmentedFaceNode.setFaceRegionsRenderable(modelRenderable);

            isAdded = true;
        }
    });
}
}

Solution

  • I had a similar problem before.
    Capturing the Camera image with placed 3d models.

    i solved it with PixelCopy.
    I'm adding my code of that part below.
    I'm sorry that it's not going to be the straight-answer to your problem but i hope you get some ideas

    ImageButton btn3 = (ImageButton)findViewById(R.id.camera_btn);
        btn3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                takePhoto();
            }
        }); 
    
    private String generateFilename() {
    
        //현재시간을 기준으로 파일 이름 생성
        String date =
                new SimpleDateFormat("yyyyMMddHHmmss", java.util.Locale.getDefault()).format(new Date());
        return Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES) + File.separator + "IM/" + date + "_screenshot.jpg";
    }
    
    private void saveBitmapToDisk(Bitmap bitmap, String filename) throws IOException {
    
        //사용자의 갤러리에 IM 디렉토리 생성 및 Bitmap 을 JPEG 형식으로 갤러리에 저장
        File out = new File(filename);
        if (!out.getParentFile().exists()) {
            out.getParentFile().mkdirs();
        }
        try (FileOutputStream outputStream = new FileOutputStream(filename);
             ByteArrayOutputStream outputData = new ByteArrayOutputStream()) {
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputData);
            outputData.writeTo(outputStream);
            outputStream.flush();
            outputStream.close();
        } catch (IOException ex) {
            throw new IOException("Failed to save bitmap to disk", ex);
        }
    }
    
    private void takePhoto(){
        //PixelCopy 를 사용하여 카메라 화면과 object 를 bitmap 으로 생성
        final String filename = generateFilename();
        ArSceneView view = arFragment.getArSceneView();
    
        final Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),view.getHeight(),
                Bitmap.Config.ARGB_8888);
    
        final HandlerThread handlerThread = new HandlerThread("PixelCopier");
        handlerThread.start();
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            PixelCopy.request(view, bitmap, (copyResult) -> {
                if (copyResult == PixelCopy.SUCCESS) {
                    try {
                        saveBitmapToDisk(bitmap, filename);
    
                        //Media Scanning 실시
                        Uri uri = Uri.parse("file://" + filename);
                        Intent i = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                        i.setData(uri);
                        sendBroadcast(i);
    
                    } catch (IOException e) {
                        Toast toast = Toast.makeText(AR_Activity.this, e.toString(),
                                Toast.LENGTH_LONG);
                        toast.show();
                        return;
                    }
                    Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content),
                            "스크린샷이 저장되었습니다.", Snackbar.LENGTH_LONG);
                    snackbar.setAction("갤러리에서 보기", v -> {
                        //어플 내에서 저장한 스크린샷을 확인 가능
                        File photoFile = new File(filename);
    
                        Uri photoURI = FileProvider.getUriForFile(AR_Activity.this,
                                AR_Activity.this.getPackageName() + ".ar.codelab.name.provider",
                                photoFile);
                        Intent intent = new Intent(Intent.ACTION_VIEW, photoURI);
                        intent.setDataAndType(photoURI, "image/*");
                        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                        startActivity(intent);
                    });
                    snackbar.show();
                } else {
                    Toast toast = Toast.makeText(AR_Activity.this,
                            "스크린샷 저장 실패!: " + copyResult, Toast.LENGTH_LONG);
                    toast.show();
                }
                handlerThread.quitSafely();
            }, new Handler(handlerThread.getLooper()));
        }
    }