• <code id="58gs9"></code>

      <mark id="58gs9"></mark>
      1. 您好£¬欢迎来到源码搜藏网£¡分享精神£¬快乐你我£¡
        [加入VIP] 设为首页 | 收藏本站 | 网站地图 | Sitemap | TAG标签
      2. 首 页
      3. 在线工具
      4. jquery手册
      5. 当前位置£º首页 > 安卓源码 > 技术博客 >

        如何使用Android设备上的相机预览来裁剪图像

        时间£º2019-02-28 22:51 来源£º互联网 作者£º源码搜藏 浏览£º收藏 挑错 推荐 打印

        介绍 基本思路非常简单£º 显示相机预览 添加矩形视图到相机预览£¨新裁剪图像的边界£© 裁剪图像并将结果保存到文件中 使用代码 开始吧£¡ 在Android studio中创建一个新项目£¨我使用的是3.2.1版£©£¬或者您可以下载源文件并选择£ºFile-New-Import项目¡£ 添加到

        介绍

        基本思路非常简单£º

        • 显示相机预览
        • 添加矩形视图到相机预览£¨新裁剪图像的边界£©
        • 裁剪图像并将结果保存到文件中

        使用代码

        开始吧£¡在Android studio中创建一个新项目£¨我使用的是3.2.1版£©£¬或者您可以下载源文件并选择£ºFile-New-Import项目¡£添加到build.gradle应用程序级别£º

        implementation 'com.jakewharton:butterknife:8.8.1'
        annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

        我使用Butterknife库£¬它非常有用¡£此外£¬我们需要相机和写入权限£¬因此将其添加到AndroidManifest.xml¡£

        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-feature android:name="android.hardware.camera" />
        <uses-permission android:name="android.permission.CAMERA" />

        我们需要2个片段£¬一个用于相机预览£¬另一个用于显示裁剪图像¡£创建新片段- ImageFragment£¨文件-新建片段的片段£¨空白£©-add TextViewImageview布局的XML文件£º

        <?xml version="1.0" encoding="utf-8"?>
        <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        
            xmlns:tools="http://schemas.android.com/tools"
        
            android:layout_width="match_parent"
        
            android:layout_height="match_parent"
        
            tools:context=".ImageFragment">
        
            <LinearLayout
        
                android:layout_width="wrap_content"
        
                android:layout_height="wrap_content"
        
                android:orientation="vertical">
        
                <TextView
        
                    android:id="@+id/res_photo_size"
        
                    android:layout_width="wrap_content"
        
                    android:layout_height="wrap_content" />
        
                <ImageView
        
                    android:id="@+id/res_photo"
        
                    android:layout_width="wrap_content"
        
                    android:layout_height="wrap_content"
        
                    android:src="@drawable/ic_launcher_background" />
        
            </LinearLayout>
        </FrameLayout>

        如何使用Android设备上的相机预览来裁剪图像

        将一些代码添加到ImageFragment类中£¬它只显示imagetextview信息£º

        public class ImageFragment extends Fragment {
        
            private Bitmap bitmap;
        
            @BindView(R.id.res_photo)
            ImageView resPhoto;
        
            @BindView(R.id.res_photo_size)
            TextView resPhotoSize;
        
            public void imageSetupFragment(Bitmap bitmap) {
                if (bitmap != null) {
                    this.bitmap = bitmap;
                }
            }
        
            @Override
            public void onCreate(@Nullable Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                this.setRetainInstance(true);
            }
        
            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                     Bundle savedInstanceState) {
        
                View view = inflater.inflate(R.layout.fragment_image, container, false);
                ButterKnife.bind(this, view);
                //check if bitmap exist, set to ImageView
                if (bitmap != null) {
                    resPhoto.setImageBitmap(bitmap);
                    String info = "image with:" + bitmap.getWidth() + "\n" + 
                                  "image height:" + bitmap.getHeight();
                    resPhotoSize.setText(info);
                }
                return view;
            }
        }

        创建第二个片段 - PhotoFragment£¨File-New- FragmentFragment£¨空白£© - 向layout-xml文件添加一些组件¡£主要是SurfaceView£¨用于摄像机预览£©和View£¨用于裁剪的边框£©¡£

        <?xml version="1.0" encoding="utf-8"?>
        <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        
            android:id="@+id/frame_surface_main"
        
            android:layout_width="match_parent"
        
            android:layout_height="match_parent">
        
            <LinearLayout
        
                android:id="@+id/preview_layout"
        
                android:layout_width="match_parent"
        
                android:layout_height="match_parent"
        
                android:orientation="vertical">
        
                <RelativeLayout
        
                    android:layout_width="match_parent"
        
                    android:layout_height="match_parent">
        
                    <SurfaceView
        
                        android:id="@+id/camera_preview_surface"
        
                        android:layout_width="match_parent"
        
                        android:layout_height="match_parent"
        
                        android:layout_centerInParent="true" />
        
                    <View
        
                        android:id="@+id/border_camera"
        
                        android:layout_width="match_parent"
        
                        android:layout_height="100dp"
        
                        android:layout_centerInParent="true"
        
                        android:layout_marginStart="50dp"
        
                        android:layout_marginEnd="50dp"
        
                        android:background="@drawable/border" />
                    <!---Customize your views and button-->
                    <TextView
        
                        android:id="@+id/res_border_size"
        
                        android:layout_width="wrap_content"
        
                        android:layout_height="wrap_content"
        
                        android:layout_alignParentStart="true"
        
                        android:layout_alignParentBottom="true"
        
                        android:text="size"
        
                        android:textColor="@color/colorAccent" />
        
                    <Button
        
                        android:id="@+id/make_photo_button"
        
                        android:layout_width="wrap_content"
        
                        android:layout_height="wrap_content"
        
                        android:layout_alignParentEnd="true"
        
                        android:layout_alignParentBottom="true"
        
                        android:background="@drawable/photo_button"
        
                        android:text="photo" />
                </RelativeLayout>
            </LinearLayout>
        </FrameLayout>

        如何使用Android设备上的相机预览来裁剪图像

        我使用了一个自定义按钮£¨绿色按钮£©£¬这是简单的代码£¬但很棒的视图£¡为此£¬您需要在Res-drawable中创建一个新的XML文件£¬如photo_button.xml£¬根据需要设置形状£¬颜色或使用一些Web资源£¬如下所示£ºhttp£º//angrytools.com/android/button /¡£

        <?xml version="1.0" encoding="utf-8"?>
        <shape xmlns:android="http://schemas.android.com/apk/res/android"
        
            android:shape="rectangle">
            <corners
        
                android:bottomLeftRadius="0dp"
        
                android:bottomRightRadius="20dp"
        
                android:topLeftRadius="20dp"
        
                android:topRightRadius="0dp" />
            <gradient
        
                android:angle="45"
        
                android:centerColor="#47A891"
        
                android:centerX="35%"
        
                android:endColor="#000000"
        
                android:startColor="#E8E8E8"
        
                android:type="linear" />
            <size
        
                android:width="100dp"
        
                android:height="60dp" />
            <stroke
        
                android:width="3dp"
        
                android:color="#16875A" />
        </shape>

        然后将背景按钮设置为£º

        android:background="@drawable/photo_button"

        如何使用Android设备上的相机预览来裁剪图像

        此外£¬我们需要裁剪边框 - 它将是一个简单的矩形£¬为此£¬您需要在Res-drawable中创建一个新的XML文件£¬如border.xml£º

        <?xml version="1.0" encoding="utf-8"?>
        <shape xmlns:android="http://schemas.android.com/apk/res/android">
            <stroke android:width="2dp" android:color="#C4CDD5"  />
            <corners android:radius="10dp" />
            <padding android:left="2dp" android:top="2dp" 
        
            android:right="2dp" android:bottom="2dp" />
        </shape>

        并设置view-background为£º

        android:background="@drawable/border" />

        下一步£¬PhotoFragment上课¡£我们不能使用标准意图来制作照片£¬我们需要自定义函数£¬所以我们可以使用Camera类 - 它已被弃用£¬但仍然很好用£¬所以让我们使用它¡£Camera级用来设置图像捕获设置£¬启动/停止预览£¬抓拍图片£¬并检索编码的视频帧¡£此类是Camera服务的客户端£¬它管理?#23548;?#30340;相机硬件¡£

        要控制预览£¬我们需要使用SurfaceHolder.Callback¡£abstract interface是为了保持显示表面¡£允许您控制曲面大小和格式£¬编辑曲面中的像素以及监视曲面的更改¡£

        public class PhotoFragment extends Fragment implements SurfaceHolder.Callback
        {}

        并实现一些方法£º

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
        
        }
        
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        
        }
        
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
        
        }

        像这样£º

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            camera = Camera.open();
        }
        
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            if (previewing) {
                camera.stopPreview();
                previewing = false;
            }
        
            if (camera != null) {
                try {
                    Camera.Parameters parameters = camera.getParameters();
                    //get preview sizes
                    List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
        
                    //find optimal - it very important
                    previewSizeOptimal = getOptimalPreviewSize(previewSizes, parameters.getPictureSize().width,
                            parameters.getPictureSize().height);
        
                    //set parameters
                    if (previewSizeOptimal != null) {
                        parameters.setPreviewSize(previewSizeOptimal.width, previewSizeOptimal.height);
                    }
        
                    if (camera.getParameters().getFocusMode().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
                        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
                    }
                    if (camera.getParameters().getFlashMode().contains(Camera.Parameters.FLASH_MODE_AUTO)) {
                        parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
                    }
        
                    camera.setParameters(parameters);
        
                    //rotate screen, because camera sensor usually in landscape mode
                    Display display = ((WindowManager) context.getSystemService
                                          (Context.WINDOW_SERVICE)).getDefaultDisplay();
                    if (display.getRotation() == Surface.ROTATION_0) {
                        camera.setDisplayOrientation(90);
                    } else if (display.getRotation() == Surface.ROTATION_270) {
                        camera.setDisplayOrientation(180);
                    }
        
                    //write some info
                    int x1 = previewLayout.getWidth();
                    int y1 = previewLayout.getHeight();
        
                    int x2 = borderCamera.getWidth();
                    int y2 = borderCamera.getHeight();
        
                    String info = "Preview width:" + String.valueOf(x1) + "\n" + 
                                         "Preview height:" + String.valueOf(y1) + "\n" +
                            "Border width:" + String.valueOf(x2) + 
                                         "\n" + "Border height:" + String.valueOf(y2);
                    resBorderSizeTV.setText(info);
        
                    camera.setPreviewDisplay(surfaceHolder);
                    camera.startPreview();
                    previewing = true;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            camera.stopPreview();
            camera.release();
            camera = null;
            previewing = false;
        }

        设置正确的相机预览尺寸非常重要£¬如果图像的纵横比不适合预览相机尺寸 - 裁剪的图像尺寸不正确¡£

        public Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
            final double ASPECT_TOLERANCE = 0.1;
            double targetRatio = (double) w / h;
            if (sizes == null) return null;
        
            Camera.Size optimalSize = null;
            double minDiff = Double.MAX_VALUE;
        
            int targetHeight = h;
        
            // Try to find an size match aspect ratio and size
            for (Camera.Size size : sizes) {
                double ratio = (double) size.width / size.height;
                if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        
            // Cannot find the one match the aspect ratio, ignore the requirement
            if (optimalSize == null) {
                minDiff = Double.MAX_VALUE;
                for (Camera.Size size : sizes) {
                    if (Math.abs(size.height - targetHeight) < minDiff) {
                        optimalSize = size;
                        minDiff = Math.abs(size.height - targetHeight);
                    }
                }
            }
            return optimalSize;
        }

        定义一些功能来拍照£º

        @OnClick(R.id.make_photo_button)
        void makePhoto() {
            if (camera != null) {
                camera.takePicture(myShutterCallback,
                        myPictureCallback_RAW, myPictureCallback_JPG);
            }
        }

        和一些回调£º

        Camera.ShutterCallback myShutterCallback = new Camera.ShutterCallback() {
            @Override
            public void onShutter() {
        
            }
        };
        
        //leave it empty
        Camera.PictureCallback myPictureCallback_RAW = new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
        
            }
        };
        
        //we need only JPG
        Camera.PictureCallback myPictureCallback_JPG = new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
                Bitmap bitmapPicture
                        = BitmapFactory.decodeByteArray(data, 0, data.length);
        
                Bitmap croppedBitmap = null;
        
                Display display = ((WindowManager) context.getSystemService
                                      (Context.WINDOW_SERVICE)).getDefaultDisplay();
                if (display.getRotation() == Surface.ROTATION_0) {
        
                    //rotate bitmap, because camera sensor usually in landscape mode
                    Matrix matrix = new Matrix();
                    matrix.postRotate(90);
                    Bitmap rotatedBitmap = Bitmap.createBitmap(bitmapPicture, 0, 0, 
                               bitmapPicture.getWidth(), bitmapPicture.getHeight(), matrix, true);
                    //save file
                    createImageFile(rotatedBitmap);
        
                    //calculate aspect ratio
                    float koefX = (float) rotatedBitmap.getWidth() / (float) previewLayout.getWidth();
                    float koefY = (float) rotatedBitmap.getHeight() / previewLayout.getHeight();
        
                    //get viewfinder border size and position on the screen
                    int x1 = borderCamera.getLeft();
                    int y1 = borderCamera.getTop();
        
                    int x2 = borderCamera.getWidth();
                    int y2 = borderCamera.getHeight();
        
                    //calculate position and size for cropping
                    int cropStartX = Math.round(x1 * koefX);
                    int cropStartY = Math.round(y1 * koefY);
        
                    int cropWidthX = Math.round(x2 * koefX);
                    int cropHeightY = Math.round(y2 * koefY);
        
                    //check limits and make crop
                    if (cropStartX + cropWidthX <= rotatedBitmap.getWidth() && 
                                 cropStartY + cropHeightY <= rotatedBitmap.getHeight()) {
                        croppedBitmap = Bitmap.createBitmap(rotatedBitmap, cropStartX, 
                                                            cropStartY, cropWidthX, cropHeightY);
                    } else {
                        croppedBitmap = null;
                    }
        
                    //save result
                    if (croppedBitmap != null) {
                        createImageFile(croppedBitmap);
                    }
        
                } else if (display.getRotation() == Surface.ROTATION_270) {
                    // for Landscape mode
                }
        
                //pass to another fragment
                if (mListener != null) {
                    if (croppedBitmap != null)
                        mListener.onFragmentInteraction(croppedBitmap);
                }
        
                if (camera != null) {
                    camera.startPreview();
                }
            }
        };

        裁剪裁剪图像很简单£º

        //calculate aspect ratio
        float koefX = (float) rotatedBitmap.getWidth() / (float) previewLayout.getWidth();
        float koefY = (float) rotatedBitmap.getHeight() / (float)previewLayout.getHeight();
        
        //get viewfinder border size and position on the screen
        int x1 = borderCamera.getLeft();
        int y1 = borderCamera.getTop();
        
        int x2 = borderCamera.getWidth();
        int y2 = borderCamera.getHeight();
        
        //calculate position and size for cropping
        int cropStartX = Math.round(x1 * koefX);
        int cropStartY = Math.round(y1 * koefY);
        
        int cropWidthX = Math.round(x2 * koefX);
        int cropHeightY = Math.round(y2 * koefY);
        
        //check limits and make crop
        if (cropStartX + cropWidthX <= rotatedBitmap.getWidth() && cropStartY + 
                                         cropHeightY <= rotatedBitmap.getHeight()) {
            croppedBitmap = Bitmap.createBitmap
                        (rotatedBitmap, cropStartX, cropStartY, cropWidthX, cropHeightY);
        } else {
            croppedBitmap = null;
        }

        另外£¬我们需要写位图来存档£º

        public void createImageFile(final Bitmap bitmap) {
        
            File path = Environment.getExternalStoragePublicDirectory(
                    Environment.DIRECTORY_PICTURES);
        
            String timeStamp = new SimpleDateFormat("MMdd_HHmmssSSS").format(new Date());
            String imageFileName = "region_" + timeStamp + ".jpg";
            final File file = new File(path, imageFileName);
        
            try {
                // Make sure the Pictures directory exists.
                if (path.mkdirs()) {
                    Toast.makeText(context, "Not exist :" + path.getName(), Toast.LENGTH_SHORT).show();
                }
        
                OutputStream os = new FileOutputStream(file);
        
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
        
                os.flush();
                os.close();
                Log.i("ExternalStorage", "Writed " + path + file.getName());
                // Tell the media scanner about the new file so that it is
                // immediately available to the user.
                MediaScannerConnection.scanFile(context,
                        new String[]{file.toString()}, null,
                        new MediaScannerConnection.OnScanCompletedListener() {
                            public void onScanCompleted(String path, Uri uri) {
                                Log.i("ExternalStorage", "Scanned " + path + ":");
                                Log.i("ExternalStorage", "-> uri=" + uri);
                            }
                        });
                Toast.makeText(context, file.getName(), Toast.LENGTH_SHORT).show();
        
            } catch (Exception e) {
                // Unable to create file, likely because external storage is
                // not currently mounted.
                Log.w("ExternalStorage", "Error writing " + file, e);
            }
        }

        设计MainActivity类£º

        <?xml version="1.0" encoding="utf-8"?>
        <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        
            xmlns:app="http://schemas.android.com/apk/res-auto"
        
            xmlns:tools="http://schemas.android.com/tools"
        
            android:layout_width="match_parent"
        
            android:layout_height="match_parent"
        
            tools:context=".MainActivity">
        
            <LinearLayout
        
                android:layout_width="match_parent"
        
                android:layout_height="match_parent"
        
                android:orientation="vertical">
        
                <LinearLayout
        
                    android:layout_width="match_parent"
        
                    android:layout_height="wrap_content"
        
                    android:orientation="vertical">
        
                    <Button
        
                        android:id="@+id/make_photo_button"
        
                        android:layout_gravity="center"
        
                        android:layout_width="wrap_content"
        
                        android:layout_height="wrap_content"
        
                        android:text="Photo!" />
                </LinearLayout>
        
                <LinearLayout
        
                    android:id="@+id/res_photo_layout"
        
                    android:layout_width="match_parent"
        
                    android:layout_height="wrap_content"
        
                    android:orientation="vertical">
        
                </LinearLayout>
            </LinearLayout>
        </FrameLayout>

        如何使用Android设备上的相机预览来裁剪图像

        并提出一些代码£º

        public class MainActivity extends AppCompatActivity 
               implements PhotoFragment.OnFragmentInteractionListener {
        
            int PERMISSION_ALL = 1;
            boolean flagPermissions = false;
        
            String[] PERMISSIONS = {
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    android.Manifest.permission.CAMERA
            };
        
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                ButterKnife.bind(this);
                checkPermissions();
            }
        
            @OnClick(R.id.make_photo_button)
            void onClickScanButton() {
                // check permissions
                if (!flagPermissions) {
                    checkPermissions();
                    return;
                }
                //start photo fragment
                getSupportFragmentManager()
                        .beginTransaction()
                        .replace(R.id.res_photo_layout, new PhotoFragment())
                        .addToBackStack(null)
                        .commit();
            }
        
            void checkPermissions() {
                if (!hasPermissions(this, PERMISSIONS)) {
                    requestPermissions(PERMISSIONS,
                            PERMISSION_ALL);
                    flagPermissions = false;
                }
                flagPermissions = true;
            }
        
            public static boolean hasPermissions(Context context, String... permissions) {
                if (context != null && permissions != null) {
                    for (String permission : permissions) {
                        if (ActivityCompat.checkSelfPermission(context, permission) 
                                != PackageManager.PERMISSION_GRANTED) {
                            return false;
                        }
                    }
                }
                return true;
            }
        
            @Override
            public void onFragmentInteraction(Bitmap bitmap) {
                if (bitmap != null) {
                    ImageFragment imageFragment = new ImageFragment();
                    imageFragment.imageSetupFragment(bitmap);
        
                    getSupportFragmentManager()
                            .beginTransaction()
                            .replace(R.id.res_photo_layout, imageFragment)
                            .addToBackStack(null)
                            .commit();
                }
            }
        }

        作物测试£º

        如何使用Android设备上的相机预览来裁剪图像

        如何使用Android设备上的相机预览来裁剪图像

        如何使用Android设备上的相机预览来裁剪图像转载

        快速集成MQTT协议到Android客户端,只需要简

        android自定义尺子收集demo

        错误运行app: This version of Android Stu

        android日历收集demo

        android图片上传功能实现

        安卓开发?#22987;Ç¡ª¡ªTabHost组件(一)£¨实现底

        ¡¾Android¡¿BugHD-简单实用的Bug收集工具-

        Android开发轻松自制flyme悬浮球

        解决关于SearchView的样式与控制问题 Andro

        最完整的Android开发工具集合整理

        Android开发greenDao数据库升级Hepler£¬保

        Android drawText 在指定位置进行画文字

        ´ó¸»ÎÌÆåÅÆÓéÀÖ¹ÙÍø

      6. <code id="58gs9"></code>

          <mark id="58gs9"></mark>

          1. <code id="58gs9"></code>

              <mark id="58gs9"></mark>