mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-18 22:01:42 +08:00
fix(android): image asset handling regarding requestLegacyExternalStorage (#9373)
This commit is contained in:
24
packages/core/global-types.d.ts
vendored
24
packages/core/global-types.d.ts
vendored
@ -349,31 +349,31 @@ declare class WeakRef<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Java long from a number
|
||||
*/
|
||||
* Create a Java long from a number
|
||||
*/
|
||||
declare function long(value: number): any;
|
||||
|
||||
/**
|
||||
* Create a Java byte from a number
|
||||
*/
|
||||
* Create a Java byte from a number
|
||||
*/
|
||||
declare function byte(value: number): any;
|
||||
|
||||
/**
|
||||
* Create a Java short from a number
|
||||
*/
|
||||
* Create a Java short from a number
|
||||
*/
|
||||
declare function short(value: number): any;
|
||||
|
||||
/**
|
||||
* Create a Java double from a number
|
||||
*/
|
||||
* Create a Java double from a number
|
||||
*/
|
||||
declare function double(value: number): any;
|
||||
|
||||
/**
|
||||
* Create a Java float from a number
|
||||
*/
|
||||
* Create a Java float from a number
|
||||
*/
|
||||
declare function float(value: number): any;
|
||||
|
||||
/**
|
||||
* Create a Java char from a string
|
||||
*/
|
||||
* Create a Java char from a string
|
||||
*/
|
||||
declare function char(value: string): any;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { ImageAssetBase, getRequestedImageSize } from './image-asset-common';
|
||||
import { path as fsPath, knownFolders } from '../file-system';
|
||||
|
||||
import { ad } from '../utils';
|
||||
import { Screen } from '../platform';
|
||||
export * from './image-asset-common';
|
||||
|
||||
export class ImageAsset extends ImageAssetBase {
|
||||
@ -25,66 +26,20 @@ export class ImageAsset extends ImageAssetBase {
|
||||
}
|
||||
|
||||
public getImageAsync(callback: (image, error) => void) {
|
||||
const bitmapOptions = new android.graphics.BitmapFactory.Options();
|
||||
bitmapOptions.inJustDecodeBounds = true;
|
||||
// read only the file size
|
||||
let bitmap = android.graphics.BitmapFactory.decodeFile(this.android, bitmapOptions);
|
||||
const sourceSize = {
|
||||
width: bitmapOptions.outWidth,
|
||||
height: bitmapOptions.outHeight,
|
||||
};
|
||||
const requestedSize = getRequestedImageSize(sourceSize, this.options);
|
||||
|
||||
const sampleSize = org.nativescript.widgets.image.Fetcher.calculateInSampleSize(bitmapOptions.outWidth, bitmapOptions.outHeight, requestedSize.width, requestedSize.height);
|
||||
|
||||
const finalBitmapOptions = new android.graphics.BitmapFactory.Options();
|
||||
finalBitmapOptions.inSampleSize = sampleSize;
|
||||
try {
|
||||
let error = null;
|
||||
// read as minimum bitmap as possible (slightly bigger than the requested size)
|
||||
bitmap = android.graphics.BitmapFactory.decodeFile(this.android, finalBitmapOptions);
|
||||
|
||||
if (bitmap) {
|
||||
if (requestedSize.width !== bitmap.getWidth() || requestedSize.height !== bitmap.getHeight()) {
|
||||
// scale to exact size
|
||||
bitmap = android.graphics.Bitmap.createScaledBitmap(bitmap, requestedSize.width, requestedSize.height, true);
|
||||
}
|
||||
|
||||
const rotationAngle = calculateAngleFromFile(this.android);
|
||||
if (rotationAngle !== 0) {
|
||||
const matrix = new android.graphics.Matrix();
|
||||
matrix.postRotate(rotationAngle);
|
||||
bitmap = android.graphics.Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!bitmap) {
|
||||
error = "Asset '" + this.android + "' cannot be found.";
|
||||
}
|
||||
|
||||
callback(bitmap, error);
|
||||
} catch (ex) {
|
||||
org.nativescript.widgets.Utils.loadImageAsync(
|
||||
ad.getApplicationContext(),
|
||||
this.android,
|
||||
JSON.stringify(this.options || {}),
|
||||
Screen.mainScreen.widthPixels,
|
||||
Screen.mainScreen.heightPixels,
|
||||
new org.nativescript.widgets.Utils.AsyncImageCallback({
|
||||
onSuccess(bitmap) {
|
||||
callback(bitmap, null);
|
||||
},
|
||||
onError(ex) {
|
||||
callback(null, ex);
|
||||
}
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function calculateAngleFromFile(filename: string) {
|
||||
let rotationAngle = 0;
|
||||
const ei = new android.media.ExifInterface(filename);
|
||||
const orientation = ei.getAttributeInt(android.media.ExifInterface.TAG_ORIENTATION, android.media.ExifInterface.ORIENTATION_NORMAL);
|
||||
|
||||
switch (orientation) {
|
||||
case android.media.ExifInterface.ORIENTATION_ROTATE_90:
|
||||
rotationAngle = 90;
|
||||
break;
|
||||
case android.media.ExifInterface.ORIENTATION_ROTATE_180:
|
||||
rotationAngle = 180;
|
||||
break;
|
||||
case android.media.ExifInterface.ORIENTATION_ROTATE_270:
|
||||
rotationAngle = 270;
|
||||
break;
|
||||
}
|
||||
|
||||
return rotationAngle;
|
||||
}
|
||||
|
Binary file not shown.
@ -1,11 +1,6 @@
|
||||
declare module org {
|
||||
module nativescript {
|
||||
module widgets {
|
||||
|
||||
export class Utils {
|
||||
public static drawBoxShadow(view: android.view.View, value: string): void;
|
||||
}
|
||||
|
||||
export class BoxShadowDrawable {
|
||||
public constructor(drawable: android.graphics.drawable.Drawable, value: string);
|
||||
public getWrappedDrawable(): android.graphics.drawable.Drawable;
|
||||
@ -632,3 +627,34 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare module org {
|
||||
export module nativescript {
|
||||
export module widgets {
|
||||
export class Utils {
|
||||
public static class: java.lang.Class<org.nativescript.widgets.Utils>;
|
||||
public static loadImageAsync(param0: globalAndroid.content.Context, param1: string, param2: string, param3: number, param4: number, param5: org.nativescript.widgets.Utils.AsyncImageCallback): void;
|
||||
public static drawBoxShadow(param0: globalAndroid.view.View, param1: string): void;
|
||||
public constructor();
|
||||
}
|
||||
export module Utils {
|
||||
export class AsyncImageCallback {
|
||||
public static class: java.lang.Class<org.nativescript.widgets.Utils.AsyncImageCallback>;
|
||||
/**
|
||||
* Constructs a new instance of the org.nativescript.widgets.Utils$AsyncImageCallback interface with the provided implementation. An empty constructor exists calling super() when extending the interface class.
|
||||
*/
|
||||
public constructor(implementation: {
|
||||
onSuccess(param0: globalAndroid.graphics.Bitmap): void;
|
||||
onError(param0: java.lang.Exception): void;
|
||||
});
|
||||
public constructor();
|
||||
public onSuccess(param0: globalAndroid.graphics.Bitmap): void;
|
||||
public onError(param0: java.lang.Exception): void;
|
||||
}
|
||||
export class ImageAssetOptions {
|
||||
public static class: java.lang.Class<org.nativescript.widgets.Utils.ImageAssetOptions>;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ dependencies {
|
||||
implementation 'androidx.viewpager:viewpager:' + androidxVersion
|
||||
implementation 'androidx.fragment:fragment:' + androidxVersion
|
||||
implementation 'androidx.transition:transition:' + androidxVersion
|
||||
implementation "androidx.exifinterface:exifinterface:1.3.2"
|
||||
} else {
|
||||
println 'Using support library'
|
||||
implementation 'com.android.support:support-v4:' + computeSupportVersion()
|
||||
|
@ -17,13 +17,17 @@
|
||||
package org.nativescript.widgets.image;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.media.ExifInterface;
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
|
||||
@ -34,6 +38,7 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@ -257,8 +262,9 @@ public class Fetcher extends Worker {
|
||||
if (debuggable > 0) {
|
||||
Log.v(TAG, "process: " + uri);
|
||||
}
|
||||
|
||||
if (uri.startsWith(FILE_PREFIX)) {
|
||||
if(uri.startsWith(CONTENT_PREFIX)){
|
||||
return decodeSampledBitmapFromContent(uri,mResolver , decodeWidth, decodeHeight, keepAspectRatio, getCache());
|
||||
}else if (uri.startsWith(FILE_PREFIX)) {
|
||||
String filename = uri.substring(FILE_PREFIX.length());
|
||||
return decodeSampledBitmapFromFile(filename, decodeWidth, decodeHeight, keepAspectRatio, getCache());
|
||||
} else if (uri.startsWith(RESOURCE_PREFIX)) {
|
||||
@ -474,6 +480,62 @@ public class Fetcher extends Worker {
|
||||
return scaleAndRotateBitmap(bitmap, ei, reqWidth, reqHeight, keepAspectRatio);
|
||||
}
|
||||
|
||||
private static void closePfd(ParcelFileDescriptor pfd){
|
||||
if(pfd != null){
|
||||
try {
|
||||
pfd.close();
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode and sample down a bitmap from a file to the requested width and height.
|
||||
*
|
||||
* @param content The content uri of the file to decode
|
||||
* @param reqWidth The requested width of the resulting bitmap
|
||||
* @param reqHeight The requested height of the resulting bitmap
|
||||
* @param cache The Cache used to find candidate bitmaps for use with inBitmap
|
||||
* @return A bitmap sampled down from the original with the same aspect ratio and dimensions
|
||||
* that are equal to or greater than the requested width and height
|
||||
*/
|
||||
public static Bitmap decodeSampledBitmapFromContent(String content, ContentResolver resolver, int reqWidth, int reqHeight,
|
||||
boolean keepAspectRatio, Cache cache) {
|
||||
|
||||
// First decode with inJustDecodeBounds=true to check dimensions
|
||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
|
||||
|
||||
Uri uri = android.net.Uri.parse(content);
|
||||
ParcelFileDescriptor pfd = null;
|
||||
try {
|
||||
pfd = resolver.openFileDescriptor(uri, "r");
|
||||
BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor(), null, options);
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.v(TAG, "File not found " + content);
|
||||
closePfd(pfd);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
options.inSampleSize = calculateInSampleSize(options.outWidth, options.outHeight, reqWidth, reqHeight);
|
||||
|
||||
// If we're running on Honeycomb or newer, try to use inBitmap
|
||||
if (Utils.hasHoneycomb()) {
|
||||
addInBitmapOptions(options, cache);
|
||||
}
|
||||
|
||||
// Decode bitmap with inSampleSize set
|
||||
options.inJustDecodeBounds = false;
|
||||
|
||||
final Bitmap bitmap = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor(), null, options);
|
||||
|
||||
ExifInterface ei = getExifInterface(pfd.getFileDescriptor());
|
||||
closePfd(pfd);
|
||||
|
||||
return scaleAndRotateBitmap(bitmap, ei, reqWidth, reqHeight, keepAspectRatio);
|
||||
}
|
||||
|
||||
private static Bitmap scaleAndRotateBitmap(Bitmap bitmap, ExifInterface ei, int reqWidth, int reqHeight,
|
||||
boolean keepAspectRatio) {
|
||||
if (bitmap == null) {
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package org.nativescript.widgets.image;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
@ -37,6 +38,7 @@ public abstract class Worker {
|
||||
|
||||
protected static final String RESOURCE_PREFIX = "res://";
|
||||
protected static final String FILE_PREFIX = "file:///";
|
||||
protected static final String CONTENT_PREFIX = "content://";
|
||||
|
||||
static final String TAG = "JS";
|
||||
private static final int FADE_IN_TIME = 200;
|
||||
@ -49,7 +51,7 @@ public abstract class Worker {
|
||||
|
||||
protected boolean mPauseWork = false;
|
||||
protected Resources mResources;
|
||||
|
||||
protected ContentResolver mResolver;
|
||||
private static final int MESSAGE_CLEAR = 0;
|
||||
private static final int MESSAGE_INIT_DISK_CACHE = 1;
|
||||
private static final int MESSAGE_FLUSH = 2;
|
||||
@ -59,7 +61,7 @@ public abstract class Worker {
|
||||
|
||||
protected Worker(Context context) {
|
||||
mResources = context.getResources();
|
||||
|
||||
mResolver = context.getContentResolver();
|
||||
// Negative means not initialized.
|
||||
if (debuggable < 0) {
|
||||
try {
|
||||
|
@ -1,12 +1,33 @@
|
||||
package org.nativescript.widgets;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class Utils {
|
||||
public static void drawBoxShadow(View view, String value) {
|
||||
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
|
||||
@ -16,14 +37,14 @@ public class Utils {
|
||||
|
||||
Drawable currentBg = view.getBackground();
|
||||
|
||||
if(currentBg != null) {
|
||||
if (currentBg != null) {
|
||||
Log.d("BoxShadowDrawable", "current BG is: " + currentBg.getClass().getName());
|
||||
}
|
||||
|
||||
if(currentBg == null) {
|
||||
if (currentBg == null) {
|
||||
Log.d("BoxShadowDrawable", "view had no background!");
|
||||
currentBg = new ColorDrawable(Color.TRANSPARENT);
|
||||
} else if(currentBg instanceof BoxShadowDrawable) {
|
||||
} else if (currentBg instanceof BoxShadowDrawable) {
|
||||
currentBg = ((BoxShadowDrawable) view.getBackground()).getWrappedDrawable();
|
||||
Log.d("BoxShadowDrawable", "already a BoxShadowDrawable, getting wrapped drawable:" + currentBg.getClass().getName());
|
||||
}
|
||||
@ -33,7 +54,7 @@ public class Utils {
|
||||
view.setBackground(new BoxShadowDrawable(currentBg, value));
|
||||
|
||||
Drawable bg = view.getBackground();
|
||||
if(bg != null) {
|
||||
if (bg != null) {
|
||||
Log.d("BoxShadowDrawable", "new current bg: " + bg.getClass().getName());
|
||||
}
|
||||
|
||||
@ -50,6 +71,222 @@ public class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
public interface AsyncImageCallback {
|
||||
void onSuccess(Bitmap bitmap);
|
||||
|
||||
void onError(Exception exception);
|
||||
}
|
||||
|
||||
static class ImageAssetOptions {
|
||||
int width;
|
||||
int height;
|
||||
boolean keepAspectRatio;
|
||||
boolean autoScaleFactor;
|
||||
}
|
||||
|
||||
private static final Executor executors = Executors.newCachedThreadPool();
|
||||
|
||||
|
||||
private static Pair<Integer, Integer> getAspectSafeDimensions(float sourceWidth, float sourceHeight, float reqWidth, float reqHeight) {
|
||||
float widthCoef = sourceWidth / reqWidth;
|
||||
float heightCoef = sourceHeight / reqHeight;
|
||||
float aspectCoef = Math.min(widthCoef, heightCoef);
|
||||
|
||||
return new Pair<>((int) Math.floor(sourceWidth / aspectCoef), (int) Math.floor(sourceHeight / aspectCoef));
|
||||
}
|
||||
|
||||
|
||||
private static Pair<Integer, Integer> getRequestedImageSize(Pair<Integer, Integer> src, Pair<Integer, Integer> maxSize, ImageAssetOptions options) {
|
||||
int reqWidth = options.width;
|
||||
if (reqWidth <= 0) {
|
||||
reqWidth = Math.min(src.first, maxSize.first);
|
||||
}
|
||||
int reqHeight = options.height;
|
||||
if (reqHeight <= 0) {
|
||||
reqHeight = Math.min(src.second, maxSize.second);
|
||||
}
|
||||
|
||||
if (options.keepAspectRatio) {
|
||||
Pair<Integer, Integer> safeAspectSize = getAspectSafeDimensions(src.first, src.second, reqWidth, reqHeight);
|
||||
reqWidth = safeAspectSize.first;
|
||||
reqHeight = safeAspectSize.second;
|
||||
}
|
||||
|
||||
return new Pair<>(reqWidth, reqHeight);
|
||||
}
|
||||
|
||||
|
||||
private static void closePfd(ParcelFileDescriptor pfd) {
|
||||
if (pfd != null) {
|
||||
try {
|
||||
pfd.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int calculateAngleFromFile(String filename) {
|
||||
int rotationAngle = 0;
|
||||
ExifInterface ei;
|
||||
try {
|
||||
ei = new ExifInterface(filename);
|
||||
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
|
||||
|
||||
switch (orientation) {
|
||||
case ExifInterface.ORIENTATION_ROTATE_90:
|
||||
rotationAngle = 90;
|
||||
break;
|
||||
case ExifInterface.ORIENTATION_ROTATE_180:
|
||||
rotationAngle = 180;
|
||||
break;
|
||||
case ExifInterface.ORIENTATION_ROTATE_270:
|
||||
rotationAngle = 270;
|
||||
break;
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
|
||||
return rotationAngle;
|
||||
}
|
||||
|
||||
|
||||
private static int calculateAngleFromFileDescriptor(FileDescriptor fd) {
|
||||
int rotationAngle = 0;
|
||||
ExifInterface ei;
|
||||
try {
|
||||
ei = new ExifInterface(fd);
|
||||
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
|
||||
|
||||
switch (orientation) {
|
||||
case ExifInterface.ORIENTATION_ROTATE_90:
|
||||
rotationAngle = 90;
|
||||
break;
|
||||
case ExifInterface.ORIENTATION_ROTATE_180:
|
||||
rotationAngle = 180;
|
||||
break;
|
||||
case ExifInterface.ORIENTATION_ROTATE_270:
|
||||
rotationAngle = 270;
|
||||
break;
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
|
||||
return rotationAngle;
|
||||
}
|
||||
|
||||
private static final Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
public static void loadImageAsync(final Context context, final String src, final String options, final int maxWidth, final int maxHeight, final AsyncImageCallback callback) {
|
||||
executors.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
|
||||
bitmapOptions.inJustDecodeBounds = true;
|
||||
|
||||
try {
|
||||
Bitmap bitmap;
|
||||
ParcelFileDescriptor pfd = null;
|
||||
if (src.startsWith("content://")) {
|
||||
Uri uri = android.net.Uri.parse(src);
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
try {
|
||||
pfd = resolver.openFileDescriptor(uri, "r");
|
||||
} catch (final FileNotFoundException e) {
|
||||
mainHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.onError(e);
|
||||
}
|
||||
});
|
||||
closePfd(pfd);
|
||||
return;
|
||||
}
|
||||
android.graphics.BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor(), null, bitmapOptions);
|
||||
} else {
|
||||
android.graphics.BitmapFactory.decodeFile(src, bitmapOptions);
|
||||
}
|
||||
|
||||
ImageAssetOptions opts = new ImageAssetOptions();
|
||||
opts.keepAspectRatio = true;
|
||||
opts.autoScaleFactor = true;
|
||||
|
||||
try {
|
||||
JSONObject object = new JSONObject(options);
|
||||
opts.width = object.optInt("width", 0);
|
||||
opts.height = object.optInt("height", 0);
|
||||
opts.keepAspectRatio = object.optBoolean("keepAspectRatio", true);
|
||||
opts.autoScaleFactor = object.optBoolean("autoScaleFactor", true);
|
||||
} catch (JSONException ignored) {
|
||||
}
|
||||
|
||||
|
||||
Pair<Integer, Integer> sourceSize = new Pair<>(bitmapOptions.outWidth, bitmapOptions.outHeight);
|
||||
Pair<Integer, Integer> maxSize = new Pair<>(maxWidth, maxHeight);
|
||||
Pair<Integer, Integer> requestedSize = getRequestedImageSize(sourceSize, maxSize, opts);
|
||||
int sampleSize = org.nativescript.widgets.image.Fetcher.calculateInSampleSize(bitmapOptions.outWidth, bitmapOptions.outHeight, requestedSize.first, requestedSize.second);
|
||||
BitmapFactory.Options finalBitmapOptions = new BitmapFactory.Options();
|
||||
finalBitmapOptions.inSampleSize = sampleSize;
|
||||
|
||||
|
||||
String error = null;
|
||||
// read as minimum bitmap as possible (slightly bigger than the requested size)
|
||||
|
||||
|
||||
if (pfd != null) {
|
||||
bitmap = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor(), null, finalBitmapOptions);
|
||||
} else {
|
||||
bitmap = android.graphics.BitmapFactory.decodeFile(src, finalBitmapOptions);
|
||||
}
|
||||
|
||||
|
||||
if (bitmap != null) {
|
||||
if (requestedSize.first != bitmap.getWidth() || requestedSize.second != bitmap.getHeight()) {
|
||||
// scale to exact size
|
||||
bitmap = android.graphics.Bitmap.createScaledBitmap(bitmap, requestedSize.first, requestedSize.second, true);
|
||||
}
|
||||
int rotationAngle;
|
||||
|
||||
if (pfd != null) {
|
||||
rotationAngle = calculateAngleFromFileDescriptor(pfd.getFileDescriptor());
|
||||
closePfd(pfd);
|
||||
} else {
|
||||
rotationAngle = calculateAngleFromFile(src);
|
||||
}
|
||||
|
||||
if (rotationAngle != 0) {
|
||||
Matrix matrix = new android.graphics.Matrix();
|
||||
matrix.postRotate(rotationAngle);
|
||||
bitmap = android.graphics.Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||
}
|
||||
}
|
||||
if (bitmap == null) {
|
||||
error = "Asset '" + src + "' cannot be found.";
|
||||
}
|
||||
|
||||
final String finalError = error;
|
||||
final Bitmap finalBitmap = bitmap;
|
||||
mainHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (finalError != null) {
|
||||
callback.onError(new Exception(finalError));
|
||||
} else {
|
||||
callback.onSuccess(finalBitmap);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (final Exception ex) {
|
||||
mainHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.onError(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// public static void clearBoxShadow(View view) {
|
||||
// if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
|
||||
// return;
|
||||
|
Reference in New Issue
Block a user