מפענח תמונות

‫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);