RedApparat / Fotoapparat

Making Camera for Android more friendly. 📸
Apache License 2.0
3.82k stars 407 forks source link

Wrong Orientation of image captured using this library #293

Closed fazalBykea closed 5 years ago

fazalBykea commented 6 years ago

When I captured image and write image to file the image gets rotate on the left side i think there is an orientation issue in the library.

Here is my code.

/***
     * Take picture from camera and save into new file and compress the image
     */
    private fun upoadImage(){
        var fileImage = File(FileUtils.getImagePath())
        if (!fileImage.exists() == true){
            fileImage.createNewFile()
        }

        var result = fotoapparat
                ?.takePicture()
                ?.saveToFile(fileImage)
        result?.whenAvailable {
            var imageCompress = ImageCompression(this@CustomCameraActivity, listener)
            imageCompress.execute(fileImage.absolutePath)
        }
    }

### Recieved Result

rotate to left instead of right

Expected Result

rotate to right.

XinyueZ commented 6 years ago

I use following codes to capture frames, perhaps they can help you:

 override fun process(frame: Frame) {
        Log.d(TAG, "frame: ${frame.image.size}, ${frame.size}")

        YuvImage(
            frame.image,
            ImageFormat.NV21,
            frame.size.width,
            frame.size.height,
            null
        ).let { yuvImage ->
            ByteArrayOutputStream().use { output ->
                yuvImage.compressToJpeg(
                    Rect(0, 0, frame.size.width, frame.size.height),
                    100,
                    output
                )
                output.toByteArray().apply {
                    BitmapFactory.decodeByteArray(this, 0, size)?.let { bitmap ->
                        process(
                            bitmap.rotate(90f).flip(
                                false, activeCamera == Camera.Front
                            )
                        )
                        bitmap.recycle()
                    }
                }
            }
        }
    }

    private fun Bitmap.flip(horizontal: Boolean, vertical: Boolean): Bitmap {
        val matrix = Matrix()
        matrix.preScale((if (horizontal) -1 else 1).toFloat(), (if (vertical) -1 else 1).toFloat())
        return Bitmap.createBitmap(this, 0, 0, width, height, matrix, true)
    }

    private fun Bitmap.rotate(degrees: Float): Bitmap {
        val matrix = Matrix()
        matrix.postRotate(degrees)
        val scaledBitmap = Bitmap.createScaledBitmap(this, width, height, true)
        return Bitmap.createBitmap(
            scaledBitmap,
            0,
            0,
            scaledBitmap.width,
            scaledBitmap.height,
            matrix,
            true
        )
    }
MarkMurillo commented 6 years ago

Hi, when using the library to take a picture and save to a file, it contains EXIF information on the orientation of the image. It is the user's responsibility to adjust according to the rotation contained in the EXIF data of the picture.

Here is some kotlin code to rotate a saved image adjusting for EXIF data on rotation. This code assumes you want the image to be always point upright (0 rotation).

    private fun handleRotation(imgPath: String) {
        val bMap = BitmapFactory.decodeFile(imgPath) ?: return
        try {
            val ei = ExifInterface(imgPath)
            val orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_UNDEFINED)

            var rotatedBitmap: Bitmap? = null
            when (orientation) {
                ExifInterface.ORIENTATION_NORMAL -> rotatedBitmap = bMap

                ExifInterface.ORIENTATION_ROTATE_90 -> rotatedBitmap = ImageUtil.rotateImage(bMap, 270f)

                ExifInterface.ORIENTATION_ROTATE_180 -> rotatedBitmap = ImageUtil.rotateImage(bMap, 180f)

                ExifInterface.ORIENTATION_ROTATE_270 -> rotatedBitmap = ImageUtil.rotateImage(bMap, 90f)
                else -> rotatedBitmap = bMap
            }

            //Update the input file with the new bytes.
            var out: FileOutputStream? = null
            try {
                out = FileOutputStream(imgPath)
                rotatedBitmap!!.compress(Bitmap.CompressFormat.JPEG, 100, out) // bmp is your Bitmap instance
            } catch (e: Exception) {
                e.printStackTrace()
            } finally {
                try {
                    out?.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }

            }

        } catch (e: IOException) {
        }

    }
XinyueZ commented 6 years ago

@MarkMurillo I have done a little refactor on ur codes, it helps me very much. https://gist.github.com/XinyueZ/aba75863047a0b243197c4be9195bb89

MarkMurillo commented 6 years ago

@MarkMurillo I have done a little refactor on ur codes, it helps me very much. https://gist.github.com/XinyueZ/aba75863047a0b243197c4be9195bb89

Wow that's much cleaner thanks.

dmitry-zaitsev commented 5 years ago

@MarkMurillo @XinyueZ thanks for answering the question 👍 It is sad that BitmapDecoder is mostly ignoring the Exif information. It does work for some devices but not for all of them

Keesdil commented 5 years ago

Dear sirs, i have chosen a picture on a virtual device in Android Studio and put the bitmap in "/storage/emulated/0/Pictures/filename.jpg". This bitmap shows rotated 90 to the left, but the original picture from the camera is NOT rotated. So i want to rotate the bitmap. So i tried to use handleRotation( imgPath), where imgPath = "/storage/emulated/0/Pictures/filename.jpg", the name of the file where i stored the bitmap from a before chosen picture, BUT handleRotation immediately ends with return after BitmapFactory.decodeFile(imgPath) ?: return. Also after retrieving the bitmap with (for instance) MediaStore.Images.Media.getBitmap( context?.contentResolver, data) and calling : val ei = ExifInterface(imgPath), this is not succesfull, as ExifInterface requires an ABSOLUTE path string! So what am i missing??