5

I find myself in need of assistance.

I'm trying to develop this simple app that takes pictures (Wow, now that's original!). Everything is fine. The only thing I need is to have a CIRCULAR CAMERA PREVIEW.

I have my camerapreview class (which extends surfaceview) placed inside a frame layout, which is my camera preview basically. As you all know, this comes in a rectangular shape. Since I have bigger plans for the app, I'd need the camera preview to be circular (so, for example, someone can take a picture of someone's face and I can have some drawings around...).

Now, I don't know how to proceed. I tried different things, creating a shape with xml and set it as background for my frame layout, but that just didn't work.

After hours spent on google for solutions I decided that I had to give up and come here.

So please, if someone knows anything, let us know :) I hope I was clear enough, do not hesitate to ask for clarification if needed.

Robert
  • 10,403
  • 14
  • 67
  • 117
user3494305
  • 61
  • 1
  • 6

3 Answers3

3

Simple way:

1) not setup surface for priview

2) catch raw data

3) convert to bitmap and make circle

4) show (for ex. on imegeview)

just for sample:

public class CameraRoundPriview extends ImageView {
 private Camera camera;
 private Bitmap bitmap = null;
 private int mPreviewWidth, mPreviewHeight; 
 boolean mCameraOn = false;  

 public CameraRoundPriview(Context context, AttributeSet attrs) {
        super(context, attrs); 
 }   

 private Bitmap getclip() { 
     //clip
     Bitmap output = Bitmap.createBitmap(bitmap.getHeight(),
                                         bitmap.getHeight(), 
                                         Config.ARGB_8888);  
     Canvas canvas = new Canvas(output);     
     final int color = 0xff424242;
     final Paint paint = new Paint();
     final Rect rect = new Rect(0, 0, bitmap.getHeight(),
                                     bitmap.getHeight()); 

     paint.setAntiAlias(true);
     canvas.drawARGB(0, 0, 0, 0);
     canvas.drawCircle(bitmap.getHeight() / 2,
                       bitmap.getHeight() / 2, 
                       bitmap.getHeight() / 2, paint);
     paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
     canvas.drawBitmap(bitmap, rect, rect, paint);

     //rotate
      android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
      android.hardware.Camera.getCameraInfo(getCameraID(), info);
      int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
      int degrees = 0;
      switch (rotation) {
          case Surface.ROTATION_0:
              degrees = 0;
              break;
          case Surface.ROTATION_90:
              degrees = 90;
              break;
          case Surface.ROTATION_180: 
              degrees = 180;
              break;
          case Surface.ROTATION_270:
              degrees = 270;
              break;
      }

     int result = degrees; 
     if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP){
          if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
              result = (info.orientation + degrees) % 360;
              result = (360 - result) % 360; // compensate the mirror
          } else { // back-facing
              result = (info.orientation - degrees + 360) % 360;
          }
     }
     Matrix matrix = new Matrix();
     matrix.postRotate(result);
     Bitmap scaledBitmap  = Bitmap.createScaledBitmap(output,output.getWidth(),output.getHeight(),true);
     Bitmap rotatedBitmap = Bitmap.createBitmap(scaledBitmap , 0, 0, scaledBitmap.getWidth(), scaledBitmap .getHeight(), matrix, true);

     return rotatedBitmap;
 }

private void showImage(){   
     if ((bitmap != null)){
         this.setImageBitmap(getclip());   
     }
 }

public boolean onClickCamera(){
    if (mCameraOn){
        mCameraOn = false;
        cameraStop();
    }else{
        mCameraOn = true;
        cameraStart();
    }
    return mCameraOn;
}

private void cameraStop(){
    if (camera == null) return;
    camera.setPreviewCallback(null);
    camera.release();
    camera = null; 
}

private int getCameraID(){
    // specify camera id
    return 0;
}

private void cameraStart(){
      Camera camera = Camera.open(getCameraID());
      final Camera.Size previewSize   = camera.getParameters().getPreviewSize();
      mPreviewWidth                   = previewSize.width; 
      mPreviewHeight                  = previewSize.height; 

      try {  
       camera.setPreviewCallback(new PreviewCallback() {
        public void onPreviewFrame(byte[] data, Camera camera_call) {
         ByteArrayOutputStream outstr = new ByteArrayOutputStream();
         Rect rect = new Rect(0, 0, mPreviewWidth, mPreviewHeight);  
         YuvImage yuvimage=new YuvImage(data,ImageFormat.NV21,mPreviewWidth,mPreviewHeight,null);
         yuvimage.compressToJpeg(rect, 50, outstr);
         bitmap = BitmapFactory.decodeByteArray(outstr.toByteArray(), 0, outstr.size());
         showImage();
         camera_call.addCallbackBuffer(data);
        } 
       }); 
      } catch (Exception e) {}
      camera.startPreview();

      this.camera=camera;   
}
}
Community
  • 1
  • 1
Siarhei
  • 2,358
  • 3
  • 27
  • 63
1

You can overlay an ImageView over the camera preview. put both the SurfaceView and the ImageView within a FrameLayout both match_parent and the image must be on top. Set to an black image with transparent circle in the middle.

Kirill Kulakov
  • 10,035
  • 9
  • 50
  • 67
  • that did work, however there's more i need to do and i need some other solution. as the background color of the activity will change according to some choice made by the user, the rectangle of the image will remain white, so that wouldn't work for my purpose. perhaps i should have explained this in the first place, nontheless, your solution worked just fine. – user3494305 Apr 18 '14 at 03:16
  • 1
    if you need to change the color or the shape you could write a custom `View` and implement the `onDraw` method to draw the desired shape. – Kirill Kulakov Apr 18 '14 at 06:01
  • yes, what i did is create a class Drawing which implements surfaceview and i tried to override onDraw(Canvas c). I'm simply drawing a text on top of the camera, however i get a black background, and i should actually see my camera preview instead. In my activity: frame = //get my frame layout reference draw = new Draw(this) //my drawing class that draw on top of the camera preview camerapreview = new Camerapreview(this,camera) // my camera preview class frame.addView(camerapreview); frame.addView(draw); By doing so i get the text on a black background. – user3494305 Apr 18 '14 at 06:46
  • ok i managed to fixe it, i added draw.setZOrderOnTop(true); and transparency and now it's good – user3494305 Apr 18 '14 at 06:59
0

this is as simple as shown below: this is for camerax or camera2 API

Note: you must have background transparent.

you must have xml file like below.

 <com.RoundedCameraPreview
            android:id="@+id/viewFinder"
            android:background="#00000000"
            app:scaleType="fillCenter"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

also don't forget to declare in style.xml

<declare-styleable name="PreviewView">
        <attr name="isRound" format="boolean" />
    </declare-styleable>

and code is written like this

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.view.PreviewView;

public class RoundedCameraPreview extends PreviewView {


    Path clipPath;
    boolean isRound;

    public RoundedCameraPreview(@NonNull Context context) {
        super(context);
    }

    public RoundedCameraPreview(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public RoundedCameraPreview(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.PreviewView,
                0, 0);

        try {
            isRound = a.getBoolean(R.styleable.PreviewView_isRound, true);
        } finally {
            a.recycle();
        }
    }

    public boolean isRound() {
        return isRound;
    }

    public void setIsRound(boolean isRound) {
        this.isRound = isRound;
        invalidate();
        requestLayout();
    }

    public RoundedCameraPreview(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        if (isRound) {
            clipPath = new Path();
            //TODO: define the circle you actually want
            clipPath.addCircle(canvas.getWidth() / 2, canvas.getWidth() / 2, canvas.getWidth() / 2, Path.Direction.CW);

            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

            canvas.clipPath(clipPath);
            canvas.drawPath(clipPath, paint);
        }
        super.dispatchDraw(canvas);
    }
}
Chirag Thummar
  • 665
  • 6
  • 16