拍照_拍照搜题 - CSDN
精华内容
参与话题
  • win7打开摄像头照相拍照软件

    热门讨论 2020-07-30 23:33:30
    win7打开摄像头照相拍照软件,漂亮的很,,
  • 工程地址: ... 可到群文件下载 1.拍照  拍照API https://docs.unity3d.com/Manual/windowsholographic-photocapture.html 可以在编辑器模式下拍照 PhotoCapture.CreateAsync(fals...

    工程地址:

    https://download.csdn.net/download/shanguuncle/10548611

    可到群文件下载

    1.拍照

     拍照API https://docs.unity3d.com/Manual/windowsholographic-photocapture.html

    可以在编辑器模式下拍照

    PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);

    第一个参数布尔值是否拍摄全息画面,如果只拍摄摄像头就false,拍摄全息就true

       
    
        public PhotoCapture photoCaptureObj = null;
        List<byte> imageBufferList = new List<byte>();
        CameraParameters cameraParameters;
    
     public void TakePhoto()
        {
            ShowImage.gameObject.SetActive(true);
    #if UNITY_EDITOR || UNITY_WSA
            PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
    #else
    
    #endif
        }
    
      void OnPhotoCaptureCreated(PhotoCapture captureObject)
        {
            photoCaptureObj = captureObject;
    
            Resolution  cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
            cameraParameters = new CameraParameters();
            cameraParameters.hologramOpacity = 0.0f;
            cameraParameters.cameraResolutionHeight = cameraResolution.height;
            cameraParameters.cameraResolutionWidth = cameraResolution.width;
            cameraParameters.pixelFormat = CapturePixelFormat.BGRA32;
    
            captureObject.StartPhotoModeAsync(cameraParameters, OnPhotoModeStarted);
        }
    
    
        private void OnPhotoModeStarted(PhotoCapture.PhotoCaptureResult result)
        {
            if (result.success)
            {
                photoCaptureObj.TakePhotoAsync(OnCaptturePhotoToMemory);
                Debug.Log("拍照成功");
            }
            else
            {
                //重新拍照
                // PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
                Debug.Log("重新拍照");
            }
        }
    
        void OnCaptturePhotoToMemory(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)
        {
            if (result.success)
            {
                //照片显示
                photoCaptureFrame.CopyRawImageDataIntoBuffer(imageBufferList);
                imageBufferList = FlipVertical(imageBufferList, cameraParameters.cameraResolutionWidth, cameraParameters.cameraResolutionHeight, 4);
                targetTexture = CreateTexture(imageBufferList, cameraParameters.cameraResolutionWidth, cameraParameters.cameraResolutionHeight);
                ShowImage.sprite = Sprite.Create(targetTexture, new Rect(0, 0, targetTexture.width, targetTexture.height), new Vector2(0.5f, 0.5f));
            }
            photoCaptureObj.StopPhotoModeAsync(OnStoppedPhotoMode);
        }
    
        void OnStoppedPhotoMode(PhotoCapture.PhotoCaptureResult result)
        {
            photoCaptureObj.Dispose();
            photoCaptureObj = null;
        }
    
    
        private Texture2D CreateTexture(List<byte> rawData, int width, int height)
        {
            Texture2D tex = new Texture2D(width, height, TextureFormat.BGRA32, false);
            tex.LoadRawTextureData(rawData.ToArray());
            tex.Apply();
            return tex;
        }
        /// <summary>
        /// 照片上下反转
        /// </summary>
        /// <param name="src"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="stride"></param>
        /// <returns></returns>
        private List<byte> FlipVertical(List<byte> src, int width, int height, int stride)
        {
            byte[] dst = new byte[src.Count];
            for (int y = 0; y < height; ++y)
            {
                for (int x = 0; x < width; ++x)
                {
                    int invY = (height - 1) - y;
                    int pxel = (y * width + x) * stride;
                    int invPxel = (invY * width + x) * stride;
                    for (int i = 0; i < stride; ++i)
                    {
                        dst[invPxel + i] = src[pxel + i];
                    }
                }
            }
            return new List<byte>(dst);
        }

    保存图片到本地

      public void SavePhoto()
        {
            //Texture2D tex = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, true);
            //tex.Apply();
            SavenPic(targetTexture,"test");
            VideoImage.gameObject.SetActive(false);
            ShowImage.gameObject.SetActive(false);
        }
        public void SavenPic(Texture2D tex, string filename)
        {
            try
            {
                string path = Application.persistentDataPath + "/" + filename + ".jpg";
                File.WriteAllBytes(path, tex.EncodeToJPG());
                ShowImage.sprite = null;
                print("保存成功!" + path);
    
            }
            catch (System.Exception e)
            {
                print("保存失败!" + e.Message);
    
            }
    
        }

     读取图片

      public void ShowPhoto() 
        {
            VideoImage.gameObject.SetActive(false);
            ShowImage.gameObject.SetActive(true);
            StartCoroutine(LoadPic("test"));
        }
    
        private IEnumerator LoadPic(string picname)
        {
            string path = Application.persistentDataPath + "/" + picname + ".jpg" ;
            if (File.Exists(path))
            {
                WWW www = new WWW("file:///" + path);
                yield return www;
    
                //获取Texture
                Texture2D dynaPic = www.texture;
                ShowImage.sprite = Sprite.Create(dynaPic, new Rect(0, 0, dynaPic.width, dynaPic.height), new Vector2(0.5f, 0.5f));
                print("读取成功");
            }
            else
            {
                print("图片不存在!");
            }
        }

    2.录像

    录像API https://docs.unity3d.com/Manual/windowsholographic-videocapture.html

    编辑器模式下不可用,只有在Hololens上能使用

       VideoCapture m_VideoCapture = null;
        bool isRecording;
        public void StopVideo()
        {
            if (isRecording)
            {
                isRecording = false;
                print("停止录像...");
                if(Application.platform==RuntimePlatform.WSAPlayerX86)
                m_VideoCapture.StopRecordingAsync(OnStoppedRecordingVideo);   
            }
        }
        public void TakeVideo()
        {
            VideoImage.gameObject.SetActive(false);
            ShowImage.gameObject.SetActive(false);
    
            if (!isRecording)
            {
               
                isRecording = true;
                print("开始录像...");
                if (Application.platform == RuntimePlatform.WSAPlayerX86)
                VideoCapture.CreateAsync(false, StartVideoCapture);
            }
        }
     void StartVideoCapture(VideoCapture videoCapture)
        {
    
            if (videoCapture != null)
            {
                m_VideoCapture = videoCapture;
                Debug.Log("Created VideoCapture Instance!");
    
                Resolution cameraResolution = VideoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
                float cameraFramerate = VideoCapture.GetSupportedFrameRatesForResolution(cameraResolution).OrderByDescending((fps) => fps).First();
                Debug.Log("刷新率:" + cameraFramerate);
    
                CameraParameters cameraParameters = new CameraParameters();
                cameraParameters.hologramOpacity = 0.0f;
                cameraParameters.frameRate = cameraFramerate;
                cameraParameters.cameraResolutionWidth = cameraResolution.width;
                cameraParameters.cameraResolutionHeight = cameraResolution.height;
                cameraParameters.pixelFormat = CapturePixelFormat.BGRA32;
    
                m_VideoCapture.StartVideoModeAsync(cameraParameters,
                    VideoCapture.AudioState.ApplicationAndMicAudio,
                    OnStartedVideoCaptureMode);
            }
            else
            {
                Debug.LogError("Failed to create VideoCapture Instance!");
            }
        }
    
        void OnStartedVideoCaptureMode(VideoCapture.VideoCaptureResult result)
        {
            Debug.Log("开始录像模式!");
            //string timeStamp = Time.time.ToString().Replace(".", "").Replace(":", "");
            //string filename = string.Format("TestVideo_{0}.mp4", timeStamp);
            string filename = "TestVideo.mp4";
            string filepath = Path.Combine(Application.persistentDataPath, filename);
            filepath = filepath.Replace("/", @"\");
            m_VideoCapture.StartRecordingAsync(filepath, OnStartedRecordingVideo);
            print("videopath:"+ filepath);
        }
    
        void OnStoppedVideoCaptureMode(VideoCapture.VideoCaptureResult result)
        {
            m_VideoCapture.Dispose();
            m_VideoCapture = null;
            Debug.Log("停止录像模式!");
        }
    
        void OnStartedRecordingVideo(VideoCapture.VideoCaptureResult result)
        {
            Debug.Log("开始录像!");
        }
    
        void OnStoppedRecordingVideo(VideoCapture.VideoCaptureResult result)
        {
            Debug.Log("停止录像!");
            m_VideoCapture.StopVideoModeAsync(OnStoppedVideoCaptureMode);
        }

    播放录制的视频

     public void PlayVideo()
        {
            if (File.Exists(Application.persistentDataPath + "/TestVideo.mp4"))
            {
                VideoImage.gameObject.SetActive(true);
                ShowImage.gameObject.SetActive(false);
    
                print("播放视频...");
                VideoImage.url = "file:///" + Application.persistentDataPath + "/TestVideo.mp4";
                VideoImage.Play();    
            }
            else
            {
                print("视频不存在!");
            }
        }

    3.打包勾选权限

    打包需勾选摄像头和麦克风权限

    Player settings->Capabilities

    Hololens运行截图

    展开全文
  • 目前支持谷歌、火狐浏览器
  • 更换头像或者上传图片功能已基本是每个 APP 所具备的基础功能了,但这对于开发者来说是一个很麻烦的事情,除机型之外,适配版本就至少要考虑这几种情况(6.0以下版本、6.0的动态权限、7.0的FileProvider、8.0的特殊...

    更换头像或者上传图片功能已基本是每个 APP 所具备的基础功能了,但这对于开发者来说是一个很麻烦的事情,除机型之外,适配版本就至少要考虑这几种情况(6.0以下版本、6.0的动态权限、7.0的FileProvider、8.0的特殊情况)。

    今天来个总结,方便自己也方便同行。


    功能说明

    本文的示例以下图为准:
    选择图片

    界面只有一个 ImageView,点击 ImageView 弹出 DialogFragment,分别是拍照和相册选择图片功能,其中都带有系统的裁剪功能,将裁剪后的图片显示在 ImageView 上。如果不需要裁剪功能,只需要将代码中的裁剪方法注释掉即可。

    6.0 以下版本

    1. 权限

    <uses-feature android:name="android.hardware.camera" />
        <!--相机权限-->
        <uses-permission android:name="android.permission.CAMERA" />
        <!--写入SD卡的权限:如果你希望保存相机拍照后的照片-->
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <!--读取SD卡的权限:打开相册选取图片所必须的权限-->
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    2. 拍照代码

    /**
         * 打开系统相机
         */
        private void openSysCamera() {
            Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(
                    new File(Environment.getExternalStorageDirectory(), imgName)));
            startActivityForResult(cameraIntent, CAMERA_RESULT_CODE);
        }

    其中 imgName 是拍照图片的名字,一般以时间戳再加上自定义字符串命名;CAMERA_RESULT_CODE 是自定义的一个常量,作为拍照的请求码。

    onActivityResult 处理拍照后的图片

    case CAMERA_RESULT_CODE:
                    tempFile = new File(Environment.getExternalStorageDirectory(), imgName);
                    cropPic(Uri.fromFile(tempFile));
                    break;

    将拍照后的图片创建成一个 File 对象,用来裁剪,裁剪的功能代码是和相册选取图片通用的。

    裁剪代码

    /**
         * 裁剪图片
         *
         * @param data
         */
        private void cropPic(Uri data) {
            if (data == null) {
                return;
            }
            Intent cropIntent = new Intent("com.android.camera.action.CROP");
            cropIntent.setDataAndType(data, "image/*");
    
            // 开启裁剪:打开的Intent所显示的View可裁剪
            cropIntent.putExtra("crop", "true");
            // 裁剪宽高比
            cropIntent.putExtra("aspectX", 1);
            cropIntent.putExtra("aspectY", 1);
            // 裁剪输出大小
            cropIntent.putExtra("outputX", 320);
            cropIntent.putExtra("outputY", 320);
            cropIntent.putExtra("scale", true);
            /**
             * return-data
             * 这个属性决定我们在 onActivityResult 中接收到的是什么数据,
             * 如果设置为true 那么data将会返回一个bitmap
             * 如果设置为false,则会将图片保存到本地并将对应的uri返回,当然这个uri得有我们自己设定。
             * 系统裁剪完成后将会将裁剪完成的图片保存在我们所这设定这个uri地址上。我们只需要在裁剪完成后直接调用该uri来设置图片,就可以了。
             */
            cropIntent.putExtra("return-data", true);
            // 当 return-data 为 false 的时候需要设置这句
    //        cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
            // 图片输出格式
    //        cropIntent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
            // 头像识别 会启动系统的拍照时人脸识别
    //        cropIntent.putExtra("noFaceDetection", true);
            startActivityForResult(cropIntent, CROP_RESULT_CODE);
        }

    其中的 CROP_RESULT_CODE 也是定义的静态常量,同拍照时定义的常量相同的作用。

    如果裁剪时将 return-data 设置为 false,那么需要定义一个 Uri 来保存裁剪后的图片路径。

     // 裁剪属性 cropIntent.putExtra("return-data", false); 时,使用自定义接收图片的Uri
        private static final String IMAGE_FILE_LOCATION = "file:///" + Environment.getExternalStorageDirectory().getPath() + "/temp.jpg";
        private Uri imageUri = Uri.parse(IMAGE_FILE_LOCATION);

    图片裁剪完成回调

     case CROP_RESULT_CODE:
                    // 裁剪时,这样设置 cropIntent.putExtra("return-data", true); 处理方案如下
                    if (data != null) {
                        Bundle bundle = data.getExtras();
                        if (bundle != null) {
                            Bitmap bitmap = bundle.getParcelable("data");
                            imageView.setImageBitmap(bitmap);
                            // 把裁剪后的图片保存至本地 返回路径
                            String urlpath = FileUtilcll.saveFile(this, "crop.jpg", bitmap);
                            L.e("裁剪图片地址->" + urlpath);
                        }
                    }
    
                    // 裁剪时,这样设置 cropIntent.putExtra("return-data", false); 处理方案如下
    //                try {
    //                    ivHead.setImageBitmap(BitmapFactory.decodeStream(
    // getActivity().getContentResolver().openInputStream(imageUri)));
    //                } catch (FileNotFoundException e) {
    //                    e.printStackTrace();
    //                }
                    break;

    FileUtilcll 代码

    /**
     * 图片文件操作
     */
    public class FileUtilcll {
    
        /**
         * 将Bitmap 图片保存到本地路径,并返回路径
         *
         * @param fileName 文件名称
         * @param bitmap   图片
         * @param资源类型,参照 MultimediaContentType 枚举,根据此类型,保存时可自动归类
         */
        public static String saveFile(Context c, String fileName, Bitmap bitmap) {
            return saveFile(c, "", fileName, bitmap);
        }
    
        public static String saveFile(Context c, String filePath, String fileName, Bitmap bitmap) {
            byte[] bytes = bitmapToBytes(bitmap);
            return saveFile(c, filePath, fileName, bytes);
        }
    
        /**
         * Bitmap 转 字节数组
         *
         * @param bm
         * @return
         */
        public static byte[] bitmapToBytes(Bitmap bm) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            bm.compress(CompressFormat.JPEG, 100, baos);
            return baos.toByteArray();
        }
    
        public static String saveFile(Context c, String filePath, String fileName, byte[] bytes) {
            String fileFullName = "";
            FileOutputStream fos = null;
            String dateFolder = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA)
                    .format(new Date());
            try {
                String suffix = "";
                if (filePath == null || filePath.trim().length() == 0) {
                    filePath = Environment.getExternalStorageDirectory() + "/cxs/" + dateFolder + "/";
                }
                File file = new File(filePath);
                if (!file.exists()) {
                    file.mkdirs();
                }
                File fullFile = new File(filePath, fileName + suffix);
                fileFullName = fullFile.getPath();
                fos = new FileOutputStream(new File(filePath, fileName + suffix));
                fos.write(bytes);
            } catch (Exception e) {
                fileFullName = "";
            } finally {
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        fileFullName = "";
                    }
                }
            }
            return fileFullName;
        }
    
    }

    到此,拍照功能就完成了,附带了裁剪。剩下的就是相册选取照片,这个也不难,固定代码,其他功能和拍照时相同的。

     /**
         * 打开系统相册
         */
        private void openSysAlbum() {
            Intent albumIntent = new Intent(Intent.ACTION_PICK);
            albumIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
            startActivityForResult(albumIntent, ALBUM_RESULT_CODE);
        }

    其中的 ALBUM_RESULT_CODE 同样是定义的常量。用来在 onActivityResult 中处理返回结果。

    case ALBUM_RESULT_CODE:
                    // 相册
                    cropPic(data.getData());
                    break;

    和拍照公用裁剪代码,这里直接调用即可,其他逻辑不变。


    6.0动态权限适配

    除了上述功能保持不变之外,需要在代码中动态申请文件读写权限和相机权限。这里我将申请的时机写在了刚进入页面,而不是刚打开 APP,也不是点击按钮的时候。

    逻辑

    • 如果用户点击了拒绝,但没有点击“不再询问”,这个时候再次进入界面继续弹框;
    • 如果用户点击了拒绝,且选择了“不再询问”,那么再次进入此界面将会弹框提示打开 APP 的详情界面,手动开启对应权限。

    权限申请代码

    /**
         * 初始化相机相关权限
         * 适配6.0+手机的运行时权限
         */
        private void initPermission() {
            String[] permissions = new String[]{Manifest.permission.CAMERA,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.READ_EXTERNAL_STORAGE};
            //检查权限
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
                    != PackageManager.PERMISSION_GRANTED) {
                // 之前拒绝了权限,但没有点击 不再询问 这个时候让它继续请求权限
                if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                        Manifest.permission.CAMERA)) {
                    Toast.makeText(this, "用户曾拒绝打开相机权限", Toast.LENGTH_SHORT).show();
                    ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSIONS);
                } else {
                    //注册相机权限
                    ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSIONS);
                }
            }
        }

    这里我将需要的权限统一写在了一个数组里面。其中的 REQUEST_PERMISSIONS 和上面拍照定义的常量功能相同。

    权限申请回调

    @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                               @NonNull int[] grantResults) {
            switch (requestCode) {
                case REQUEST_PERMISSIONS:
                    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        //成功
                        Toast.makeText(this, "用户授权相机权限", Toast.LENGTH_SHORT).show();
                    } else {
                        // 勾选了不再询问
                        Toast.makeText(this, "用户拒绝相机权限", Toast.LENGTH_SHORT).show();
                        /**
                         * 跳转到 APP 详情的权限设置页
                         *
                         * 可根据自己的需求定制对话框,点击某个按钮在执行下面的代码
                         */
                        Intent intent = Util.getAppDetailSettingIntent(PhotoFromSysActivity.this);
                        startActivity(intent);
                    }
                    break;
            }
        }

    其中的 getAppDetailSettingIntent()方法代码如下:

    /**
         * 获取 APP 详情页面intent
         *
         * @return
         */
        public static Intent getAppDetailSettingIntent(Context context) {
            Intent localIntent = new Intent();
            localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            if (Build.VERSION.SDK_INT >= 9) {
                localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
                localIntent.setData(Uri.fromParts("package", context.getPackageName(), null));
            } else if (Build.VERSION.SDK_INT <= 8) {
                localIntent.setAction(Intent.ACTION_VIEW);
                localIntent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails");
                localIntent.putExtra("com.android.settings.ApplicationPkgName", context.getPackageName());
            }
            return localIntent;
        }

    到这,权限这个适配问题就解决了,接下来该是 Android 7.0 的适配了,这里我们只需要修改拍照的功能即可,相册是没有问题的。


    Android7.0 适配

    Android 7.0 就是 File 路径的变更,需要使用 FileProvider 来做,下面看拍照的代码。

    拍照代码修改

    /**
         * 打开系统相机
         */
        private void openSysCamera() {
            Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    //        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(
    //                new File(Environment.getExternalStorageDirectory(), imgName)));
    //        File file = new File(Environment.getExternalStorageDirectory(), imgName);
            try {
                file = createOriImageFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            if (file != null) {
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
                    imgUriOri = Uri.fromFile(file);
                } else {
                    imgUriOri = FileProvider.getUriForFile(this, getPackageName() + ".provider", file);
                }
                cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imgUriOri);
                startActivityForResult(cameraIntent, CAMERA_RESULT_CODE);
            }
        }

    File 对象的创建和 拍照图片的 Uri 对象创建方式更改。创建原图像保存的代码如下:

    /**
         * 创建原图像保存的文件
         *
         * @return
         * @throws IOException
         */
        private File createOriImageFile() throws IOException {
            String imgNameOri = "HomePic_" + new SimpleDateFormat(
                    "yyyyMMdd_HHmmss").format(new Date());
            File pictureDirOri = new File(getExternalFilesDir(
                    Environment.DIRECTORY_PICTURES).getAbsolutePath() + "/OriPicture");
            if (!pictureDirOri.exists()) {
                pictureDirOri.mkdirs();
            }
            File image = File.createTempFile(
                    imgNameOri,         /* prefix */
                    ".jpg",             /* suffix */
                    pictureDirOri       /* directory */
            );
            imgPathOri = image.getAbsolutePath();
            return image;
        }

    拍照回调代码修改

     case CAMERA_RESULT_CODE:
    //                tempFile = new File(Environment.getExternalStorageDirectory(), imgName);
    //                cropPic(Uri.fromFile(tempFile));
    
                    // 适配 Android7.0+
                    cropPic(getImageContentUri(file));
                    break;

    getImageContentUri() 代码如下:

    /**
         * 7.0以上获取裁剪 Uri
         *
         * @param imageFile
         * @return
         */
        private Uri getImageContentUri(File imageFile) {
            String filePath = imageFile.getAbsolutePath();
            Cursor cursor = getContentResolver().query(
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    new String[]{MediaStore.Images.Media._ID},
                    MediaStore.Images.Media.DATA + "=? ",
                    new String[]{filePath}, null);
    
            if (cursor != null && cursor.moveToFirst()) {
                int id = cursor.getInt(cursor
                        .getColumnIndex(MediaStore.MediaColumns._ID));
                Uri baseUri = Uri.parse("content://media/external/images/media");
                return Uri.withAppendedPath(baseUri, "" + id);
            } else {
                if (imageFile.exists()) {
                    ContentValues values = new ContentValues();
                    values.put(MediaStore.Images.Media.DATA, filePath);
                    return getContentResolver().insert(
                            MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
                } else {
                    return null;
                }
            }
        }

    代码适配解决完了,还有一个 FileProvider 问题需要做如下配置。

    1. 在 res 目录下创建一个名为 xml 的文件夹,并在其下创建一个名为 file_paths.xml 文件,其内容如下:
    <?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <files-path
            name="images"
            path="Android/data/com.example.package.name/files/Pictures/OriPicture/" />
        <external-path
            name="images"
            path="Android/data/com.example.package.name/files/Pictures/OriPicture/" />
        <external-files-path
            name="images"
            path="files/Pictures/OriPicture" />
        <root-path
            name="images"
            path="" />
        <root-path
            name="images"
            path="" />
    </paths>
    2. 在 AndroidMainfest.xml 中的 application 节点下做如下配置:
    
    <!--FileProvider共享文件、缓存-->
            <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="com.cxs.yukumenu.provider"
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/file_paths" />
            </provider>

    其中这里的 android:authorities 属性值要和代码中 FileProvider.getUriForFile()的第二个参数值保持一致。

    注意

    • 代码已全部给出,粘贴即可使用
    • 本次测试真机:华为5.1.1,一加8.0.0

    总结

    1. 机型适配是个细活,但能锻炼排查问题和解决问题能力。
    2. 本文的代码有很多是可以抽取的,如果是在项目中使用,那么建议提取出特定功能的代码。
    展开全文
  • html拍照

    2019-06-21 11:02:31
    html<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compa...

    html

    <!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <meta http-equiv="X-UA-Compatible" content="ie=edge">  <link rel="stylesheet" href="../css/style.css">  <link rel="stylesheet" href="../css/element.css">  <script src="../js/rem.js"></script>  <script src="../js/pub.js"></script>  <script src="../js/jquery-1.12.4.js"></script>  <script type='text/javascript' src='../js/index.js' charset='utf-8'></script>  <title>信息采集</title>  <style>    nav {      height: 0.5rem;      width: 100%;      font-size: 0.18rem;      line-height: 0.5rem;      text-align: center;      border-bottom: 0.01rem solid #eee;    }    .logo {      height: 2rem;    }    .btn {      margin-top: 0.25rem;      text-align: center;    }    .box {      width: 100%;      justify-content: space-around;      margin-top: 0.15rem;    }    .img_box {      height: 2.5rem;      background: #eee;      width: 100%;      display: flex;      justify-content: space-around;      flex-direction: column;      align-items: center;    }    .po_nav {      padding: 0 0.2rem 0 0.2rem;      font-size: 0.18rem;      background-color: #fff;      width: 100%;      position: fixed;      top: 0;      left: 0;      height: 0.5rem;      display: flex;      justify-content: space-between;      align-items: center    }    .po_back {      width: 0.22rem;      height: 0.22rem;      display: flex;      justify-content: center;      align-items: center    }    .po_back_row {      width: 0.15rem;      height: 0.15rem;    }    .head {      width: 0.5rem;      height: 0.5rem;      margin: 0.5rem auto    }    .headipt {      font-size: 0.16rem    }    .mine_container {      width: 100%;      height: 1.5rem;      display: flex;      justify-content: space-between;      align-items: center;      background-color: #fff;      flex-direction: column;      font-size: 0.16rem;      padding-top: 0.2rem    }    .pic {      font-size: 0.16rem;      border: 0.01rem solid #eee;      padding: 0.05rem 0.08rem;      border-radius: 0.05rem;      width: 1rem;      display: inline-block;      text-align: center;    }    .mine_pic {      width: 0.65rem;      height: 0.65rem;      border-radius: 50%;    }    .fs {      font-size: 0.14rem;      margin-top: 0.5rem;      color: #ccc;      text-align: center;    }    .f_tit {      font-size: 0.18rem;      color: #282828    }    [v-cloak] {      display: none !important    }    .number_box {      display: flex;      justify-content: space-around;      padding-top: 0.5rem;    }    .container input {      opacity: 0;      filter: alpha(opacity=0);      height: 100%;      width: 100%;      position: absolute;      top: 0;      left: 0;      z-index: 9;    }    #mainForm {      width: 100%;      padding: 0.15rem;      font-size: 0.14rem;    }    .container {      width: 100% !important;      position: relative;      display: flex;      justify-content: center;      align-items: center;      flex-direction: column;    }  </style></head><body>  <!-- <input type="file" capture="camera" accept="image/*" id="cameraInput" name="cameraInput"> -->  <div id="app" v-cloak>    <nav>      速通门人员信息采集    </nav>    <form id="mainForm">      <div class="content">        <div class="img-area">          <div class="container">            <input type="file" id='id-face' name='face' accept="image/*" />            <img class="logo" :src='src' alt="" id='face-result'>            <div class="row_flex al_flex box">              <div id='face-empty-result'>                <el-button size='mini'>拍照</el-button>              </div>            </div>          </div>        </div>      </div>      <div class="btn">        <el-button type="primary" size='mini' @click='submit'>提交</el-button>      </div>    </form>    <div class="fs ">      <span class="f_tit">        拍照要求:      </span>      <span>        纯色背景,      </span>      <span>        免冠正面照,      </span>      <span>        亮度适中,      </span>      <span>如果不满意,点击图片可以更换</span>    </div>  </div>  <script src="../js/vue.js"></script>  <script src="../js/element.js"></script>  <script src="../js/face.js"></script></body></html>复制代码

    js

    var app = new Vue({  el: "#app",  data: {    uuid: '',    identity_card: '',    src: '../other/face.png',    fg: false,  },  created() {    const that = this    that.identity_card = pub._LinkParm('id')    that.uuid = pub._LinkParm('uuid')  },  mounted() {    const that = this    window.onload = function () {      document.getElementById("id-face").addEventListener("change", function () {        that.onFileChange(this, "face-result", "face-empty-result")      });      // document.getElementById("id-back").addEventListener("change", function(){             //     onFileChange(this,"back-result","back-empty-result")      // });      // document.getElementsByClassName("btn")[0].addEventListener("click", function () {      //   if(that.fg){      //     // that.submit();      //     // console.log('zhen')      //   }else{      //     // that.submit();      //     // console.log('jia')      //   }      // });    };  },  methods: {    /**    * 选中图片时的处理    * @param {*} fileObj input file元素    * @param {*} el //选中后用于显示图片的元素ID    * @param {*} btnel //未选中图片时显示的按钮区域ID    */    onFileChange(fileObj, el, btnel) {      const that = this;      // console.log('选择图片')      that.fg = true      var windowURL = window.URL || window.webkitURL;      var dataURL;      var imgObj = document.getElementById(el);      document.getElementById(btnel).style.display = "none";      imgObj.style.display = "block";      if (fileObj && fileObj.files && fileObj.files[0]) {        dataURL = windowURL.createObjectURL(fileObj.files[0]);        imgObj.src = dataURL;        // console.log(dataURL)      } else {        dataURL = fileObj.value;        imgObj.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale)";        imgObj.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = dataURL;        // console.log(dataURL)      }    },    /**    * 将图片压缩后返回base64格式的数据    * @param {*} image img元素    * @param {*} width 压缩后图片宽度    * @param {*} height 压缩后图片高度    * @param {*} qua //图片质量1-100    */    compressImageTobase64(image, width, height, qua) {      var quality = qua ? qua / 100 : 0.8;      var canvas = document.createElement("canvas"),        ctx = canvas.getContext('2d');      var w = image.naturalWidth,        h = image.naturalHeight;      canvas.width = width || w;      canvas.height = height || h;      ctx.drawImage(image, 0, 0, w, h, 0, 0, width || w, height || h);      var data = canvas.toDataURL("image/jpeg", quality);      // console.log(w, h, width, height, data)      return data;    },    submit() {      const that = this      //1、form提交      //document.getElementById("mainForm").submit();      //2、压缩后ajax提交      // console.log('上传图片')      if (that.fg) {
            // 设置压缩图片的大小比例        var _img = document.getElementById("face-result"),          _img_h = _img.naturalHeight,          _img_w = _img.naturalWidth,          _img_num = 1024,          _img_width, _img_height, _img_b;        if (_img_w > _img_h) {          // console.log('kuan')          _img_b = _img_num / _img_w;          _img_width = _img_num;          _img_height = _img_b * _img_h        } else {          // console.log('gao ')          _img_b = _img_num / _img_h;          _img_height = _img_num;          _img_width = _img_b * _img_w        }        var face_data = that.compressImageTobase64(document.getElementById("face-result"), _img_width, _img_height, 90);        var formData = new FormData();        formData.append("face", face_data);        formData.append("identity_card", that.identity_card);        // formData.append("back",back_data);        //需引入jQuery        $.ajax({          url: '',          type: 'POST',          cache: false,          // data:JSON.stringify(data) ,          data: formData,          dataType: "JSON",          // timeout: 180000,          processData: false,          contentType: false,          success: function (res) {            // console.log(res)            if(res.code =='200'){              that.src = res.data              that.onSubmit()            }else{              alert(res.msg)            }                      },          error: function (r) {            // console.log(r)          }        });      }else{        alert('请拍照!')      }    },    onSubmit() {      const that = this;      // console.log('baoxun')      var use_parm = {        that: that,        _url: pub._url,        ur: pub._DetailApi.editPhoto, // 具体接口        cbk: that.cb_editPhoto, // 回调        data: {          uuid: that.uuid,          photo_path: that.src        }, // 形参      };      // console.log(use_parm)      pub._InitAjax(use_parm)    },    cb_editPhoto(res) {      // e.log(res)      if (res.code == "200") {        alert('保存成功,跳转信息查询页!')        setTimeout(function () {          window.location.href = './card.html'        }, 1000)      }    }  },})复制代码

    input 调用摄像头

    <input type="file" capture="camera" accept="image/*" id="cameraInput" name="cameraInput">复制代码


    转载于:https://juejin.im/post/5cff67315188254628166fc2

    展开全文
  • 拍照预览

    2019-03-08 11:16:12
    package com.newingscom.takephoto... import android.Manifest; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory;...import android.graphics.ImageFormat;...imp...
    package com.newingscom.takephoto;
    
    import android.Manifest;
    import android.app.Activity;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.ImageFormat;
    import android.graphics.Matrix;
    import android.hardware.Camera;
    import android.os.Build;
    import android.os.Environment;
    import android.support.v4.app.ActivityCompat;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.View;
    import android.widget.Button;
    import android.widget.Toast;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class MainActivity extends BaseActivity {
    
        private SurfaceView sv_camera;
        private SurfaceHolder surfaceHolder;
        private Camera mCamera;
        private String TAG = "mingshine";
    
        private boolean isPreviewing;
        private Button btn_cancle;
        private Button btn_save;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            permission();
            initView();
            setListener();
        }
    
        private void initView() {
            setContentView(R.layout.activity_main);
            sv_camera = findViewById(R.id.sv_camera);
            btn_cancle = findViewById(R.id.btn_cancle);
            btn_save = findViewById(R.id.btn_save);
            initCamera();
        }
    
        private Bitmap takeBitmap = null;
    
        private void initCamera() {
            // 获得SurfaceView的SurfaceHolder
            surfaceHolder = sv_camera.getHolder();
            // 为surfaceHolder添加一个回调监听器
            surfaceHolder.addCallback(new SurfaceHolder.Callback() {
                @Override
                public void surfaceChanged(SurfaceHolder holder, int format,
                                           int width, int height) {
                }
    
                @Override
                public void surfaceCreated(SurfaceHolder holder) {
                    startCamera();
                }
    
                @Override
                public void surfaceDestroyed(SurfaceHolder holder) {
                    // 如果camera不为null ,释放摄像头
                    if (mCamera != null) {
                        mCamera.release();
                        mCamera = null;
                    }
                }
            });
            // 设置该SurfaceView自己不维护缓冲
            surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }
    
        private void startCamera() {
    
            //默认开启后置
            mCamera = Camera.open(findFrontCamera() == -1 ? 0 : findFrontCamera());
            mCamera.setDisplayOrientation(90);//摄像头进行旋转90°
            if (mCamera != null) {
                try {
                    Camera.Parameters parameters = mCamera.getParameters();
                    //设置预览照片的大小
    //                parameters.setPreviewFpsRange(100, 120);
                    //设置相机预览照片帧数
    //                parameters.setPreviewFpsRange(4, 10);
                    //设置图片格式
                    parameters.setPictureFormat(ImageFormat.JPEG);
                    //设置图片的质量
                    parameters.set("jpeg-quality", 90);
                    mCamera.setPreviewDisplay(surfaceHolder);
                    //开始预览
                    mCamera.startPreview();
                    isPreviewing = true;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
        }
    
    
        private void setListener() {
            sv_camera.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (isPreviewing && (mCamera != null)) {
                        mCamera.takePicture(mShutterCallback, null, mJpegPictureCallback);
                    }
                }
            });
        }
    
        /*为了实现拍照的快门声音及拍照保存照片需要下面三个回调变量*/
        Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback()
                //快门按下的回调,在这里我们可以设置类似播放“咔嚓”声之类的操作。默认的就是咔嚓。
        {
            public void onShutter() {
                // TODO Auto-generated method stub
                Log.i(TAG, "myShutterCallback:onShutter...");
            }
        };
    
        Camera.PictureCallback mJpegPictureCallback = new Camera.PictureCallback()
                //对jpeg图像数据的回调,最重要的一个回调
        {
            public void onPictureTaken(byte[] data, Camera camera) {
                // TODO Auto-generated method stub
                Log.i(TAG, "myJpegCallback:onPictureTaken...");
                takeBitmap = null;
                if (null != data) {
                    takeBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);//data是字节数据,将其解析成位图
                    mCamera.stopPreview();
                    isPreviewing = false;
                    updateBtnVisable(View.VISIBLE);
                }
    
            }
        };
    
        //取消
        public void cancle(View view) {
            mCamera.startPreview();
            isPreviewing = true;
            updateBtnVisable(View.INVISIBLE);
            takeBitmap = null;
        }
    
        //保存
        public void save(View view) {
            mCamera.startPreview();
            isPreviewing = true;
            updateBtnVisable(View.INVISIBLE);
            if (takeBitmap != null) {
                takeBitmap = adjustPhotoRotation(takeBitmap, -90);
                File sdRoot = Environment.getExternalStorageDirectory();
                File file = new File(sdRoot, "takephoto");
                if (!file.exists()) file.mkdirs();
                File bitmapFile = new File(file.getAbsolutePath() + "/" + System.currentTimeMillis() + ".png");
                try {
                    FileOutputStream fos = new FileOutputStream(bitmapFile);
                    takeBitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
                    fos.flush();
                    fos.close();
                    Toast.makeText(MainActivity.this, "保持成功", Toast.LENGTH_SHORT).show();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            takeBitmap = null;
        }
    
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            // 如果camera不为null ,释放摄像头
            if (mCamera != null) {
                mCamera.release();
                mCamera = null;
            }
        }
    
        private int findFrontCamera() {
            int cameraCount = 0;
            Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
            cameraCount = Camera.getNumberOfCameras(); // get cameras number
    
            for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
                Camera.getCameraInfo(camIdx, cameraInfo); // get camerainfo
                if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                    // 代表摄像头的方位,目前有定义值两个分别为CAMERA_FACING_FRONT前置和CAMERA_FACING_BACK后置
                    return camIdx;
                }
            }
            return -1;
        }
        //动态授权
    
        private void permission() {
    
            if (Build.VERSION.SDK_INT >= 23) {
                String[] mPermissionList = new String[]{
                        Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE,
                        Manifest.permission.CAMERA};
                ActivityCompat.requestPermissions(MainActivity.this, mPermissionList, 123);
            }
        }
    
        private void updateBtnVisable(int visable) {
            btn_cancle.setVisibility(visable);
            btn_save.setVisibility(visable);
        }
    
        Bitmap adjustPhotoRotation(Bitmap bm, final int orientationDegree) {
    
            Matrix m = new Matrix();
            m.setRotate(orientationDegree, (float) bm.getWidth() / 2, (float) bm.getHeight() / 2);
    
            try {
                Bitmap bm1 = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), m, true);
    
                return bm1;
    
            } catch (OutOfMemoryError ex) {
            }
            return null;
    
        }
    
    }
    
    
    展开全文
  • android camera 后台拍照

    千次阅读 2013-07-08 10:15:15
    Android2010.11.16———androidCamera拍照的两个有关问题 2010.11.16———android Camera 拍照的两个问题 2010.11.16———androidCamera拍照的两个问题1、setParameters failed 异常信息如下11-16 11:21:33....
  • DRuler 拍照测距原理

    万次阅读 2016-12-28 11:44:28
    拍照测距原理
  • 手机的web页面调用相机拍照上传

    万次阅读 2015-07-29 03:58:43
    想在手机里的web页面里上传照片,又希望能调用摄像头拍完了再上传。 看这代码,重要的是capture="camera" accept="image/*"。 结束。
  • TakePhoto https://github.com/crazycodeboy/TakePhoto/blob/master/README.md
  • 现在Android手机一般都会带有照相功能,有很多朋友就发现手机照相时快门声音很响,想关又关不掉。。。。。不过话说回来,静音拍照你想做啥?来到主题上,因为网络上有很多关于“删除或修改快门声音文件是关闭快门声...
  • Android监听照相广播

    千次阅读 2015-08-24 09:41:18
    也许很多时候,你想实现一个功能,那就是,当用手机拍照时,你的程序可以知道已经拍照完成,并取得刚拍摄的照片。这个思路很简单,就是新建一个广播接收器,当手机进行拍照的时候,系统会发出一个广播,你接受到此...
  • html5网页调起相机拍照

    千次阅读 2018-03-01 18:18:15
    使用html5中 input的 capture属性,设定为camera,即可调起相机,页面显示跟上传文件一样,点击后调起camera。源码如下:&lt;...gt; &lt;meta name="viewport" content="width=device-width,...
  • 阿里云 OCR身份证识别Api 使用(一)

    万次阅读 2017-05-09 15:19:40
    最近项目更新使用拍照识别身份证功能,为了省去用户手动输入身份证号码信息等。 从网上搜了一些方案,发现阿里云的非常便宜,果断采用。 但是没有android 的官方案例 ,只能自己搞了。 首选OCR 识别技术,需要调用...
  • 在最开始接触Android相机功能之前,先来体验一下Android调用系统照相功能吧核心代码Intent intent = new Intent(); //调用照相机intent.setAction("android.media.action.STILL_IMAGE_CAMERA
  • HTML5实现摄像头调用并拍照,兼容各大浏览器,需要的来拿
  • 智能手机现在成了人们生活的必需品,现在的手机像素越来越高,还自带美颜功能,因此,无论是生活中的美好时刻记录,还是无聊时刻的自拍,手机拍照就显得尤为重要了。但是我们在使用苹果手机的时候,尤其是曾经摔过碰...
  • 如果说婚纱产业是大餐,需要前期准备的比较多,消费也高,绝对利润也大,那么证件照就是快餐,这种服务非常好复制,投入小,但是成本利润率应该相当高,甚至高于婚纱行业,而且受众非常多,几乎可以说人人需要。...
  • Android如何调用系统现有的照相机拍照与摄像

    千次下载 热门讨论 2020-07-30 23:32:29
    Android如何调用系统现有的照相机拍照与摄像,详细参见博客:http://www.cnblogs.com/plokmju/p/Android_SystemCamera.html
  • 随着OCR文字识别技术的盛行,同时也给...今天小编就给大家介绍一款可以拍照识别并能翻译文字的软件-迅捷文字识别。 这款软件还是比较实用的,可以识别相册里的图片,也可以拍照识别。 应用简介: 迅捷文字识别是一...
1 2 3 4 5 ... 20
收藏数 131,872
精华内容 52,748
关键字:

拍照