ממשק ה-API ImageDecoder
של NDK מספק ממשק API רגיל לאפליקציות Android ב-C/C++ לצורך פענוח תמונות ישירות. מפתחי אפליקציות כבר לא צריכים להשתמש בממשקי ה-API של Java (דרך JNI) או בספריות של צד שלישי לפענוח תמונות. ממשק ה-API הזה, יחד עם פונקציות קידוד במודול Bitmap, מאפשר לבצע את הפעולות הבאות:
- אפליקציות וספריות מקוריות יכולות להיות קטנות יותר כי אין יותר צורך לקשר ספריות פענוח משלהם.
- אפליקציות וספריות נהנות באופן אוטומטי מעדכוני האבטחה של הפלטפורמה לספריות הפענוח.
- אפליקציות יכולות לפענח תמונות ישירות בזיכרון שהן מספקות. לאחר מכן, האפליקציות יכולות לעבד את נתוני התמונה בשלב מאוחר יותר (אם רוצים) ולהעביר אותם ל-OpenGL או לקוד הציור שלהן.
בדף הזה נסביר איך משתמשים ב-API כדי לפענח תמונה.
זמינות ויכולות
ממשק ה-API ImageDecoder
זמין באפליקציות שמטרגטות ל-Android 11 (רמת API 30)
ואילך. ההטמעה נמצאת בקבצים הבאים:
imagedecoder.h
למפענחbitmap.h
למקודדlibjnigraphics.so
ה-API תומך בפורמטים הבאים של תמונות:
- JPEG
- PNG
- GIF
- WebP
BMP
ICO
WBMP
HEIF
תמונות נגטיב דיגיטליות (דרך DNG SDK)
כדי לכסות את כל השימושים בתמונות הגולמיות שעבר תהליך פענוח, ה-API הזה לא מספק אובייקטים ברמה גבוהה יותר, כמו אובייקטים שנוצרו מעל תמונות שעבר תהליך פענוח בתוך מסגרת Java, למשל:
- אובייקטים מסוג
Drawable
. NinePatch
: אם הם נמצאים בתמונה מקודדת, המערכת מתעלמת מקטעי NinePatch.- צפיפות הבייטמאפ:
AImageDecoder
לא מבצע התאמה אוטומטית של הגודל על סמך הצפיפות של המסך, אבל הוא מאפשר פענוח לגודל אחר באמצעותAImageDecoder_setTargetSize()
. - אנימציות: רק פענוח של הפריים הראשון בקובץ GIF מונפש או בקובץ WebP.
פענוח תמונה
תהליך הפענוח מתחיל עם סוג כלשהו של קלט שמייצג את התמונה המקודדת.
AImageDecoder
מקבלת כמה סוגים של קלט:
AAsset
(כפי שמוצג בהמשך)- תיאור קובץ
- מאגר נתונים זמני
בקוד הבא מוסבר איך לפתוח קובץ תמונה Asset
, לפענח אותו ואז להיפטר מהפענח ומהנכס בצורה נכונה. דוגמה לעיבוד של התמונה המפוענחת מופיעה בדוגמה של הכיור.
AAssetManager* nativeManager = AAssetManager_fromJava(env, jAssets);
const char* file = // Filename
AAsset* asset = AAssetManager_open(nativeManager, file, AASSET_MODE_STREAMING);
AImageDecoder* decoder;
int result = AImageDecoder_createFromAAsset(asset, &decoder);
if (result != ANDROID_IMAGE_DECODER_SUCCESS) {
// An error occurred, and the file could not be decoded.
}
const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
int32_t width = AImageDecoderHeaderInfo_getWidth(info);
int32_t height = AImageDecoderHeaderInfo_getHeight(info);
AndroidBitmapFormat format =
(AndroidBitmapFormat) AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
size_t stride = AImageDecoder_getMinimumStride(decoder); // Image decoder does not
// use padding by default
size_t size = height * stride;
void* pixels = malloc(size);
result = AImageDecoder_decodeImage(decoder, pixels, stride, size);
if (result != ANDROID_IMAGE_DECODER_SUCCESS) {
// An error occurred, and the file could not be decoded.
}
// We’re done with the decoder, so now it’s safe to delete it.
AImageDecoder_delete(decoder);
// The decoder is no longer accessing the AAsset, so it is safe to
// close it.
AAsset_close(asset);
// Draw the pixels somewhere
// Free the pixels when done drawing with them
free(pixels);