Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TIMOB-24528] Android: Fixed issue where images (such as camera photos) will fail to load if too big to be shown by the GPU. Now auto-downscales to fit. #8951

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public void processProperties(KrollDict d)
}

if (drawableRef != null) {
Drawable image = drawableRef.getDensityScaledDrawable();
Drawable image = drawableRef.getDrawable();
btn.setCompoundDrawablesWithIntrinsicBounds(image, null, null, null);
}
} else if (d.containsKey(TiC.PROPERTY_BACKGROUND_COLOR)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewParent;

Expand Down Expand Up @@ -261,10 +262,20 @@ private void setImage(final Bitmap bitmap)

private void handleSetImage(final Bitmap bitmap)
{
// Fetch the image view.
TiImageView view = getView();
if (view != null) {
view.setImageBitmap(bitmap);
if (view == null) {
return;
}

// Clear the DPI/density setting from the bitmap.
// This makes the view display the bitmap pixel perfect, without density scaling.
if (bitmap != null) {
bitmap.setDensity(Bitmap.DENSITY_NONE);
}

// Show the given bitmap in the view.
view.setImageBitmap(bitmap);
}

private class BitmapWithIndex
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.appcelerator.kroll.common.Log;
import org.appcelerator.kroll.common.TiMessenger;
import org.appcelerator.titanium.TiApplication;
import org.appcelerator.titanium.view.TiDrawableReference;

import android.content.Context;
import android.content.res.AssetManager;
Expand Down Expand Up @@ -307,65 +308,60 @@ public Drawable loadDrawable(String path, boolean report, boolean checkForNinePa
*/
public Drawable loadDrawable(String path, boolean report, boolean checkForNinePatch, boolean densityScaled)
{
Drawable d = null;
InputStream is = null;

// Try to get Resource drawable first.
d = TiUIHelper.getResourceDrawable(path);
if (d != null) {
return d;
// Validate.
if ((path == null) || (path.length() <= 0)) {
return null;
}

try
{
if (checkForNinePatch && path != null && !URLUtil.isNetworkUrl(path)) {
// Create a new drawable wrapping the given image.
Drawable d = null;
try {
// Determine if we need to process the referenced image as a 9-patch.
// Note: Titanium does not require the ".9.png" suffix on an image file.
boolean isNinePatchProcessingRequested = false;
if (checkForNinePatch && !URLUtil.isNetworkUrl(path)) {
if (path.endsWith(".png")) {
if (!path.endsWith(".9.png")) {
String apath = null;
// First See if it's in the root dir
apath = path.substring(0, path.lastIndexOf(".")) + ".9.png";
// If the given file path does not end with ".9.png",
// then append it and check if a matching file exists.
String apath = path.substring(0, path.lastIndexOf(".")) + ".9.png";
InputStream is = null;
try {
is = openInputStream(apath, false);
if (is != null) {
path = apath;
}
} catch (IOException e) {
Log.d(TAG, "path not found: " + apath);
Log.d(TAG, "path not found: " + apath);
}
finally {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, try to keep consistent with the formatting used in the source file:

...
} finally {
    if (is != null) {
        try {
            is.close();
        } catch (Exception ex) {
        }
    }
...

There are other instances, but I'll just comment here.

if (is != null) {
try { is.close(); }
catch (Exception ex) {}
}
}
}
}
if (is == null) {
is = openInputStream(path, report);
}
Bitmap b = null;
if (densityScaled) {
b = TiUIHelper.createDensityScaledBitmap(is);
} else {
b = TiUIHelper.createBitmap(is);
}
d = nph.process(b);
} else {
is = openInputStream(path, report);
Bitmap b = null;
isNinePatchProcessingRequested = true;
}

// Load the image via "TiDrawableReference" which will auto-downscale the image
// if is too large to be displayed by an Android view. (Can happen with large camera photos.)
TiDrawableReference drawableLoader = TiDrawableReference.fromUrl(
TiApplication.getInstance().getCurrentActivity(), path);
if (drawableLoader != null) {
if (densityScaled) {
b = TiUIHelper.createDensityScaledBitmap(is);
} else {
b = TiUIHelper.createBitmap(is);
d = drawableLoader.getDensityScaledDrawable();
}
if (b != null) {
d = new BitmapDrawable(b);
else {
d = drawableLoader.getDrawable();
}
}
} catch (IOException e) {
Log.e(TAG, path + " not found.", e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
//Ignore
if (isNinePatchProcessingRequested && (d != null)) {
d = this.nph.process(d);
}
}
} catch (Exception e) {
Log.e(TAG, "Failed to load drawable for path: " + path, e);
}

return d;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@

import java.util.ArrayList;

import org.appcelerator.titanium.TiApplication;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.NinePatch;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
Expand All @@ -24,32 +28,72 @@ class SegmentColor {
int color;
};

/**
* Analyzes the given drawable's bitmap (if it has one) to see if it is a 9-patch image.
* If it is, then this method creates and returns a new NinePatchDrawable with the given drawable's bitmap.
* @param d The drawable whose bitmap will be checked for 9-patch information. Can be null.
* @return
* Returns a new NinePatchDrawable using the given drawable's bitmap if that bitmap is a 9-patch image.
* <p>
* Returns the given drawable reference if it cannot be displayed as a 9-patch.
* <p>
* Returns null if given a null argument.
*/
public Drawable process(Drawable d) {
Drawable nd = d;

if (d instanceof BitmapDrawable) {
Bitmap b = ((BitmapDrawable) d).getBitmap();
if (b != null) {
if (isNinePatch(b)) {
byte[] newChunk = createChunk(b);
nd = new NinePatchDrawable(cropNinePatch(b), newChunk, new Rect(1,1,1,1), "");
Resources resources = TiApplication.getInstance().getResources();
byte[] ninePatchChunk = b.getNinePatchChunk();
if ((ninePatchChunk != null) && NinePatch.isNinePatchChunk(ninePatchChunk)) {
// The bitmap already has 9-patch pixels extracted from the image. Use it as-is.
// Note: This is typically the case for image's under the APK's "res/drawable" directories.
nd = new NinePatchDrawable(resources, b, ninePatchChunk, new Rect(1,1,1,1), "");
}
else if (isNinePatch(b)) {
// The bitmap has 9-patch pixels on the edges. Extract it and crop the pixels off.
// Note: This is typically the case for images under the APK's "assets" directory.
ninePatchChunk = createChunk(b);
nd = new NinePatchDrawable(resources, cropNinePatch(b), ninePatchChunk, new Rect(1,1,1,1), "");
}
}
}

return nd;
}

public Drawable process(Bitmap b)
{
/**
* Creates a new BitmapDrawable or NinePatchDrawable with the given bitmap.
* @param b The bitmap to be drawn by the returned drawable. Can be null.
* @return
* Returns a new NinePatchDrawable if the given bitmap is a 9-patch image.
* <p>
* Returns a new BitmapDrawable if the given bitmap is not a 9-patch image.
* <p>
* Returns null if given a null argument.
*/
public Drawable process(Bitmap b) {
Drawable nd = null;

if (b != null) {
if (isNinePatch(b)) {
byte[] newChunk = createChunk(b);
nd = new NinePatchDrawable(cropNinePatch(b), newChunk, new Rect(1,1,1,1), "");
} else {
nd = new BitmapDrawable(b);
Resources resources = TiApplication.getInstance().getResources();
byte[] ninePatchChunk = b.getNinePatchChunk();
if ((ninePatchChunk != null) && NinePatch.isNinePatchChunk(ninePatchChunk)) {
// The bitmap already has 9-patch pixels extracted from the image. Use it as-is.
// Note: This is typically the case for image's under the APK's "res/drawable" directories.
nd = new NinePatchDrawable(resources, b, ninePatchChunk, new Rect(1,1,1,1), "");
}
else if (isNinePatch(b)) {
// The bitmap has 9-patch pixels on the edges. Extract it and crop the pixels off.
// Note: This is typically the case for images under the APK's "assets" directory.
ninePatchChunk = createChunk(b);
nd = new NinePatchDrawable(resources, cropNinePatch(b), ninePatchChunk, new Rect(1,1,1,1), "");
}
else {
// The given bitmap is not a 9-patch image. Display it in a drawable as-is.
nd = new BitmapDrawable(resources, b);
}
}

Expand Down Expand Up @@ -120,16 +164,17 @@ private boolean isValidColor(int c) {
return (c == 0 || (c == Color.BLACK));
}

private Bitmap cropNinePatch(Bitmap b) {
Bitmap cb = null;
private Bitmap cropNinePatch(Bitmap b) {
Bitmap cb = null;

cb = Bitmap.createBitmap(b.getWidth()-2, b.getHeight()-2, b.getConfig());
int[] pixels = new int[cb.getWidth() * cb.getHeight()];
b.getPixels(pixels, 0, cb.getWidth(), 1, 1, cb.getWidth(), cb.getHeight());
cb.setPixels(pixels, 0, cb.getWidth(), 0, 0, cb.getWidth(), cb.getHeight());
cb = Bitmap.createBitmap(b.getWidth()-2, b.getHeight()-2, b.getConfig());
int[] pixels = new int[cb.getWidth() * cb.getHeight()];
b.getPixels(pixels, 0, cb.getWidth(), 1, 1, cb.getWidth(), cb.getHeight());
cb.setPixels(pixels, 0, cb.getWidth(), 0, 0, cb.getWidth(), cb.getHeight());
cb.setDensity(b.getDensity());

return cb;
}
return cb;
}

byte[] createChunk(Bitmap b) {
byte[] chunk = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,8 @@ public static Drawable getResourceDrawable(String url)

public static Drawable getResourceDrawable(int res_id)
{
return TiApplication.getInstance().getResources().getDrawable(res_id);
Activity activity = TiApplication.getInstance().getCurrentActivity();
return TiDrawableReference.fromResourceId(activity, res_id).getDrawable();
}

public static Drawable getResourceDrawable(Object path)
Expand Down