From 3e80a86726484be7fb9f1a4175951ce57600d8cd Mon Sep 17 00:00:00 2001 From: M66B Date: Fri, 26 Jul 2019 20:45:53 +0200 Subject: [PATCH] Use html image width/height --- .../eu/faircode/email/AdapterMessage.java | 3 +- .../java/eu/faircode/email/HtmlHelper.java | 127 ++++++++++++++---- 2 files changed, 106 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java index 0f1b8fcf1f..7d44975847 100644 --- a/app/src/main/java/eu/faircode/email/AdapterMessage.java +++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java @@ -2079,7 +2079,8 @@ public class AdapterMessage extends RecyclerView.Adapter 0 && image[0].getSource() != null) { - Uri uri = Uri.parse(image[0].getSource()); + HtmlHelper.AnnotatedSource a = new HtmlHelper.AnnotatedSource(image[0].getSource()); + Uri uri = Uri.parse(a.getSource()); if ("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) { onOpenLink(uri, null); return true; diff --git a/app/src/main/java/eu/faircode/email/HtmlHelper.java b/app/src/main/java/eu/faircode/email/HtmlHelper.java index b0e4b88037..9035f667c7 100644 --- a/app/src/main/java/eu/faircode/email/HtmlHelper.java +++ b/app/src/main/java/eu/faircode/email/HtmlHelper.java @@ -232,6 +232,29 @@ public class HtmlHelper { img.appendText(alt); } } + + // Annotate source with width and height + if (img.hasAttr("src")) { + try { + int width = 0; + int height = 0; + + String awidth = img.attr("width"); + String aheight = img.attr("height"); + if (!TextUtils.isEmpty(awidth)) + width = Integer.parseInt(awidth); + if (!TextUtils.isEmpty(aheight)) + height = Integer.parseInt(aheight); + + if (width != 0 || height != 0) { + String src = img.attr("src"); + AnnotatedSource a = new AnnotatedSource(src, width, height); + img.attr("src", a.getAnnotated()); + } + } catch (NumberFormatException ex) { + Log.w(ex); + } + } } // Autolink @@ -314,7 +337,7 @@ public class HtmlHelper { return (body == null ? "" : body.html()); } - static Drawable decodeImage(final Context context, final long id, final String source, boolean show, final TextView view) { + static Drawable decodeImage(final Context context, final long id, String source, boolean show, final TextView view) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); boolean compact = prefs.getBoolean("compact", false); int zoom = prefs.getInt("zoom", compact ? 0 : 1); @@ -325,23 +348,25 @@ public class HtmlHelper { final Resources.Theme theme = context.getTheme(); final Resources res = context.getResources(); - if (TextUtils.isEmpty(source)) { + final AnnotatedSource a = new AnnotatedSource(source); + + if (TextUtils.isEmpty(a.source)) { Drawable d = res.getDrawable(R.drawable.baseline_broken_image_24, theme); d.setBounds(0, 0, px, px); return d; } - boolean embedded = source.startsWith("cid:"); - boolean data = source.startsWith("data:"); + boolean embedded = a.source.startsWith("cid:"); + boolean data = a.source.startsWith("data:"); if (BuildConfig.DEBUG) Log.i("Image show=" + show + " inline=" + inline + - " embedded=" + embedded + " data=" + data + " source=" + source); + " embedded=" + embedded + " data=" + data + " source=" + a.source); // Embedded images if (embedded && (show || inline)) { DB db = DB.getInstance(context); - String cid = "<" + source.substring(4) + ">"; + String cid = "<" + a.source.substring(4) + ">"; EntityAttachment attachment = db.attachment().getAttachment(id, cid); if (attachment == null) { Log.i("Image not found CID=" + cid); @@ -366,7 +391,7 @@ public class HtmlHelper { DisplayMetrics dm = context.getResources().getDisplayMetrics(); d.setBounds(0, 0, Math.round(bm.getWidth() * dm.density), Math.round(bm.getHeight() * dm.density)); if (view != null) - fitDrawable(d, view); + fitDrawable(d, a, view); return d; } } @@ -375,9 +400,9 @@ public class HtmlHelper { // Data URI if (data && (show || inline)) try { - Drawable d = getDataDrawable(context, source); + Drawable d = getDataDrawable(context, a.source); if (view != null) - fitDrawable(d, view); + fitDrawable(d, a, view); return d; } catch (IllegalArgumentException ex) { Log.w(ex); @@ -398,7 +423,7 @@ public class HtmlHelper { File dir = new File(context.getCacheDir(), "images"); if (!dir.exists()) dir.mkdir(); - final File file = new File(dir, id + "_" + Math.abs(source.hashCode()) + ".png"); + final File file = new File(dir, id + "_" + Math.abs(a.source.hashCode()) + ".png"); Drawable cached = getCachedImage(context, file); if (cached != null || view == null) { @@ -410,7 +435,7 @@ public class HtmlHelper { } else return cached; else - fitDrawable(cached, view); + fitDrawable(cached, a, view); return cached; } @@ -426,21 +451,21 @@ public class HtmlHelper { try { Drawable cached = getCachedImage(context, file); if (cached != null) { - fitDrawable(cached, view); - post(cached, source); + fitDrawable(cached, a, view); + post(cached, a.source); return; } BitmapFactory.Options options = new BitmapFactory.Options(); - Log.i("Probe " + source); - try (InputStream probe = new URL(source).openStream()) { + Log.i("Probe " + a.source); + try (InputStream probe = new URL(a.source).openStream()) { options.inJustDecodeBounds = true; BitmapFactory.decodeStream(probe, null, options); } - Log.i("Download " + source); + Log.i("Download " + a.source); Bitmap bm; - try (InputStream is = new URL(source).openStream()) { + try (InputStream is = new URL(a.source).openStream()) { int scaleTo = res.getDisplayMetrics().widthPixels; int factor = 1; while (options.outWidth / factor > scaleTo) @@ -456,9 +481,9 @@ public class HtmlHelper { } if (bm == null) - throw new FileNotFoundException("Download image failed source=" + source); + throw new FileNotFoundException("Download image failed source=" + a.source); - Log.i("Downloaded image source=" + source); + Log.i("Downloaded image source=" + a.source); try (OutputStream os = new FileOutputStream(file)) { bm.compress(Bitmap.CompressFormat.PNG, 90, os); @@ -468,8 +493,8 @@ public class HtmlHelper { Drawable d = new BitmapDrawable(res, bm); DisplayMetrics dm = context.getResources().getDisplayMetrics(); d.setBounds(0, 0, Math.round(bm.getWidth() * dm.density), Math.round(bm.getHeight() * dm.density)); - fitDrawable(d, view); - post(d, source); + fitDrawable(d, a, view); + post(d, a.source); } catch (Throwable ex) { // Show broken icon Log.w(ex); @@ -478,7 +503,7 @@ public class HtmlHelper { : R.drawable.baseline_broken_image_24); Drawable d = res.getDrawable(resid, theme); d.setBounds(0, 0, px, px); - post(d, source); + post(d, a.source); } } @@ -503,11 +528,22 @@ public class HtmlHelper { return lld; } - private static void fitDrawable(Drawable d, View view) { + private static void fitDrawable(Drawable d, AnnotatedSource a, View view) { Rect bounds = d.getBounds(); int w = bounds.width(); int h = bounds.height(); + if (a.width == 0 && a.height != 0) + a.width = Math.round(a.height * w / (float) h); + if (a.height == 0 && a.width != 0) + a.height = Math.round(a.width * h / (float) w); + + if (a.width != 0 && a.height != 0) { + w = Helper.dp2pixels(view.getContext(), a.width); + h = Helper.dp2pixels(view.getContext(), a.height); + d.setBounds(0, 0, w, h); + } + float width = view.getWidth(); if (w > width) { float scale = width / w; @@ -723,4 +759,49 @@ public class HtmlHelper { return doc.outerHtml(); } + + public static class AnnotatedSource { + private String source; + private int width = 0; + private int height = 0; + + // Encapsulate some ugliness + + AnnotatedSource(String source) { + this.source = source; + + if (source != null && source.endsWith("###")) { + int pos = source.substring(0, source.length() - 3).lastIndexOf("###"); + if (pos > 0) { + int x = source.indexOf("x", pos + 3); + if (x > 0) + try { + this.width = Integer.parseInt(source.substring(pos + 3, x)); + this.height = Integer.parseInt(source.substring(x + 1, source.length() - 3)); + this.source = source.substring(0, pos); + } catch (NumberFormatException ex) { + Log.e(ex); + this.width = 0; + this.height = 0; + } + } + } + } + + private AnnotatedSource(String source, int width, int height) { + this.source = source; + this.width = width; + this.height = height; + } + + public String getSource() { + return this.source; + } + + private String getAnnotated() { + return (width == 0 && height == 0 + ? source + : source + "###" + width + "x" + height + "###"); + } + } }