From f9133474552f200149f47dab7b8337c891e48fb4 Mon Sep 17 00:00:00 2001 From: M66B Date: Sat, 14 Oct 2023 13:47:57 +0200 Subject: [PATCH] Added PDF previews --- .../java/eu/faircode/email/AdapterImage.java | 85 ++++++++++++------- .../eu/faircode/email/AdapterMessage.java | 5 +- .../eu/faircode/email/EntityAttachment.java | 4 + 3 files changed, 61 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/eu/faircode/email/AdapterImage.java b/app/src/main/java/eu/faircode/email/AdapterImage.java index f0ef844e3f..96842c7099 100644 --- a/app/src/main/java/eu/faircode/email/AdapterImage.java +++ b/app/src/main/java/eu/faircode/email/AdapterImage.java @@ -23,11 +23,15 @@ import android.content.Context; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.drawable.AnimatedImageDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.graphics.pdf.PdfRenderer; import android.os.Build; import android.os.Bundle; +import android.os.ParcelFileDescriptor; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; @@ -60,6 +64,8 @@ public class AdapterImage extends RecyclerView.Adapter private List items = new ArrayList<>(); + private static final int PDF_WIDTH = 120; + public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { private View view; private ImageView ivImage; @@ -108,45 +114,62 @@ public class AdapterImage extends RecyclerView.Adapter String type = args.getString("type"); int max = args.getInt("max"); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - boolean webp = prefs.getBoolean("webp", true); - - if ("image/webp".equalsIgnoreCase(type) && !webp) { - args.putBoolean("nowebp", true); - return null; - } + if ("application/pdf".equals(type)) { + // https://medium.com/@aditya09tyagi/android-pdf-reader-using-pdfrenderer-6daa2dacec1a + try (ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY)) { + try (PdfRenderer pdf = new PdfRenderer(pfd)) { + try (PdfRenderer.Page page = pdf.openPage(0)) { + int width = Helper.dp2pixels(context, PDF_WIDTH); + int height = (int) ((float) width / page.getWidth() * page.getHeight()); + Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bm); + canvas.drawColor(Color.WHITE); + page.render(bm, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY); + return new BitmapDrawable(context.getResources(), bm); + } + } + } + } else { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + boolean webp = prefs.getBoolean("webp", true); - args.putLong("size", file.length()); - - try { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - BitmapFactory.decodeFile(file.getAbsolutePath(), options); - args.putInt("width", options.outWidth); - args.putInt("height", options.outHeight); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - if (options.outColorSpace != null) - args.putString("color", options.outColorSpace.getModel().name()); - if (options.outConfig != null) - args.putString("config", options.outConfig.name()); + if ("image/webp".equalsIgnoreCase(type) && !webp) { + args.putBoolean("nowebp", true); + return null; } - } catch (Throwable ex) { - Log.w(ex); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && - !"image/svg+xml".equals(type) && - !"svg".equals(Helper.getExtension(file.getName()))) + args.putLong("size", file.length()); + try { - return ImageHelper.getScaledDrawable(context, file, type, max); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(file.getAbsolutePath(), options); + args.putInt("width", options.outWidth); + args.putInt("height", options.outHeight); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (options.outColorSpace != null) + args.putString("color", options.outColorSpace.getModel().name()); + if (options.outConfig != null) + args.putString("config", options.outConfig.name()); + } } catch (Throwable ex) { Log.w(ex); } - Bitmap bm = ImageHelper.decodeImage(file, type, max); - if (bm == null) - return null; - return new BitmapDrawable(context.getResources(), bm); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && + !"image/svg+xml".equals(type) && + !"svg".equals(Helper.getExtension(file.getName()))) + try { + return ImageHelper.getScaledDrawable(context, file, type, max); + } catch (Throwable ex) { + Log.w(ex); + } + + Bitmap bm = ImageHelper.decodeImage(file, type, max); + if (bm == null) + return null; + return new BitmapDrawable(context.getResources(), bm); + } } @Override diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java index a2d8aba2b0..0fadd9164b 100644 --- a/app/src/main/java/eu/faircode/email/AdapterMessage.java +++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java @@ -3650,9 +3650,10 @@ public class AdapterMessage extends RecyclerView.Adapter images = new ArrayList<>(); if (thumbnails && bind_extras) { for (EntityAttachment attachment : attachments) - if (attachment.isAttachment() && attachment.isImage()) { + if (attachment.isPDF() || + (attachment.isAttachment() && attachment.isImage())) { images.add(attachment); - if (attachment.available) + if (attachment.available && !attachment.isPDF()) iavailable++; } } diff --git a/app/src/main/java/eu/faircode/email/EntityAttachment.java b/app/src/main/java/eu/faircode/email/EntityAttachment.java index 9d9e0d4458..3ab1c529cf 100644 --- a/app/src/main/java/eu/faircode/email/EntityAttachment.java +++ b/app/src/main/java/eu/faircode/email/EntityAttachment.java @@ -117,6 +117,10 @@ public class EntityAttachment { return ImageHelper.isImage(getMimeType()); } + boolean isPDF() { + return "application/pdf".equals(getMimeType()); + } + boolean isCompressed() { if ("application/zip".equals(type)) return true;