Monday, 5 July 2021

JPG image is stored incorrectly on external storage (Android)

I am developing an Android app and I am trying to save bitmaps as jpeg-images into the Pictures folder of the phone. The code below works mostly fine, but it occasionally happens that the app saves the photo incorrectly (see distorted image below). Any idea what may cause this error and how to fix it? (The app is designed for Android 10+, hence I am working with MediaStore). I am relatively new to Android development, so please let me know if I should add any information to the question. Thanks in advance for your help!

        lateinit var uri: Uri
        val imageOutStream: OutputStream
        val contentResolver = context.contentResolver

        val mimeType =  "image/jpeg"
        val mediaContentUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
        val values = ContentValues().apply {
            put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
            put(MediaStore.Images.Media.MIME_TYPE, mimeType)
            put(MediaStore.Images.Media.RELATIVE_PATH, directory)
        }
        contentResolver.run {
            uri = context.contentResolver.insert(mediaContentUri, values)
                            ?: return
            imageOutStream = openOutputStream(uri) ?: return
        }

        try {
            imageOutStream.use { bitmap.compress(Bitmap.CompressFormat.JPEG, photoCompression, it) }
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
        } finally {
            imageOutStream.close()
        }

        try {
            context.contentResolver.openInputStream(uri).use {
                val exif = ExifInterface(context.contentResolver.openFileDescriptor(uri, "rw")!!.fileDescriptor)
                saveExif(exif, context)     //method ads exif metadata to image

            }
        }catch (e: java.lang.Exception){

        }

While it might not be relevant, I have added the saveExif method for completeness (see below). This method adds some exif metadata to the saved image.

private fun saveExif(exif: ExifInterface, context: Context){
            if (referenceWithCaptionExif != "" && notesExif != "") {
                exif.setAttribute(ExifInterface.TAG_USER_COMMENT, "$referenceWithCaptionExif | $notesExif")
            } else {
                exif.setAttribute(ExifInterface.TAG_USER_COMMENT, "$referenceWithCaptionExif$notesExif")
            }
            if (companyExif != "") {
                exif.setAttribute(ExifInterface.TAG_CAMERA_OWNER_NAME, companyExif)
                val yearForExif = SimpleDateFormat("yyyy",
                        Locale.getDefault()).format(Date())
                exif.setAttribute(ExifInterface.TAG_COPYRIGHT, "Copyright (c) $companyExif $yearForExif")
            }
            if (projectExif != "") {
                exif.setAttribute(ExifInterface.TAG_IMAGE_DESCRIPTION, projectExif)
            }
            exif.setAttribute(ExifInterface.TAG_MAKER_NOTE, "Project[$projectExif] Company[$companyExif] " +
                    "Notes[$notesExif] Reference[$referenceExif] ReferenceType[$referenceTypeExif] Coordinates[$coordinatesExif] " +
                    "CoordinateSystem[$coordinateSystemExif] Accuracy[$accuracyExif] Altitude[$altitudeExif] " +
                    "Date[$dateTimeExif] Address[$addressExif]")
            exif.setAttribute(ExifInterface.TAG_ARTIST, "${android.os.Build.MANUFACTURER} ${android.os.Build.MODEL}")
            exif.setAttribute(ExifInterface.TAG_SOFTWARE, context.resources.getString(R.string.app_name))
            exif.setAttribute(ExifInterface.TAG_MAKE, (android.os.Build.MANUFACTURER).toString())
            exif.setAttribute(ExifInterface.TAG_MODEL, (android.os.Build.MODEL).toString())
            exif.setAttribute(ExifInterface.TAG_COMPRESSION, 7.toString())
            exif.setAttribute(ExifInterface.TAG_IMAGE_WIDTH, "${bitmapToProcess.width} px")
            exif.setAttribute(ExifInterface.TAG_IMAGE_LENGTH, "${bitmapToProcess.height} px")
            exif.setAttribute(ExifInterface.TAG_PIXEL_X_DIMENSION, "${bitmapToProcess.width} px")
            exif.setAttribute(ExifInterface.TAG_PIXEL_Y_DIMENSION, "${bitmapToProcess.height} px")
            exif.setAttribute(ExifInterface.TAG_GPS_ALTITUDE, altitudeExif)
            exif.setAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF, 0.toString())
            exif.setAltitude(altitudeMetricExif)
            exif.setLatLong(latitudeWGS84Exif, longitudeWGS84Exif)
            exif.setAttribute(ExifInterface.TAG_GPS_TIMESTAMP, timeGPSExif)
            exif.setAttribute(ExifInterface.TAG_GPS_DATESTAMP, dateGPSExif)
            exif.setAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD, "GPS")
            exif.setAttribute(ExifInterface.TAG_DATETIME, dateTimeOriginalExif)
            exif.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL, dateTimeOriginalExif)
            exif.setAttribute(ExifInterface.TAG_DATETIME_DIGITIZED, dateTimeOriginalExif)
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
                exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_DIGITIZED, SimpleDateFormat("XXX", Locale.getDefault()).format(Date()))
                exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL, SimpleDateFormat("XXX", Locale.getDefault()).format(Date()))
                exif.setAttribute(ExifInterface.TAG_OFFSET_TIME, SimpleDateFormat("XXX", Locale.getDefault()).format(Date()))
            }

            exif.saveAttributes()
    }

enter image description here



from JPG image is stored incorrectly on external storage (Android)

No comments:

Post a Comment