From 8d7efff5c4eaaaa18fab527229228507ceb305bb Mon Sep 17 00:00:00 2001 From: M66B Date: Tue, 11 Nov 2025 08:41:25 +0100 Subject: [PATCH] Allow resizing HEIF --- app/build.gradle | 4 ++ app/src/main/AndroidManifest.xml | 2 + .../eu/faircode/email/FragmentCompose.java | 67 +++++++++++++------ 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index d274cb9e49..16d4d486f8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -609,6 +609,7 @@ dependencies { def zxing_version = "3.5.3" def evalex_version = "3.4.0" def image_cropper_version = "4.6.0" + def heifwriter_version = "1.1.0" // https://mvnrepository.com/artifact/com.android.tools/desugar_jdk_libs?repo=google coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:$desugar_version" @@ -889,4 +890,7 @@ dependencies { // https://github.com/CanHub/Android-Image-Cropper // https://mvnrepository.com/artifact/com.vanniktech/android-image-cropper implementation "com.vanniktech:android-image-cropper:$image_cropper_version" + + // https://developer.android.com/jetpack/androidx/releases/heifwriter + implementation "androidx.heifwriter:heifwriter:$heifwriter_version" } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5f68e5b4a2..3494350a74 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -45,6 +45,8 @@ android:required="false" /> + + diff --git a/app/src/main/java/eu/faircode/email/FragmentCompose.java b/app/src/main/java/eu/faircode/email/FragmentCompose.java index 5849c013f0..b3fcdf48e4 100644 --- a/app/src/main/java/eu/faircode/email/FragmentCompose.java +++ b/app/src/main/java/eu/faircode/email/FragmentCompose.java @@ -135,6 +135,7 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; +import androidx.heifwriter.HeifWriter; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.Observer; @@ -5662,7 +5663,10 @@ public class FragmentCompose extends FragmentBase { if (!"image/jpg".equals(attachment.type) && !"image/jpeg".equals(attachment.type) && !"image/png".equals(attachment.type) && - !"image/webp".equals(attachment.type)) { + !"image/webp".equals(attachment.type) && + !(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && + ("image/heic".equals(attachment.type) || + "image/heif".equals(attachment.type)))) { Log.i("Skipping resize of type=" + attachment.type); return; } @@ -5685,7 +5689,7 @@ public class FragmentCompose extends FragmentBase { factor *= 2; Matrix rotation = ("image/jpeg".equals(attachment.type) ? ImageHelper.getImageRotation(file) : null); - Log.i("Image type=" + attachment.type + " rotation=" + rotation); + Log.i("Image type=" + attachment.type + " factor=" + factor + " rotation=" + rotation); if (factor > 1 || rotation != null) { options.inJustDecodeBounds = false; options.inSampleSize = factor; @@ -5701,26 +5705,47 @@ public class FragmentCompose extends FragmentBase { resized = rotated; } - Bitmap.CompressFormat format; - if ("image/jpg".equals(attachment.type) || - "image/jpeg".equals(attachment.type)) - format = Bitmap.CompressFormat.JPEG; - else if ("image/png".equals(attachment.type)) - format = Bitmap.CompressFormat.PNG; - else if ("image/webp".equals(attachment.type)) - format = Bitmap.CompressFormat.WEBP; - else - throw new IllegalArgumentException("Invalid format type=" + attachment.type); - File tmp = new File(file.getAbsolutePath() + ".tmp"); - try (OutputStream out = new BufferedOutputStream(new FileOutputStream(tmp))) { - if (!resized.compress(format, ImageHelper.DEFAULT_PNG_COMPRESSION, out)) - throw new IOException("compress"); - } catch (Throwable ex) { - Log.w(ex); - Helper.secureDelete(tmp); - } finally { - resized.recycle(); + + if ("image/heic".equals(attachment.type) || + "image/heif".equals(attachment.type)) { + // https://developer.android.com/reference/androidx/heifwriter/HeifWriter + Log.i("Image heif writer"); + try (HeifWriter writer = new HeifWriter.Builder(tmp.getAbsolutePath(), + resized.getWidth(), resized.getHeight(), HeifWriter.INPUT_MODE_BITMAP) + .setMaxImages(1) + .build()) { + writer.start(); + writer.addBitmap(resized); + writer.stop(5000L); + Log.i("Image heif writer done"); + } catch (Throwable ex) { + Log.w(ex); + Helper.secureDelete(tmp); + } finally { + resized.recycle(); + } + } else { + Bitmap.CompressFormat format; + if ("image/jpg".equals(attachment.type) || + "image/jpeg".equals(attachment.type)) + format = Bitmap.CompressFormat.JPEG; + else if ("image/png".equals(attachment.type)) + format = Bitmap.CompressFormat.PNG; + else if ("image/webp".equals(attachment.type)) + format = Bitmap.CompressFormat.WEBP; + else + throw new IllegalArgumentException("Invalid format type=" + attachment.type); + + try (OutputStream out = new BufferedOutputStream(new FileOutputStream(tmp))) { + if (!resized.compress(format, ImageHelper.DEFAULT_PNG_COMPRESSION, out)) + throw new IOException("compress"); + } catch (Throwable ex) { + Log.w(ex); + Helper.secureDelete(tmp); + } finally { + resized.recycle(); + } } if (tmp.exists() && tmp.length() > 0) {