使用 Android Camera API,拍摄照片的方向始终未定义

Posted

技术标签:

【中文标题】使用 Android Camera API,拍摄照片的方向始终未定义【英文标题】:Using Android Camera API, snapped photo's orientation is always Undefined 【发布时间】:2015-03-13 02:20:58 【问题描述】:

我使用相机api,拍摄的照片总是旋转90度,我想旋转它。

所以首先我想知道图片的方向,这一点我卡住了。 我总是在这两个方面都得到不确定的方向。

代码如下:

    @Override
        public void onPictureTaken(byte[] data, Camera camera) 


            //Bitmap Options for lowering quality the bitmap to save memory
            Options options = new BitmapFactory.Options();
            options.inSampleSize = 4;
            options.inPreferredConfig = Bitmap.Config.RGB_565;

            //Make the bitmap
            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);

            //Making the path, the root will be fine for tests
            String path = Environment.getExternalStorageDirectory().toString();

            //output stream
            OutputStream outputStream = null;
            //Making the file as a jpg
            File file = new File(path, "tmp_pic" + ".jpg"); // the File to save to
            try 

                //Writing the file
                outputStream = new FileOutputStream(file);
                outputStream.flush();
                outputStream.close(); // do not forget to close the stream


                //Getting the orientation in both possible ways
                int ori = getOrientationFromExif(file.getPath());
                int ori2 = getOrientationFromUri(Uri.fromFile(file));
            
            catch (FileNotFoundException e) 
                e.printStackTrace();
            
            catch (IOException e) 
                e.printStackTrace();
            
            if (bitmap == null) 
                Toast.makeText(getApplicationContext(), "Error: Cant make photo.", Toast.LENGTH_SHORT).show();
            
            else 
                PhotoTapView.photoViews.get(index).setPhotoImage(bitmap);
                finish();
            
            cameraObject.release();
        

定位功能:

    //Getting orientation from file URI
    private int getOrientationFromUri(Uri imageUri) 
    String[] orientationColumn =  MediaStore.Images.Media.ORIENTATION ;
    Cursor cur = getContentResolver().query(imageUri, orientationColumn, null, null, null);
    int orientation = -1;
    if (cur != null && cur.moveToFirst()) 
        orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]));
    
    Log.i("Orientation from Uri", orientation + "");
    return orientation;


    //Getting orientation from ExifInterface  
    private static int getOrientationFromExif(String imagePath) 
    int orientation = -1;
    try 
        ExifInterface exif = new ExifInterface(imagePath);
        int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
        Log.i("Orientation from Exif: ", exifOrientation + "");
        switch (exifOrientation) 
            case ExifInterface.ORIENTATION_ROTATE_270:
                orientation = 270;
                Log.i("Orientation from Exif", "270");
            break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                orientation = 180;
                Log.i("Orientation from Exif", "180");
            break;
            case ExifInterface.ORIENTATION_ROTATE_90:
                Log.i("Orientation from Exif", "90");
                orientation = 90;
            break;
            case ExifInterface.ORIENTATION_NORMAL:
                orientation = 0;
                Log.i("Orientation from Exif", "0 - Normal");
            break;
            case ExifInterface.ORIENTATION_UNDEFINED:
                orientation = -1;
                Log.e("Orientation from Exif", "UNDEFINED");
        
    
    catch (IOException e) 
    return orientation;

日志输出:

01-14 19:46:09.468: E/Orientation from Exif(12411): UNDEFINED
01-14 19:46:09.468: I/Orientation from Uri(12411): -1

可能是什么问题?

【问题讨论】:

似乎在更强大的(最近的)android 硬件上,没有指定 EXIF 方向,因为相机应用程序会在编码 JPEG 之前旋转像素。在较慢的硬件上(过去),图像将以默认方向写入,实际方向将保存在 EXIF 信息中。 那么有没有办法真正做到这一点? 您似乎只能根据宽度和高度判断图像是纵向还是横向拍摄的。真正的方向似乎不可用。 @BitBank 如果您愿意,可以将此信息添加为答案,我会接受。 【参考方案1】:

自 2011 年初以来,我一直在解码/观察 Android JPEG 图像,因为我发布了一个图像查看应用程序。在“早期”,图像以传感器的原始方向编码,设备的实际方向被写入 EXIF 元数据。从大约 2 年前开始,我注意到方向不再被写入 EXIF 数据,而是相机应用程序在编码 JPEG 文件之前旋转图像像素。我的猜测是,这是因为一些照片查看器(* 咳嗽 * Windows * 咳嗽 *)在显示 JPEG 文件时忽略了 EXIF 方向,而不是等待微软修复它并指责 Android 做错了什么,他们决定利用更快的 CPU/内存,只需旋转图像。

结果是,在不知道 EXIF 方向的情况下,只能确定照片是以横向还是纵向拍摄的。这条信息只是一个假设,因为大多数相机传感器的宽度大于高度。

【讨论】:

天哪,我在寻找这种答案 2 天。因为你的回答我找到了一个真正有效的更新答案:***.com/a/26141254/1332549 处理定向照片的最佳方法是this。 仅供参考 - 在 Galaxy S6 上,三星会写入 EXIF 方向标签,因此不会普遍丢失。 你是说如果没有exif数据就无法判断照片是横拍还是竖拍?我对三星 Galaxy 5 设备有很大的问题,请看我的帖子:***.com/questions/32090603/…【参考方案2】:

在这段代码中

outputStream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream);  // Add this line
outputStream.flush();
outputStream.close(); // do not forget to close the stream

您忘记将字节实际写入输出流。所以,文件长度为0,自然不包含任何EXIF信息。

在调用decodeByteArray然后再次保存时也要小心,这也会丢失EXIF信息!您需要从原始图像字节中解析 EXIF。

【讨论】:

你能帮我写出实际的代码吗?我以前没有这样做过。 遗憾的是还是一样的结果。 打电话decodeByteArray时要注意的部分救了我!我试图通过使用 BitmapFactory.Options 进行不相关的操作来获取图像的宽度和高度,设置 options.inJustDecodeBounds = true,然后运行 ​​BitmapFactory.decodeStream(inputStream, null, options) 但我相信对 decodeStream 的调用导致EXIF信息中的方向数据设置为未定义(即被覆盖!)

以上是关于使用 Android Camera API,拍摄照片的方向始终未定义的主要内容,如果未能解决你的问题,请参考以下文章

Android 新老两代 Camera API 大起底

Android Camera2 拍照——使用TextureView

我应该使用哪个 Android Camera API

如何使用 Camera 2 API Android 提高捕获图像的质量?

Camera 2 API 会降低拍摄后的质量

Phonegap Vue js Android将CAMERA图像上传到API服务器