【问题标题】:Android: I need a circular camera preview. How to achieve it?Android:我需要一个圆形相机预览。如何实现?
【发布时间】:2014-06-01 22:25:52
【问题描述】:

我发现自己需要帮助。

我正在尝试开发这个简单的拍照应用(哇,现在是原创!)。一切顺利。我唯一需要的是有一个圆形相机预览。

我的 camerapreview 类(它扩展了 surfaceview)放置在框架布局中,这基本上是我的相机预览。众所周知,这是一个矩形。由于我对应用程序有更大的计划,我需要相机预览是圆形的(例如,有人可以拍摄某人的脸,我可以在周围画一些图画......)。

现在,我不知道该怎么做。我尝试了不同的方法,使用 xml 创建一个形状并将其设置为我的框架布局的背景,但这不起作用。

在谷歌上花了几个小时寻找解决方案后,我决定放弃并来到这里。

所以,如果有人知道任何事情,请告诉我们:) 我希望我已经足够清楚了,如果需要,请随时要求澄清。

【问题讨论】:

    标签: java android xml camera


    【解决方案1】:

    这很简单,如下所示: 这是用于 camerax 或 camera2 API

    注意:背景必须是透明的。

    你必须有如下的xml文件。

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

    也别忘了在style.xml中声明

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

    代码是这样写的

    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);
        }
    }
    

    【讨论】:

      【解决方案2】:

      简单的方法:

      1) 没有为 priview 设置表面

      2) 捕获原始数据

      3) 转换为位图并制作circle

      4) 显示(例如在 imegeview 上)

      仅供参考:

      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;   
      }
      }
      

      【讨论】:

        【解决方案3】:

        您可以在相机预览上覆盖ImageView。将SurfaceViewImageView 都放在FrameLayout 中,match_parent 和图像必须在顶部。 设置为中间有透明圆圈的黑色图像。

        【讨论】:

        • 确实有效,但是我还需要做更多的事情,我需要一些其他的解决方案。由于活动的背景颜色会根据用户做出的某些选择而改变,图像的矩形将保持白色,所以这对我的目的不起作用。也许我应该首先解释这一点,尽管如此,您的解决方案工作得很好。
        • 如果您需要更改颜色或形状,您可以编写自定义View 并实现onDraw 方法来绘制所需的形状。
        • 是的,我所做的是创建一个实现表面视图的绘图类,我试图覆盖 onDraw(Canvas c)。我只是在相机顶部绘制了一个文本,但是我得到了黑色背景,实际上我应该看到我的相机预览。在我的活动中: frame = //获取我的框架布局参考 draw = new Draw(this) //我在相机预览顶部绘制的绘图类 camerapreview = new Camerapreview(this,camera) //我的相机预览类框架。 addView(相机预览); frame.addView(绘制);通过这样做,我得到了黑色背景上的文本。
        • 好的,我设法修复它,我添加了 draw.setZOrderOnTop(true);和透明度,现在很好
        猜你喜欢
        • 2015-05-21
        • 1970-01-01
        • 2020-12-28
        • 1970-01-01
        • 2023-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多