三星Galaxy S3、S4、S5的Android摄像头/图片方向问题

三星Galaxy S3、S4、S5的Android摄像头/图片方向问题,android,android-camera,samsung-galaxy-camera,Android,Android Camera,Samsung Galaxy Camera,我正在为Android API 16到21开发一个摄像头应用程序,它的主要和唯一目的是拍摄人像。我能够使用多个设备(Nexus 4、Nexus 5、HTC…)拍摄照片,并使它们正确定向(这意味着我的预览在大小和方向上都与拍摄的照片相同) 然而,我已经在其他几个设备上测试了我的应用程序,其中一些给我带来了很多麻烦:三星Galaxy S3/S4/S5 在这三台设备上,预览显示正确,但是通过方法onPictureTaken(最终字节[]jpeg,摄像头)返回的图片始终是侧面的 这是从byte[]jpe

我正在为Android API 16到21开发一个摄像头应用程序,它的主要和唯一目的是拍摄人像。我能够使用多个设备(Nexus 4、Nexus 5、HTC…)拍摄照片,并使它们正确定向(这意味着我的预览在大小和方向上都与拍摄的照片相同)

然而,我已经在其他几个设备上测试了我的应用程序,其中一些给我带来了很多麻烦:三星Galaxy S3/S4/S5

在这三台设备上,预览显示正确,但是通过方法
onPictureTaken(最终字节[]jpeg,摄像头)
返回的图片始终是侧面的

这是从
byte[]jpeg
创建的位图,在将其保存到磁盘之前,在ImageView中显示给我的用户:

这是保存在磁盘上的图像:

正如您所见,图像在预览中完全拉伸,并且在保存到磁盘上后错误地旋转

这是我的CameraPreview类(我混淆了其他方法,因为它们与摄影机参数无关):

为什么这段代码适用于除三星外的其他设备

我试图在以下帖子中找到答案,但到目前为止没有任何帮助: 和

编辑

落实Choey Chong的答案不会改变任何事情:

public void onPictureTaken(final byte[] data, Camera camera)
{
    try
    {
        File pictureFile = new File(...);
        Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length);
        FileOutputStream fos = new FileOutputStream(pictureFile);
        realImage.compress(Bitmap.CompressFormat.JPEG, 100, fos);

        int orientation = -1;
        ExifInterface exif = new ExifInterface(pictureFile.toString());
        int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,  ExifInterface.ORIENTATION_NORMAL);

        switch (exifOrientation)
        {
            case ExifInterface.ORIENTATION_ROTATE_270:
                orientation = 270;
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                orientation = 180;
                break;
            case ExifInterface.ORIENTATION_ROTATE_90:
                orientation = 90;
                break;
            case ExifInterface.ORIENTATION_NORMAL:
                orientation = 0;
                break;
            default:
                break;
        }

        fos.close();
}
以下是我获得的工作设备的EXIF结果:

  • 方向:0
这里是S4的结果:

  • 方向:0

这是因为手机仍然以横向方式保存数据,并将元数据设置为90度。 您可以尝试检查exif,在放入图像视图之前旋转位图。要检查exif,请使用以下内容:

    int orientation = -1;

    ExifInterface exif = new ExifInterface(imagePath);

    int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 
            ExifInterface.ORIENTATION_NORMAL);

    switch (exifOrientation) {
        case ExifInterface.ORIENTATION_ROTATE_270:
            orientation = 270;

            break;
        case ExifInterface.ORIENTATION_ROTATE_180:
            orientation = 180;

            break;
        case ExifInterface.ORIENTATION_ROTATE_90:
            orientation = 90;

            break;

        case ExifInterface.ORIENTATION_NORMAL:
            orientation = 0;

            break;
        default:
            break;
    }
我用过这个。
它在这个问题上帮助了我很多。

关于保存的图像,我也遇到了类似的问题

我使用了类似于用户kinghsumit在这里描述的内容(2016年9月15日的评论)

我会把它复制到这里,以防万一

private CameraSource.PictureCallback mPicture = new CameraSource.PictureCallback() {
    @Override
    public void onPictureTaken(byte[] bytes) {
       int orientation = Exif.getOrientation(bytes);
       Bitmap   bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
       switch(orientation) {
           case 90:
               bitmapPicture= rotateImage(bitmap, 90);
               break;
           case 180:
               bitmapPicture= rotateImage(bitmap, 180);
               break;
           case 270:
               bitmapPicture= rotateImage(bitmap, 270);
               break;
           case 0:
               // if orientation is zero we don't need to rotate this
           default:
               break;
       }
       //write your code here to save bitmap 
   }
}

public static Bitmap rotateImage(Bitmap source, float angle) {
    Matrix matrix = new Matrix();
    matrix.postRotate(angle);
    return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
}
下面的类用于从字节[]数据获取方向

public class Exif {
    private static final String TAG = "CameraExif";

    // Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
    public static int getOrientation(byte[] jpeg) {
        if (jpeg == null) {
            return 0;
        }

        int offset = 0;
        int length = 0;

        // ISO/IEC 10918-1:1993(E)
        while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) {
            int marker = jpeg[offset] & 0xFF;

            // Check if the marker is a padding.
            if (marker == 0xFF) {
                continue;
            }
            offset++;

            // Check if the marker is SOI or TEM.
            if (marker == 0xD8 || marker == 0x01) {
                continue;
            }
            // Check if the marker is EOI or SOS.
            if (marker == 0xD9 || marker == 0xDA) {
                break;
            }

            // Get the length and check if it is reasonable.
            length = pack(jpeg, offset, 2, false);
            if (length < 2 || offset + length > jpeg.length) {
                Log.e(TAG, "Invalid length");
                return 0;
            }

            // Break if the marker is EXIF in APP1.
            if (marker == 0xE1 && length >= 8 &&
                    pack(jpeg, offset + 2, 4, false) == 0x45786966 &&
                    pack(jpeg, offset + 6, 2, false) == 0) {
                offset += 8;
                length -= 8;
                break;
            }

            // Skip other markers.
            offset += length;
            length = 0;
        }

        // JEITA CP-3451 Exif Version 2.2
        if (length > 8) {
            // Identify the byte order.
            int tag = pack(jpeg, offset, 4, false);
            if (tag != 0x49492A00 && tag != 0x4D4D002A) {
                Log.e(TAG, "Invalid byte order");
                return 0;
            }
            boolean littleEndian = (tag == 0x49492A00);

            // Get the offset and check if it is reasonable.
            int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
            if (count < 10 || count > length) {
                Log.e(TAG, "Invalid offset");
                return 0;
            }
            offset += count;
            length -= count;

            // Get the count and go through all the elements.
            count = pack(jpeg, offset - 2, 2, littleEndian);
            while (count-- > 0 && length >= 12) {
                // Get the tag and check if it is orientation.
                tag = pack(jpeg, offset, 2, littleEndian);
                if (tag == 0x0112) {
                    // We do not really care about type and count, do we?
                    int orientation = pack(jpeg, offset + 8, 2, littleEndian);
                    switch (orientation) {
                        case 1:
                            return 0;
                        case 3:
                            return 180;
                        case 6:
                            return 90;
                        case 8:
                            return 270;
                    }
                    Log.i(TAG, "Unsupported orientation");
                    return 0;
                }
                offset += 12;
                length -= 12;
            }
        }

        Log.i(TAG, "Orientation not found");
        return 0;
    }

    private static int pack(byte[] bytes, int offset, int length, boolean littleEndian) {
        int step = 1;
        if (littleEndian) {
            offset += length - 1;
            step = -1;
        }

        int value = 0;
        while (length-- > 0) {
            value = (value << 8) | (bytes[offset] & 0xFF);
            offset += step;
        }
        return value;
    }
}
公共类Exif{
私有静态最终字符串标记=“CameraExif”;
//以顺时针方向返回度。值为0、90、180或270。
公共静态整型getOrientation(字节[]jpeg){
如果(jpeg==null){
返回0;
}
整数偏移=0;
整数长度=0;
//ISO/IEC 10918-1:1993(E)
而(偏移量+3jpeg.length){
Log.e(标记“无效长度”);
返回0;
}
//如果标记在APP1中为EXIF,则中断。
如果(标记==0xE1&&length>=8&&
包装(jpeg,偏移量+2,4,假)=0x45786966&&
包装(jpeg,偏移量+6,2,假)=0){
偏移量+=8;
长度-=8;
打破
}
//跳过其他标记。
偏移量+=长度;
长度=0;
}
//JEITA CP-3451 Exif版本2.2
如果(长度>8){
//识别字节顺序。
int tag=pack(jpeg,偏移量,4,假);
如果(标记!=0x49492A00&&tag!=0x4D4D002A){
Log.e(标记“无效字节顺序”);
返回0;
}
布尔littleEndian=(标记==0x492A00);
//获取偏移量并检查其是否合理。
int count=pack(jpeg,偏移量+4,4,littleEndian)+2;
如果(计数<10 | |计数>长度){
Log.e(标记“无效偏移量”);
返回0;
}
偏移量+=计数;
长度-=计数;
//获取计数并遍历所有元素。
计数=pack(jpeg,偏移量-2,2,littleEndian);
而(计数-->0&&length>=12){
//获取标签并检查其是否为方向。
标签=包装(jpeg,偏移量,2,littleEndian);
如果(标记==0x0112){
//我们并不真正关心类型和计数,是吗?
int-orientation=pack(jpeg,偏移量+8,2,littleEndian);
开关(方向){
案例1:
返回0;
案例3:
返回180;
案例6:
返回90;
案例8:
返回270;
}
Log.i(标签“无支撑方向”);
返回0;
}
偏移量+=12;
长度-=12;
}
}
Log.i(标签“未找到方向”);
返回0;
}
专用静态整型包(字节[]字节,整型偏移量,整型长度,布尔型littleEndian){
int步长=1;
如果(小印度){
偏移量+=长度-1;
步骤=-1;
}
int值=0;
while(长度-->0){

value=(value您可以尝试使用摄影机参数来修复旋转问题

Camera.Parameters parameters = camera.getParameters();
parameters.set("orientation", "portrait");
parameters.setRotation(90);
camera.setParameters(parameters);

感谢您的回答,我实现了您的解决方案(请参见编辑),但在worki上ExiForOrientation始终等于0
Camera.Parameters parameters = camera.getParameters();
parameters.set("orientation", "portrait");
parameters.setRotation(90);
camera.setParameters(parameters);