From e10619ef737d3adc60e19bf5fb224dc4c0d54055 Mon Sep 17 00:00:00 2001 From: Robert Papp Date: Sat, 14 May 2016 20:30:54 +0200 Subject: [PATCH] bumptech/glide#556 Data Uri / Base64 from JSON --- .../github/_556_data_uri/TestFragment.java | 40 -------- .../FirebaseGlideModule.java | 4 +- .../FirebaseImage.java | 2 +- .../FirebaseModelLoader.java | 2 +- .../_556_data_uri_firebase/TestFragment.java | 23 +++++ .../Base64StreamDataFetcher.java | 36 +++++++ .../DataUriGlideModule.java | 18 ++++ .../DataUriModelLoader.java | 38 ++++++++ .../TestFragment.java | 24 +++++ .../github/_556_data_uri_via_POST/Image.java | 34 +++++++ .../ImageModelLoader.java | 26 +++++ .../JSONImageFetcher.java | 97 +++++++++++++++++++ .../RemoteImageGlideModule.java | 18 ++++ .../_556_data_uri_via_POST/TestFragment.java | 23 +++++ src/main/res/values/strings.xml | 3 + 15 files changed, 344 insertions(+), 44 deletions(-) delete mode 100644 src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri/TestFragment.java rename src/glide3/java/com/bumptech/glide/supportapp/github/{_556_data_uri => _556_data_uri_firebase}/FirebaseGlideModule.java (84%) rename src/glide3/java/com/bumptech/glide/supportapp/github/{_556_data_uri => _556_data_uri_firebase}/FirebaseImage.java (95%) rename src/glide3/java/com/bumptech/glide/supportapp/github/{_556_data_uri => _556_data_uri_firebase}/FirebaseModelLoader.java (97%) create mode 100644 src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_firebase/TestFragment.java create mode 100644 src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_from_string/Base64StreamDataFetcher.java create mode 100644 src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_from_string/DataUriGlideModule.java create mode 100644 src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_from_string/DataUriModelLoader.java create mode 100644 src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_from_string/TestFragment.java create mode 100644 src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/Image.java create mode 100644 src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/ImageModelLoader.java create mode 100644 src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/JSONImageFetcher.java create mode 100644 src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/RemoteImageGlideModule.java create mode 100644 src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/TestFragment.java diff --git a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri/TestFragment.java b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri/TestFragment.java deleted file mode 100644 index b4a18dc..0000000 --- a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri/TestFragment.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.bumptech.glide.supportapp.github._556_data_uri; - -import java.io.InputStream; - -import android.content.Context; -import android.os.AsyncTask; - -import com.bumptech.glide.Glide; -import com.bumptech.glide.load.engine.DiskCacheStrategy; -import com.bumptech.glide.supportapp.*; - -public class TestFragment extends GlideImageFragment { - @Override protected void load(final Context context) { - //noinspection unchecked - new AsyncTask() { - @Override protected Object doInBackground(Object[] params) { - Glide.get(context).clearDiskCache(); - return null; - } - @Override protected void onPostExecute(Object result) { - loadImage(context); - } - }.execute(); - } - - private void loadImage(Context context) { - //Glide.setup(new GlideBuilder(context).setBitmapPool(new BitmapPoolAdapter())); - Glide.get(context).register(FirebaseImage.class, InputStream.class, new FirebaseModelLoader.Factory(null)); - Glide - .with(context) - .load(new FirebaseImage( - "data:image/jpeg;base64,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")) - .placeholder(R.drawable.glide_placeholder) - .error(R.drawable.glide_error) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .skipMemoryCache(true) - .into(imageView); - } -} - diff --git a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri/FirebaseGlideModule.java b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_firebase/FirebaseGlideModule.java similarity index 84% rename from src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri/FirebaseGlideModule.java rename to src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_firebase/FirebaseGlideModule.java index 223ff1b..a2ccae7 100644 --- a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri/FirebaseGlideModule.java +++ b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_firebase/FirebaseGlideModule.java @@ -1,4 +1,4 @@ -package com.bumptech.glide.supportapp.github._556_data_uri; +package com.bumptech.glide.supportapp.github._556_data_uri_firebase; import java.io.InputStream; @@ -9,7 +9,7 @@ import com.firebase.client.Firebase; // TODO https://github.com/bumptech/glide/wiki/Configuration#creating-a-glidemodule -class FirebaseGlideModule implements GlideModule { +public class FirebaseGlideModule implements GlideModule { @Override public void applyOptions(Context context, GlideBuilder builder) { } diff --git a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri/FirebaseImage.java b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_firebase/FirebaseImage.java similarity index 95% rename from src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri/FirebaseImage.java rename to src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_firebase/FirebaseImage.java index 34409c6..c6d9fdf 100644 --- a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri/FirebaseImage.java +++ b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_firebase/FirebaseImage.java @@ -1,4 +1,4 @@ -package com.bumptech.glide.supportapp.github._556_data_uri; +package com.bumptech.glide.supportapp.github._556_data_uri_firebase; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicReference; diff --git a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri/FirebaseModelLoader.java b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_firebase/FirebaseModelLoader.java similarity index 97% rename from src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri/FirebaseModelLoader.java rename to src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_firebase/FirebaseModelLoader.java index 70c6a4f..6fdb9ab 100644 --- a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri/FirebaseModelLoader.java +++ b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_firebase/FirebaseModelLoader.java @@ -1,4 +1,4 @@ -package com.bumptech.glide.supportapp.github._556_data_uri; +package com.bumptech.glide.supportapp.github._556_data_uri_firebase; import java.io.*; diff --git a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_firebase/TestFragment.java b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_firebase/TestFragment.java new file mode 100644 index 0000000..63b92f7 --- /dev/null +++ b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_firebase/TestFragment.java @@ -0,0 +1,23 @@ +package com.bumptech.glide.supportapp.github._556_data_uri_firebase; + +import android.content.Context; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.supportapp.*; + +public class TestFragment extends GlideImageFragment { + @Override protected void load(Context context) { + //Glide.setup(new GlideBuilder(context).setBitmapPool(new BitmapPoolAdapter())); + //Glide.get(context).register(FirebaseImage.class, InputStream.class, new FirebaseModelLoader.Factory(null)); + Glide + .with(context) + .load(new FirebaseImage("data:image/jpeg;base64," + getString(R.string.glide_base64))) + .placeholder(R.drawable.glide_placeholder) + .error(R.drawable.glide_error) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .skipMemoryCache(true) + .into(imageView); + } +} + diff --git a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_from_string/Base64StreamDataFetcher.java b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_from_string/Base64StreamDataFetcher.java new file mode 100644 index 0000000..dd2ae38 --- /dev/null +++ b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_from_string/Base64StreamDataFetcher.java @@ -0,0 +1,36 @@ +package com.bumptech.glide.supportapp.github._556_data_uri_from_string; + +import java.io.*; + +import android.util.Base64; + +import com.bumptech.glide.Priority; +import com.bumptech.glide.load.data.DataFetcher; + +class Base64StreamDataFetcher implements DataFetcher { + private final String base64; + public Base64StreamDataFetcher(String base64) { + this.base64 = base64; + } + @Override public InputStream loadData(Priority priority) throws Exception { + // depending on how you encoded it, the below is just a guess: + // here the full base64 is decoded into bytes and the bytes will be parsed by Glide + // TODO match the flags based on your possible inputs: e.g. add | Base64.URL_SAFE + byte[] raw = Base64.decode(base64, Base64.NO_WRAP); + return new ByteArrayInputStream(raw); + // ---- alternative + // if you don't want to delay decoding you can use something like: + // Base64InputStream (http://stackoverflow.com/a/19981216/253468) + // here the base64 bytes are passed to Base64InputStream and that to Glide + // so base64 decoding will be done later when Glide reads from the stream. + //return new Base64InputStream(new ByteArrayInputStream(base64.getBytes("utf-8")), Base64.NO_WRAP | Base64.URL_SAFE); + } + @Override public String getId() { + // not well-cacheable, I suggest to use .diskCacheStrategy(NONE) + return base64; + } + @Override public void cancel() { + } + @Override public void cleanup() { + } +} diff --git a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_from_string/DataUriGlideModule.java b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_from_string/DataUriGlideModule.java new file mode 100644 index 0000000..0ac951d --- /dev/null +++ b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_from_string/DataUriGlideModule.java @@ -0,0 +1,18 @@ +package com.bumptech.glide.supportapp.github._556_data_uri_from_string; + +import java.io.InputStream; + +import android.content.Context; + +import com.bumptech.glide.*; +import com.bumptech.glide.module.GlideModule; + +// TODO https://github.com/bumptech/glide/wiki/Configuration#creating-a-glidemodule +public class DataUriGlideModule implements GlideModule { + @Override public void applyOptions(Context context, GlideBuilder builder) { + + } + @Override public void registerComponents(Context context, Glide glide) { + glide.register(String.class, InputStream.class, new DataUriModelLoader.Factory()); + } +} diff --git a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_from_string/DataUriModelLoader.java b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_from_string/DataUriModelLoader.java new file mode 100644 index 0000000..e81c112 --- /dev/null +++ b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_from_string/DataUriModelLoader.java @@ -0,0 +1,38 @@ +package com.bumptech.glide.supportapp.github._556_data_uri_from_string; + +import java.io.InputStream; + +import android.content.Context; + +import com.bumptech.glide.load.data.DataFetcher; +import com.bumptech.glide.load.model.*; +import com.bumptech.glide.load.model.stream.*; + +// TODO read https://github.com/bumptech/glide/wiki/Downloading-custom-sizes-with-Glide +class DataUriModelLoader implements StreamModelLoader { + private final ModelLoader defaultLoader; + public DataUriModelLoader(ModelLoader defaultLoader) { + this.defaultLoader = defaultLoader; + } + + private static final String PREFIX = "data:image/png;base64,"; + @Override public DataFetcher getResourceFetcher(final String model, int width, int height) { + if (model.startsWith(PREFIX)) { // TODO better matching based on your needs + return new Base64StreamDataFetcher(model.substring(PREFIX.length())); + } else { + return defaultLoader.getResourceFetcher(model, width, height); + } + } + + public static class Factory implements ModelLoaderFactory { + public Factory() { + } + @Override public ModelLoader build(Context context, GenericLoaderFactory factories) { + // StreamStringLoader is hardcoded, because we've already overwritten String -> InputStream loader + // This will be better handled in Glide v4. + return new DataUriModelLoader(new StreamStringLoader(context)); + } + @Override public void teardown() { + } + } +} diff --git a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_from_string/TestFragment.java b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_from_string/TestFragment.java new file mode 100644 index 0000000..e809ed8 --- /dev/null +++ b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_from_string/TestFragment.java @@ -0,0 +1,24 @@ +package com.bumptech.glide.supportapp.github._556_data_uri_from_string; + +import android.content.Context; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.resource.drawable.GlideDrawable; +import com.bumptech.glide.supportapp.*; +import com.bumptech.glide.supportapp.utils.LoggingListener; + +public class TestFragment extends GlideImageFragment { + @Override protected void load(final Context context) { + Glide + .with(context) + .load("data:image/png;base64," + getString(R.string.glide_base64)) + .placeholder(R.drawable.glide_placeholder) + .error(R.drawable.glide_error) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .skipMemoryCache(false) + .listener(new LoggingListener()) + .into(imageView); + } +} + diff --git a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/Image.java b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/Image.java new file mode 100644 index 0000000..d9ff737 --- /dev/null +++ b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/Image.java @@ -0,0 +1,34 @@ +package com.bumptech.glide.supportapp.github._556_data_uri_via_POST; + +import java.io.IOException; + +import org.json.*; + +public class Image { + private final String key; + public Image(String key) { + this.key = key; + } + + public String getKey() { + return key; + } + + public String getUri() throws IOException { + return "http://httpbin.org/post"; + } + + public JSONObject getPayload() throws IOException { + try { + JSONObject object = new JSONObject(); + object.put("imageKey", key); + return object; + } catch (JSONException e) { + throw new IOException("Invalid implementation", e); + } + } + + @Override public String toString() { + return "Image for key=" + key; + } +} diff --git a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/ImageModelLoader.java b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/ImageModelLoader.java new file mode 100644 index 0000000..041af3e --- /dev/null +++ b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/ImageModelLoader.java @@ -0,0 +1,26 @@ +package com.bumptech.glide.supportapp.github._556_data_uri_via_POST; + +import java.io.InputStream; + +import android.content.Context; + +import com.bumptech.glide.load.data.DataFetcher; +import com.bumptech.glide.load.model.*; +import com.bumptech.glide.load.model.stream.StreamModelLoader; + +// TODO read https://github.com/bumptech/glide/wiki/Downloading-custom-sizes-with-Glide +class ImageModelLoader implements StreamModelLoader { + @Override public DataFetcher getResourceFetcher(final Image model, int width, int height) { + return new JSONImageFetcher(model); + } + + public static class Factory implements ModelLoaderFactory { + public Factory() { + } + @Override public ModelLoader build(Context context, GenericLoaderFactory factories) { + return new ImageModelLoader(); + } + @Override public void teardown() { + } + } +} diff --git a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/JSONImageFetcher.java b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/JSONImageFetcher.java new file mode 100644 index 0000000..7afa0fc --- /dev/null +++ b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/JSONImageFetcher.java @@ -0,0 +1,97 @@ +package com.bumptech.glide.supportapp.github._556_data_uri_via_POST; + +import java.io.*; +import java.net.*; + +import javax.net.ssl.HttpsURLConnection; + +import org.json.*; + +import android.util.Base64; + +import com.bumptech.glide.Priority; +import com.bumptech.glide.load.data.DataFetcher; +import com.bumptech.glide.supportapp.*; + +class JSONImageFetcher implements DataFetcher { + private final Image model; + + public JSONImageFetcher(Image model) { + this.model = model; + } + + private HttpURLConnection conn; + private InputStream response; + + @Override public InputStream loadData(Priority priority) throws Exception { + // This implementation is totally up to you + // TODO produce an InputStream that contains the raw image bytes that can be decoded (below is just an example) + URL url = new URL(model.getUri()); + conn = (HttpURLConnection)url.openConnection(); + try { + conn.setReadTimeout(15000); + conn.setConnectTimeout(15000); + conn.setRequestMethod("POST"); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setRequestProperty("Content-Type", "application/json"); + + JSONObject payload = model.getPayload(); + // TODO remove this, only for testing with httpbin to have a proper response + payload.put("imageData", "data:image/png,base64," + App.getInstance().getString(R.string.glide_base64)); + OutputStream request = conn.getOutputStream(); + try { + request.write(payload.toString().getBytes("UTF-8")); + } finally { + request.close(); + } + int responseCode = conn.getResponseCode(); + if (responseCode == HttpsURLConnection.HTTP_OK) { + response = conn.getInputStream(); + try { + JSONObject object = readJSON(response); + // TODO remove this, only needed for testing with httpbin + object = new JSONObject(object.getString("data")); + String dataUri = object.getString("imageData"); + String base64 = dataUri.substring("data:image/png,base64,".length()); + byte[] raw = Base64.decode(base64, Base64.NO_WRAP); + return new ByteArrayInputStream(raw); + } finally { + response.close(); + } + } else { + throw new IOException("Invalid response: " + responseCode); + } + } finally { + conn.disconnect(); + } + } + + private JSONObject readJSON(InputStream stream) throws IOException, JSONException { + BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8")); + StringBuilder builder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + builder.append(line); + } + return new JSONObject(builder.toString()); + } + @Override public void cleanup() { + if (response != null) { + try { + response.close(); + } catch (IOException e) { + // Ignore + } + } + if (conn != null) { + conn.disconnect(); + } + } + @Override public String getId() { + return model.getKey(); + } + @Override public void cancel() { + + } +} diff --git a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/RemoteImageGlideModule.java b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/RemoteImageGlideModule.java new file mode 100644 index 0000000..75972c9 --- /dev/null +++ b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/RemoteImageGlideModule.java @@ -0,0 +1,18 @@ +package com.bumptech.glide.supportapp.github._556_data_uri_via_POST; + +import java.io.InputStream; + +import android.content.Context; + +import com.bumptech.glide.*; +import com.bumptech.glide.module.GlideModule; + +// TODO https://github.com/bumptech/glide/wiki/Configuration#creating-a-glidemodule +public class RemoteImageGlideModule implements GlideModule { + @Override public void applyOptions(Context context, GlideBuilder builder) { + + } + @Override public void registerComponents(Context context, Glide glide) { + glide.register(Image.class, InputStream.class, new ImageModelLoader.Factory()); + } +} diff --git a/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/TestFragment.java b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/TestFragment.java new file mode 100644 index 0000000..cfdd8f9 --- /dev/null +++ b/src/glide3/java/com/bumptech/glide/supportapp/github/_556_data_uri_via_POST/TestFragment.java @@ -0,0 +1,23 @@ +package com.bumptech.glide.supportapp.github._556_data_uri_via_POST; + +import android.content.Context; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.resource.drawable.GlideDrawable; +import com.bumptech.glide.supportapp.*; +import com.bumptech.glide.supportapp.utils.LoggingListener; + +public class TestFragment extends GlideImageFragment { + @Override protected void load(final Context context) { + Glide + .with(context) + .load(new Image("identifier_referencing_an_image")) + .placeholder(R.drawable.glide_placeholder) + .error(R.drawable.glide_error) + //.diskCacheStrategy(DiskCacheStrategy.NONE) + //.skipMemoryCache(true) + .listener(new LoggingListener()) + .into(imageView); + } +} + diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 89e2d2b..33c7159 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -4,4 +4,7 @@ Glide Support Glide Quick + + + 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