aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Tardieu <sam@rfc1149.net>2014-04-10 07:58:32 +0200
committerSamuel Tardieu <sam@rfc1149.net>2014-04-10 09:00:35 +0200
commit2a97bbd1ea9db1975364b6ee96e527b2c9c8bae7 (patch)
tree1fd6ca8799721c220c1efa7aa2ce00aaefd2b3c5
parent95a5e7e4884b93703ddd42cd02a23a626b482449 (diff)
downloadcgeo-2a97bbd1ea9db1975364b6ee96e527b2c9c8bae7.zip
cgeo-2a97bbd1ea9db1975364b6ee96e527b2c9c8bae7.tar.gz
cgeo-2a97bbd1ea9db1975364b6ee96e527b2c9c8bae7.tar.bz2
Use the Android-provided API to stream-decode base64-encoded data
-rw-r--r--main/src/cgeo/geocaching/network/HtmlImage.java23
-rw-r--r--main/src/cgeo/geocaching/utils/ImageUtils.java39
-rw-r--r--tests/res/raw/small_file.binbin0 -> 409 bytes
-rw-r--r--tests/src/cgeo/geocaching/ImageUtilsTest.java30
4 files changed, 72 insertions, 20 deletions
diff --git a/main/src/cgeo/geocaching/network/HtmlImage.java b/main/src/cgeo/geocaching/network/HtmlImage.java
index bde85ee..8ee2ba7 100644
--- a/main/src/cgeo/geocaching/network/HtmlImage.java
+++ b/main/src/cgeo/geocaching/network/HtmlImage.java
@@ -13,7 +13,6 @@ import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.RxUtils;
import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.androidextra.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
@@ -43,9 +42,6 @@ import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
import java.util.Date;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
@@ -172,14 +168,15 @@ public class HtmlImage implements Html.ImageGetter {
return new ImmutablePair<BitmapDrawable, Boolean>(bitmap != null ?
ImageUtils.scaleBitmapToFitDisplay(bitmap) :
null,
- loadResult.getRight());
+ loadResult.getRight()
+ );
}
private void downloadAndSave(final Subscriber<? super BitmapDrawable> subscriber) {
final File file = LocalStorage.getStorageFile(pseudoGeocode, url, true, true);
if (url.startsWith("data:image/")) {
if (url.contains(";base64,")) {
- saveBase64ToFile(url, file);
+ ImageUtils.decodeBase64ToFile(StringUtils.substringAfter(url, ";base64,"), file);
} else {
Log.e("HtmlImage.getDrawable: unable to decode non-base64 inline image");
subscriber.onCompleted();
@@ -254,20 +251,6 @@ public class HtmlImage implements Html.ImageGetter {
return false;
}
- private static void saveBase64ToFile(final String url, final File file) {
- // TODO: when we use SDK level 8 or above, we can use the streaming version of the base64
- // Android utilities.
- OutputStream out = null;
- try {
- out = new FileOutputStream(file);
- out.write(Base64.decode(StringUtils.substringAfter(url, ";base64,"), Base64.DEFAULT));
- } catch (final IOException e) {
- Log.e("HtmlImage.saveBase64ToFile: cannot write file for decoded inline image", e);
- } finally {
- IOUtils.closeQuietly(out);
- }
- }
-
/**
* Make a fresh copy of the file to reset its timestamp. On some storage, it is impossible
* to modify the modified time after the fact, in which case a brand new file must be
diff --git a/main/src/cgeo/geocaching/utils/ImageUtils.java b/main/src/cgeo/geocaching/utils/ImageUtils.java
index aae0f14..6d7a437 100644
--- a/main/src/cgeo/geocaching/utils/ImageUtils.java
+++ b/main/src/cgeo/geocaching/utils/ImageUtils.java
@@ -3,6 +3,7 @@ package cgeo.geocaching.utils;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.compatibility.Compatibility;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
@@ -16,11 +17,15 @@ import android.graphics.drawable.BitmapDrawable;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Environment;
+import android.util.Base64;
+import android.util.Base64InputStream;
import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
@@ -245,4 +250,38 @@ public final class ImageUtils {
}
return false;
}
+
+ /**
+ * Decode a base64-encoded string and save the result into a file.
+ *
+ * @param inString the encoded string
+ * @param outFile the file to save the decoded result into
+ */
+ public static void decodeBase64ToFile(final String inString, final File outFile) {
+ FileOutputStream out = null;
+ try {
+ out = new FileOutputStream(outFile);
+ decodeBase64ToStream(inString, out);
+ } catch (final IOException e) {
+ Log.e("HtmlImage.decodeBase64ToFile: cannot write file for decoded inline image", e);
+ } finally {
+ IOUtils.closeQuietly(out);
+ }
+ }
+
+ /**
+ * Decode a base64-encoded string and save the result into a stream.
+ *
+ * @param inString the encoded string
+ * @param outFile the file to save the decoded result into
+ */
+ public static void decodeBase64ToStream(final String inString, final OutputStream out) throws IOException {
+ Base64InputStream in = null;
+ try {
+ in = new Base64InputStream(new ByteArrayInputStream(inString.getBytes()), Base64.DEFAULT);
+ IOUtils.copy(in, out);
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ }
}
diff --git a/tests/res/raw/small_file.bin b/tests/res/raw/small_file.bin
new file mode 100644
index 0000000..df5b053
--- /dev/null
+++ b/tests/res/raw/small_file.bin
Binary files differ
diff --git a/tests/src/cgeo/geocaching/ImageUtilsTest.java b/tests/src/cgeo/geocaching/ImageUtilsTest.java
new file mode 100644
index 0000000..c67d340
--- /dev/null
+++ b/tests/src/cgeo/geocaching/ImageUtilsTest.java
@@ -0,0 +1,30 @@
+package cgeo.geocaching;
+
+import cgeo.geocaching.test.AbstractResourceInstrumentationTestCase;
+import cgeo.geocaching.test.R;
+import cgeo.geocaching.utils.ImageUtils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+public class ImageUtilsTest extends AbstractResourceInstrumentationTestCase {
+
+ private static final String icon64 = "iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAABAElEQVQY002NvUpDQRQG52yEILn+IAYCClaS4tqKtZ1dbHwNuaS00dYmQmrfwMZGRBAtrMQHSCMpTCMqaIx6k909e6wCme4bPhhhhuc8d8PxeC+ZPW33++9T72ZPvdFow1SvStX9We8sz2U6FlQPLUYqqkW30VgGsKJAbur1g5pzXYMosC5giEgy+6hAtUzpqLLq3O8q7M6bbZkqmpKllExUa9+q2gvhbJrKLrLsdkVkxwABShg9eN86nUzunXU6AD/O+2EMgdJ7fAiY92EtxjcAJ+02JyKNkNLmawj9xxiLlxAu/2JcWoQmwBxAFT4Hqq1rs687GADnx9DMnOsD/AMJ54Nj8e9zcgAAAABJRU5ErkJggg==";
+
+ public void testBase64decoding() throws IOException {
+ final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ ImageUtils.decodeBase64ToStream(icon64, outputStream);
+ final byte[] decodedImage = outputStream.toByteArray();
+ outputStream.close();
+ assertEquals("decoded image has the right size", 409, decodedImage.length);
+ final InputStream originalStream = getResourceStream(R.raw.small_file);
+ final byte[] originalImage = new byte[409];
+ assertEquals("original image has the right size (consistency check)", 409, originalStream.read(originalImage));
+ originalStream.close();
+ assertTrue("decoded base64 image is similar to original file data",
+ Arrays.equals(originalImage, decodedImage));
+ }
+
+}