מפענח תמונות

‫NDK ImageDecoder API מספק API סטנדרטי לאפליקציות C/C++‎ ל-Android כדי לפענח תמונות ישירות. מפתחי אפליקציות לא צריכים יותר להשתמש בממשקי Java API (דרך 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: אם יש נתונים כאלה בתמונה מקודדת, המערכת מתעלמת מהם.
  • צפיפות מפת הסיביות: ‫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);