aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/utils/ImageUtils.java
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/cgeo/geocaching/utils/ImageUtils.java')
-rw-r--r--main/src/cgeo/geocaching/utils/ImageUtils.java109
1 files changed, 95 insertions, 14 deletions
diff --git a/main/src/cgeo/geocaching/utils/ImageUtils.java b/main/src/cgeo/geocaching/utils/ImageUtils.java
index 739ecc4..c2b7327 100644
--- a/main/src/cgeo/geocaching/utils/ImageUtils.java
+++ b/main/src/cgeo/geocaching/utils/ImageUtils.java
@@ -1,6 +1,7 @@
package cgeo.geocaching.utils;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.Image;
import cgeo.geocaching.R;
import cgeo.geocaching.compatibility.Compatibility;
@@ -25,6 +26,8 @@ import android.graphics.drawable.Drawable;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Environment;
+import android.text.Html;
+import android.text.Html.ImageGetter;
import android.util.Base64;
import android.util.Base64InputStream;
import android.widget.TextView;
@@ -36,8 +39,11 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
+import java.util.Collection;
import java.util.Date;
+import java.util.LinkedHashSet;
import java.util.Locale;
+import java.util.Set;
public final class ImageUtils {
private static final int[] ORIENTATIONS = new int[] {
@@ -49,6 +55,10 @@ public final class ImageUtils {
private static final int[] ROTATION = new int[] { 90, 180, 270 };
private static final int MAX_DISPLAY_IMAGE_XY = 800;
+ // Images whose URL contains one of those patterns will not be available on the Images tab
+ // for opening into an external application.
+ private final static String[] NO_EXTERNAL = new String[] { "geocheck.org" };
+
private ImageUtils() {
// Do not let this class be instantiated, this is a utility class.
}
@@ -61,7 +71,7 @@ public final class ImageUtils {
* @return BitmapDrawable The scaled image
*/
public static BitmapDrawable scaleBitmapToFitDisplay(@NonNull final Bitmap image) {
- Point displaySize = Compatibility.getDisplaySize();
+ final Point displaySize = Compatibility.getDisplaySize();
final int maxWidth = displaySize.x - 25;
final int maxHeight = displaySize.y - 25;
return scaleBitmapTo(image, maxWidth, maxHeight);
@@ -76,7 +86,7 @@ public final class ImageUtils {
*/
@Nullable
public static Bitmap readAndScaleImageToFitDisplay(@NonNull final String filename) {
- Point displaySize = Compatibility.getDisplaySize();
+ final Point displaySize = Compatibility.getDisplaySize();
// Restrict image size to 800 x 800 to prevent OOM on tablets
final int maxWidth = Math.min(displaySize.x - 25, MAX_DISPLAY_IMAGE_XY);
final int maxHeight = Math.min(displaySize.y - 25, MAX_DISPLAY_IMAGE_XY);
@@ -128,12 +138,12 @@ public final class ImageUtils {
*/
public static void storeBitmap(final Bitmap bitmap, final Bitmap.CompressFormat format, final int quality, final String pathOfOutputImage) {
try {
- FileOutputStream out = new FileOutputStream(pathOfOutputImage);
- BufferedOutputStream bos = new BufferedOutputStream(out);
+ final FileOutputStream out = new FileOutputStream(pathOfOutputImage);
+ final BufferedOutputStream bos = new BufferedOutputStream(out);
bitmap.compress(format, quality, bos);
bos.flush();
bos.close();
- } catch (IOException e) {
+ } catch (final IOException e) {
Log.e("ImageHelper.storeBitmap", e);
}
}
@@ -152,7 +162,7 @@ public final class ImageUtils {
if (maxXY <= 0) {
return filePath;
}
- Bitmap image = readDownsampledImage(filePath, maxXY, maxXY);
+ final Bitmap image = readDownsampledImage(filePath, maxXY, maxXY);
if (image == null) {
return null;
}
@@ -184,7 +194,7 @@ public final class ImageUtils {
try {
final ExifInterface exif = new ExifInterface(filePath);
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
- } catch (IOException e) {
+ } catch (final IOException e) {
Log.e("ImageUtils.readDownsampledImage", e);
}
final BitmapFactory.Options sizeOnlyOptions = new BitmapFactory.Options();
@@ -233,7 +243,7 @@ public final class ImageUtils {
}
// Create a media file name
- String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
+ final String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
return new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
}
@@ -254,7 +264,7 @@ public final class ImageUtils {
* @return <tt>true</tt> if the URL contains at least one of the patterns, <tt>false</tt> otherwise
*/
public static boolean containsPattern(final String url, final String[] patterns) {
- for (String entry : patterns) {
+ for (final String entry : patterns) {
if (StringUtils.containsIgnoreCase(url, entry)) {
return true;
}
@@ -282,7 +292,7 @@ public final class ImageUtils {
/**
* Decode a base64-encoded string and save the result into a stream.
- *
+ *
* @param inString
* the encoded string
* @param out
@@ -303,15 +313,39 @@ public final class ImageUtils {
}
/**
+ * Add images present in the HTML description to the existing collection.
+ *
+ * @param images a collection of images
+ * @param htmlText the HTML description to be parsed
+ * @param geocode the common title for images in the description
+ */
+ public static void addImagesFromHtml(final Collection<Image> images, final String htmlText, final String geocode) {
+ final Set<String> urls = new LinkedHashSet<>();
+ for (final Image image : images) {
+ urls.add(image.getUrl());
+ }
+ Html.fromHtml(StringUtils.defaultString(htmlText), new ImageGetter() {
+ @Override
+ public Drawable getDrawable(final String source) {
+ if (!urls.contains(source) && canBeOpenedExternally(source)) {
+ images.add(new Image(source, StringUtils.defaultString(geocode)));
+ urls.add(source);
+ }
+ return null;
+ }
+ }, null);
+ }
+
+ /**
* Container which can hold a drawable (initially an empty one) and get a newer version when it
* becomes available. It also invalidates the view the container belongs to, so that it is
* redrawn properly.
*/
- @SuppressWarnings("deprecation")
- public final static class ContainerDrawable extends BitmapDrawable implements Action1<Drawable> {
+ public static class ContainerDrawable extends BitmapDrawable implements Action1<Drawable> {
private Drawable drawable;
final private TextView view;
+ @SuppressWarnings("deprecation")
public ContainerDrawable(@NonNull final TextView view) {
this.view = view;
drawable = null;
@@ -324,7 +358,7 @@ public final class ImageUtils {
}
@Override
- public void draw(final Canvas canvas) {
+ public final void draw(final Canvas canvas) {
if (drawable != null) {
drawable.draw(canvas);
}
@@ -337,8 +371,55 @@ public final class ImageUtils {
view.setText(view.getText());
}
- public void updateFrom(final Observable<? extends Drawable> drawableObservable) {
+ public final void updateFrom(final Observable<? extends Drawable> drawableObservable) {
drawableObservable.observeOn(AndroidSchedulers.mainThread()).subscribe(this);
}
}
+
+ /**
+ * Image that automatically scales to fit a line of text in the containing {@link TextView}.
+ */
+ public final static class LineHeightContainerDrawable extends ContainerDrawable {
+ private final TextView view;
+
+ public LineHeightContainerDrawable(@NonNull final TextView view, final Observable<? extends Drawable> drawableObservable) {
+ super(view, drawableObservable);
+ this.view = view;
+ }
+
+ @Override
+ public void call(final Drawable newDrawable) {
+ super.call(newDrawable);
+ setBounds(ImageUtils.scaleImageToLineHeight(newDrawable, view));
+ }
+ }
+
+ public static boolean canBeOpenedExternally(final String source) {
+ return !containsPattern(source, NO_EXTERNAL);
+ }
+
+ public static Rect scaleImageToLineHeight(final Drawable drawable, final TextView view) {
+ final int lineHeight = (int) (view.getLineHeight() * 0.8);
+ final int width = drawable.getIntrinsicWidth() * lineHeight / drawable.getIntrinsicHeight();
+ return new Rect(0, 0, width, lineHeight);
+ }
+
+ public static Bitmap convertToBitmap(final Drawable drawable) {
+ if (drawable instanceof BitmapDrawable) {
+ return ((BitmapDrawable) drawable).getBitmap();
+ }
+
+ // handle solid colors, which have no width
+ int width = drawable.getIntrinsicWidth();
+ width = width > 0 ? width : 1;
+ int height = drawable.getIntrinsicHeight();
+ height = height > 0 ? height : 1;
+
+ final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+
+ return bitmap;
+ }
}