Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 42 additions & 5 deletions app/src/main/java/fr/free/nrw/commons/filepicker/FilePicker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ import fr.free.nrw.commons.filepicker.PickedFiles.singleFileList
import java.io.File
import java.io.IOException
import java.net.URISyntaxException
import android.graphics.Bitmap
import android.graphics.ImageDecoder
import android.os.Build
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import java.io.FileOutputStream


object FilePicker : Constants {
Expand Down Expand Up @@ -52,7 +58,7 @@ object FilePicker : Constants {
): Intent {
// storing picked image type to shared preferences
storeType(context, type)
// Supported types are SVG, PNG and JPEG, GIF, TIFF, WebP, XCF
// Supported types are SVG, PNG and JPEG, GIF, TIFF, WebP, XCF and HEIC (for future conversion)
val mimeTypes = arrayOf(
"image/jpg",
"image/png",
Expand All @@ -62,7 +68,8 @@ object FilePicker : Constants {
"image/webp",
"image/xcf",
"image/svg+xml",
"image/webp"
"image/heic",
"image/heif"
)
return plainGalleryPickerIntent(openDocumentIntentPreferred)
.putExtra(
Expand Down Expand Up @@ -349,7 +356,8 @@ object FilePicker : Constants {
val images = data?.getParcelableArrayListExtra<Image>("Images")
images?.forEach { image ->
val uri = image.uri
val file = PickedFiles.pickedExistingPicture(activity, uri)
var file = PickedFiles.pickedExistingPicture(activity, uri)
file = handleHeicFile(file, activity)
files.add(file)
}

Expand Down Expand Up @@ -379,6 +387,33 @@ object FilePicker : Constants {
callbacks.onCanceled(ImageSource.GALLERY, restoreType(activity))
}
}
@JvmStatic
fun convertHeicToJpg(file: File, context: Context): File {
val bitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val source = ImageDecoder.createSource(context.contentResolver, Uri.fromFile(file))
ImageDecoder.decodeBitmap(source)
} else {
throw IllegalStateException("HEIC conversion requires Android P+")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

throw IllegalStateException("HEIC conversion requires Android P+")

meaning? for older versions below the android 9 what will happen? It doesn't make sense to have throw method. Can you check once? @Lou0320

}

val jpgFile = File(file.parent, file.nameWithoutExtension + ".jpg")
FileOutputStream(jpgFile).use { out ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)
}
return jpgFile
}
@JvmStatic
private fun handleHeicFile(file: UploadableFile, activity: Activity): UploadableFile {
val extension = file.file.extension.lowercase()
return if (extension == "heic" || extension == "heif") {
val jpgFile = convertHeicToJpg(file.file, activity)
val uploadableFile = UploadableFile(jpgFile)
uploadableFile.hasUnsupportedFormat = true
uploadableFile
} else {
file
}
}

@Throws(IOException::class, SecurityException::class)
@JvmStatic
Expand All @@ -390,12 +425,14 @@ object FilePicker : Constants {
val clipData = data?.clipData
if (clipData == null) {
val uri = data?.data
val file = PickedFiles.pickedExistingPicture(activity, uri!!)
var file = PickedFiles.pickedExistingPicture(activity, uri!!)
file = handleHeicFile(file, activity)
files.add(file)
} else {
for (i in 0 until clipData.itemCount) {
val uri = clipData.getItemAt(i).uri
val file = PickedFiles.pickedExistingPicture(activity, uri)
var file = PickedFiles.pickedExistingPicture(activity, uri)
file = handleHeicFile(file, activity)
files.add(file)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class UploadableFile : Parcelable {

val contentUri: Uri
val file: File
var hasUnsupportedFormat: Boolean = false

constructor(contentUri: Uri, file: File) {
this.contentUri = contentUri
Expand All @@ -34,6 +35,7 @@ class UploadableFile : Parcelable {
private constructor(parcel: Parcel) {
contentUri = parcel.readParcelable(Uri::class.java.classLoader)!!
file = parcel.readSerializable() as File
hasUnsupportedFormat = parcel.readInt() == 1
}

fun getFilePath(): String {
Expand Down Expand Up @@ -126,6 +128,7 @@ class UploadableFile : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeParcelable(contentUri, flags)
parcel.writeSerializable(file)
parcel.writeInt(if (hasUnsupportedFormat) 1 else 0)
}

class DateTimeWithSource {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,12 @@ class ImageProcessingService @Inject constructor(
checkFBMD(filePath),
checkEXIF(filePath)
) { duplicateImage: Int, wrongGeoLocation: Int, darkImage: Int, fbmd: Int, exif: Int ->
val unsupportedFormatResult = if (uploadItem.hasUnsupportedFormat) fr.free.nrw.commons.utils.ImageUtils.IMAGE_FORMAT_UNSUPPORTED else 0
Timber.d(
"duplicate: %d, geo: %d, dark: %d, fbmd: %d, exif: %d",
duplicateImage, wrongGeoLocation, darkImage, fbmd, exif
"duplicate: %d, geo: %d, dark: %d, fbmd: %d, exif: %d, unsupported: %d",
duplicateImage, wrongGeoLocation, darkImage, fbmd, exif, unsupportedFormatResult
)
return@zip duplicateImage or wrongGeoLocation or darkImage or fbmd or exif
return@zip duplicateImage or wrongGeoLocation or darkImage or fbmd or exif or unsupportedFormatResult
}
}

Expand Down
3 changes: 2 additions & 1 deletion app/src/main/java/fr/free/nrw/commons/upload/UploadItem.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class UploadItem(
*/
var contentUri: Uri?,
//according to EXIF data
val fileCreatedDateString: String?
val fileCreatedDateString: String?,
val hasUnsupportedFormat: Boolean = false
) {
var imageQuality: Int = ImageUtils.IMAGE_WAIT
var uploadMediaDetails: MutableList<UploadMediaDetail> = mutableListOf(UploadMediaDetail())
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/java/fr/free/nrw/commons/upload/UploadModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ class UploadModel @Inject internal constructor(
uploadableFile?.getMimeType(context), imageCoordinates, place, fileCreatedDate,
createdTimestampSource,
uploadableFile?.contentUri,
fileCreatedDateString
fileCreatedDateString,
uploadableFile?.hasUnsupportedFormat ?: false
)

// If an uploadItem of the same uploadableFile has been created before, we return that.
Expand Down
8 changes: 7 additions & 1 deletion app/src/main/java/fr/free/nrw/commons/utils/ImageUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ object ImageUtils {
const val EMPTY_CAPTION = -3
const val FILE_NAME_EXISTS = 1 shl 6 // 64
const val NO_CATEGORY_SELECTED = -5
const val IMAGE_FORMAT_UNSUPPORTED = 1 shl 7 // 128

private var progressDialogWallpaper: ProgressDialog? = null

Expand All @@ -90,7 +91,8 @@ object ImageUtils {
EMPTY_CAPTION,
FILE_NAME_EXISTS,
NO_CATEGORY_SELECTED,
IMAGE_GEOLOCATION_DIFFERENT
IMAGE_GEOLOCATION_DIFFERENT,
IMAGE_FORMAT_UNSUPPORTED
]
)
@Retention
Expand Down Expand Up @@ -349,6 +351,10 @@ object ImageUtils {
errorMessage.append("\n - ").
append(context.getString(R.string.upload_problem_image_duplicate))
}
if (result and IMAGE_FORMAT_UNSUPPORTED != 0) {
errorMessage.append("\n - ")
.append(context.getString(R.string.upload_problem_image_format_unsupported))
}
if (result and IMAGE_GEOLOCATION_DIFFERENT != 0) {
errorMessage.append("\n - ")
.append(context.getString(R.string.upload_problem_different_geolocation))
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@
<string name="upload_problem_image_dark">Image is too dark.</string>
<string name="upload_problem_image_blurry">Image is blurry.</string>
<string name="upload_problem_image_duplicate">Image is already on Commons.</string>
<string name="upload_problem_image_format_unsupported">The image type previously selected was not supported and has been converted to JPG.</string>
<string name="upload_problem_different_geolocation">This picture was taken at a different location.</string>
<string name="upload_problem_fbmd">Please only upload pictures that you have taken by yourself. Don\'t upload pictures that you have found on other people\'s Facebook accounts.</string>
<string name="upload_problem_do_you_continue">Do you still want to upload this picture?</string>
Expand Down
Loading