Я припускаю, що ви пишете код для версії Android нижче 3.2 (рівень API <12), оскільки з тих пір поведінка методів
BitmapFactory.decodeFile(pathToImage);
BitmapFactory.decodeFile(pathToImage, opt);
bitmapObject.createScaledBitmap(bitmap, desiredWidth, desiredHeight, false );
змінилося.
На старих платформах (рівень API <12) методи BitmapFactory.decodeFile (..) намагаються повернути Bitmap із конфігурацією RGB_565 за замовчуванням, якщо вони не можуть знайти альфа-версію, що знижує якість iamge. Це все ще нормально, оскільки ви можете застосувати растрове зображення ARGB_8888 за допомогою
options.inPrefferedConfig = Bitmap.Config.ARGB_8888
options.inDither = false
Справжня проблема виникає, коли кожен піксель вашого зображення має альфа-значення 255 (тобто повністю непрозорий). У цьому випадку для прапора Bitmap 'hasAlpha' встановлено значення false, навіть якщо ваш Bitmap має конфігурацію ARGB_8888. Якби у вашому файлі * .png був хоча б один справжній прозорий піксель, для цього прапора було б встановлено значення true, і вам не довелося б ні про що турбуватися.
Отже, коли ви хочете створити масштабований растровий малюнок за допомогою
bitmapObject.createScaledBitmap(bitmap, desiredWidth, desiredHeight, false );
метод перевіряє, чи встановлено для прапора 'hasAlpha значення true чи false, а у вашому випадку - false, що призводить до отримання масштабованого растрового зображення, яке автоматично перетворюється у формат RGB_565.
Тому на рівні API> = 12 існує загальнодоступний метод, який називається
public void setHasAlpha (boolean hasAlpha);
який вирішив би це питання. Поки це було лише поясненням проблеми. Я провів кілька досліджень і помітив, що метод setHasAlpha існує вже давно і є загальнодоступним, але прихований (анотація @hide). Ось як це визначається на Android 2.3:
public void setHasAlpha(boolean hasAlpha) {
nativeSetHasAlpha(mNativeBitmap, hasAlpha);
}
Зараз ось моя пропозиція щодо рішення. Він не передбачає копіювання растрових даних:
Перевіряється під час виконання за допомогою java.lang.Reflect, чи поточна реалізація Bitmap має загальнодоступний метод 'setHasAplha'. (Згідно з моїми тестами, він чудово працює з API 3 рівня, і я не тестував нижчих версій, оскільки JNI не працював). У вас можуть виникнути проблеми, якщо виробник явно зробив його приватним, захистив або видалив.
Викличте метод 'setHasAlpha' для даного об'єкта Bitmap за допомогою JNI. Це чудово працює, навіть для приватних методів або полів. Офіційно JNI не перевіряє, порушуєте Ви правила контролю доступу чи ні. Джерело: http://java.sun.com/docs/books/jni/html/pitfalls.html (10.9) Це дає нам велику силу, якою слід користуватися з розумом. Я б не намагався модифікувати остаточне поле, навіть якщо це спрацювало (лише для прикладу). І зауважте, це лише обхідний шлях ...
Ось моя реалізація всіх необхідних методів:
ЧАСТИНА ЯВА:
private static final boolean SETHASALPHA_EXISTS = setHasAlphaExists();
private static boolean setHasAlphaExists() {
java.lang.reflect.Method[] methods = Bitmap.class.getMethods();
for(int i=0; i<methods.length; i++) {
if(methods[i].getName().contains("setHasAlpha")) {
Log.i(TAG, "method setHasAlpha was found");
return true;
}
}
Log.i(TAG, "couldn't find method setHasAlpha");
return false;
}
private static void setHasAlpha(Bitmap bitmap, boolean value) {
if(bitmap.hasAlpha() == value) {
Log.i(TAG, "bitmap.hasAlpha() == value -> do nothing");
return;
}
if(!SETHASALPHA_EXISTS) {
return;
}
if(Integer.valueOf(android.os.Build.VERSION.SDK) <= 11) {
Log.i(TAG, "BEFORE: bitmap.hasAlpha() == " + bitmap.hasAlpha());
Log.i(TAG, "trying to set hasAplha to true");
int result = setHasAlphaNative(bitmap, value);
Log.i(TAG, "AFTER: bitmap.hasAlpha() == " + bitmap.hasAlpha());
if(result == -1) {
Log.e(TAG, "Unable to access bitmap.");
return;
}
} else {
bitmap.setHasAlpha(true);
}
}
public Bitmap decodeBitmapFromFile(String pathToImage, int pixels_limit) {
Bitmap bitmap;
Options opt = new Options();
opt.inDither = false;
opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
bitmap = BitmapFactory.decodeFile(pathToImage, opt);
if(bitmap == null) {
Log.e(TAG, "unable to decode bitmap");
return null;
}
setHasAlpha(bitmap, true);
int numOfPixels = bitmap.getWidth() * bitmap.getHeight();
if(numOfPixels > pixels_limit) {
imageScaleFactor = Math.sqrt((double) pixels_limit / (double) numOfPixels);
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap,
(int) (imageScaleFactor * bitmap.getWidth()), (int) (imageScaleFactor * bitmap.getHeight()), false);
bitmap.recycle();
bitmap = scaledBitmap;
Log.i(TAG, "scaled bitmap config: " + bitmap.getConfig().toString());
Log.i(TAG, "pixels_limit = " + pixels_limit);
Log.i(TAG, "scaled_numOfpixels = " + scaledBitmap.getWidth()*scaledBitmap.getHeight());
setHasAlpha(bitmap, true);
}
return bitmap;
}
Завантажте свою бібліотеку та оголосіть власний метод:
static {
System.loadLibrary("bitmaputils");
}
private static native int setHasAlphaNative(Bitmap bitmap, boolean value);
Власний розділ (папка 'jni')
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := bitmaputils
LOCAL_SRC_FILES := bitmap_utils.c
LOCAL_LDLIBS := -llog -ljnigraphics -lz -ldl -lgcc
include $(BUILD_SHARED_LIBRARY)
bitmapUtils.c:
#include <jni.h>
#include <android/bitmap.h>
#include <android/log.h>
#define LOG_TAG "BitmapTest"
#define Log_i(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define Log_e(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
static jclass bitmap_class = 0;
static jmethodID setHasAlphaMethodID = 0;
jint Java_com_example_bitmaptest_MainActivity_setHasAlphaNative(JNIEnv * env, jclass clazz, jobject bitmap, jboolean value) {
AndroidBitmapInfo info;
void* pixels;
if (AndroidBitmap_getInfo(env, bitmap, &info) < 0) {
Log_e("Failed to get Bitmap info");
return -1;
}
if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
Log_e("Incompatible Bitmap format");
return -1;
}
if (AndroidBitmap_lockPixels(env, bitmap, &pixels) < 0) {
Log_e("Failed to lock the pixels of the Bitmap");
return -1;
}
if(bitmap_class == NULL) {
bitmap_class = (*env)->GetObjectClass(env, bitmap);
if(bitmap_class == NULL) {
Log_e("bitmap_class == NULL");
return -2;
}
}
if(setHasAlphaMethodID == NULL) {
setHasAlphaMethodID = (*env)->GetMethodID(env, bitmap_class, "setHasAlpha", "(Z)V");
if(setHasAlphaMethodID == NULL) {
Log_e("methodID == NULL");
return -2;
}
}
(*env)->CallVoidMethod(env, bitmap, setHasAlphaMethodID, value);
if ((*env)->ExceptionOccurred(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
Log_e("calling setHasAlpha threw an exception");
return -2;
}
if(AndroidBitmap_unlockPixels(env, bitmap) < 0) {
Log_e("Failed to unlock the pixels of the Bitmap");
return -1;
}
return 0;
}
Це воно. Ми закінчили. Я опублікував цілий код для копіювання та вставлення. Насправді код не такий великий, але всі ці параноїчні перевірки помилок роблять його набагато більшим. Сподіваюся, це може бути корисним для когось.
setAntiAlias
істина (і це все одно не має значення)?