6

Background

I've noticed a weird column for MediaStore.Images.ImageColumns called "MINI_THUMB_MAGIC" .

the documentation says just that :

The mini thumb id.

Type: INTEGER

Constant Value: "mini_thumb_magic"

The question

my guess is that this field is related to MediaStore.Images.Thumbnails .

Is it correct ? if not, what is this and how do you use it?

if it is correct , i have other questions related to it:

  1. Is it a mini sized image of the original one? does it use the same aspect ratio or does it do center-cropping on it?

  2. how come the size of "MICRO" is square (96 x 96) and the size of "MINI" is a non-square rectangle ( 512 x 384 ) ?

  3. How do you use it? My guess is that it's done by using "THUMB_DATA", which is a blob, so you use it like this, but then what is the purpose of using "getThumbnail" if you already have this field?

  4. does it get a rotated thumbnail in case the orientation value is not 0 ? meaning that if I wish to show it, I won't need to rotate the image?

  5. Is it possible to do a query of the images together with their thumbnails? maybe using inner join?

  6. Is it available for all Android devices and versions?

  7. Why is it even called "magic" ? Is it because it's also available for videos (and for some reason doesn't exist for music, as it could be the album's cover photo, for example) ?

Community
  • 1
  • 1
android developer
  • 114,585
  • 152
  • 739
  • 1,270

3 Answers3

2

Check this file: https://github.com/android/platform_packages_providers_mediaprovider/blob/master/src/com/android/providers/media/MediaThumbRequest.java in the Android source code. This value is some magic number which allows to determine if the thumbnail is still valid. I didn't investigate that file further, but it should be no bit issue to dive deeper. To your questions:

  1. No, no mini-sized image
  2. Well, I guess it's a definition by Google who want to have a square thumbnail for some lists, where only very small previews should be visible and where many items should fit on the screen and there's another thumbnail format where the images are bigger...
  3. I don't know that, but according to Google's doc, one (THUMB_DATA) is only some raw byte array of the thumbnail (dunno in which format) and the other one (getThumbnail) retrieves a full-fledged bitmap object...
  4. don't know
  5. don't know
  6. I guess so, as it's part of AOSP source code.
  7. The word "magic" is often used for some kind of identifier. There are "magic packets" who can wake up a computer from sleep or shutdown over the network, there are magic numbers on hard disks, where some sectors (e.g. the MBR) has the hexadecimal values AA 55 on its last two byte positions, there are also magic numbers in image files which help software packages determine the image type (e.g. GIF files begin with GIF89a or GIF87a (ASCII), JPEG files begin with FF D8 hexadecimal) and there are many, many more examples. So, magic numbers are a very common term here :-)
TomS
  • 467
  • 9
  • 25
  • Interesting. Since I've already moved on from this question, I can't check it out and mark it, but because you've taken the time to answer, you get +1 . Maybe in the future I will tick it too. – android developer Apr 11 '15 at 21:46
  • @androiddeveloper the future is now here. You should probably award TomS his correct answer. – JohnnyLambada Apr 04 '16 at 20:45
0

According to the source code at the following URL, the Magic Number is the Id of the original image * a constant. That value is then used to check for a long int. If the int isn't as expected, it's considered out of sync with the image media.

http://grepcode.com/file/repo1.maven.org/maven2/org.robolectric/android-all/4.4_r1-robolectric-0/android/media/MiniThumbFile.java#MiniThumbFile.getMagic%28long%29

// Get the magic number for the specified id in the mini-thumb file.
// Returns 0 if the magic is not available.
public synchronized long getMagic(long id) {
   // check the mini thumb file for the right data.  Right is
   // defined as having the right magic number at the offset
   // reserved for this "id".
   RandomAccessFile r = miniThumbDataFile();
   if (r != null) {
       long pos = id * BYTES_PER_MINTHUMB;
       FileLock lock = null;
       try {
           mBuffer.clear();
           mBuffer.limit(1 + 8);

           lock = mChannel.lock(pos, 1 + 8, true);
           // check that we can read the following 9 bytes
           // (1 for the "status" and 8 for the long)
           if (mChannel.read(mBuffer, pos) == 9) {
               mBuffer.position(0);
               if (mBuffer.get() == 1) {
                   return mBuffer.getLong();
               }
           }
       } catch (IOException ex) {
           Log.v(TAG, "Got exception checking file magic: ", ex);
       } catch (RuntimeException ex) {
           // Other NIO related exception like disk full, read only channel..etc
           Log.e(TAG, "Got exception when reading magic, id = " + id +
                   ", disk full or mount read-only? " + ex.getClass());
       } finally {
           try {
               if (lock != null) lock.release();
           }
           catch (IOException ex) {
               // ignore it.
           }
       }
   }
   return 0;
}

I got the runtime exception when trying to get the original Id of a thumbnail by looking up the thumbnail's path. (BTW, the disk isn't full and it's not read-only.)

grigb
  • 1,151
  • 8
  • 14
0

It's a bit strange parameter...
While exploring the Gallery source code,
noticed that the value is being read from the cursor, but then is Never used:

@Override
    protected BaseImage loadImageFromCursor(Cursor cursor) {
        long id = cursor.getLong(INDEX_ID);
        String dataPath = cursor.getString(INDEX_DATA_PATH);
        long dateTaken = cursor.getLong(INDEX_DATE_TAKEN);
        if (dateTaken == 0) {
            dateTaken = cursor.getLong(INDEX_DATE_MODIFIED) * 1000;
        }

// here they read it ====>>

        long miniThumbMagic = cursor.getLong(INDEX_MINI_THUMB_MAGIC);
        int orientation = cursor.getInt(INDEX_ORIENTATION);
        String title = cursor.getString(INDEX_TITLE);
        String mimeType = cursor.getString(INDEX_MIME_TYPE);
        if (title == null || title.length() == 0) {
            title = dataPath;
        }

// and not use at all ==>>>

        return new Image(this, mContentResolver, id, cursor.getPosition(),
                contentUri(id), dataPath, mimeType, dateTaken, title,
                orientation);
    } 

Maybe it was used on the previous APIs.

ref: https://android.googlesource.com/platform/packages/apps/Gallery/+/android-8.0.0_r12/src/com/android/camera/gallery/ImageList.java?autodive=0%2F%2F.
and videos list: https://android.googlesource.com/platform/packages/apps/Gallery/+/android-8.0.0_r12/src/com/android/camera/gallery/VideoList.java?autodive=0%2F%2F

Leo DroidCoder
  • 14,527
  • 4
  • 62
  • 54