【Android】縮圖Thumbnails

來源:互聯網
上載者:User

在Android,多媒體檔案(視頻和圖片)都是有縮圖的,在很多應用中,我們需要擷取這些縮圖。比如最近在做一個類似相簿的應用,需要掃描相簿裡面的圖片,然後擷取其縮圖,使用GridView去展示縮圖,當點擊之後,我們需要擷取其原始圖,所以相關的需求如下:

1)擷取縮圖(一個問題是:是否所有的圖片以及視頻都有縮圖?);

2)將縮圖和原始圖關聯起來;

 

關於1):

現在採用的方式是:

1 Options options=new Options();2 options.inSampleSize=32;3 Bitmap bitmap=BitmapFactory.decodeFile(url, options);4 Drawable drawable=new BitmapDrawable(bitmap);

但是這種方法有問題:很難把握inSampleSize的大小(這裡的32已經顯得非常誇張了,但是從相簿角度來說,圖片數量是以百或者千為單位的,並且我遇到的問題是我的圖片並不一樣大小,我從網上下載了一些小圖片到手機裡面,原先的大圖設定32沒有問題,但是小圖卻明顯太小了)。我很想知道Android系統是否能夠聰明的幫我做到縮減到合適的尺寸(另一個原因是:跳過縮圖我就必須自己寫一個函數遍曆所有的檔案夾尋找圖片格式的檔案,這大大降低了程式的效能)。下面研究直接提取縮圖。

提取圖片和視頻的縮圖可以直接存取: 

1 android.provider.MediaStore.Images.Thumbnails2 android.provider.MediaStore.Video.Thumbnails

這兩個資料庫,即可查詢出來縮圖(這是contentprovider,具體的解釋可見:【Android】ContentProvider)

之前我一直對Android在這方面的資料存放區非常感興趣,很想知道它是如何儲存這些資料以及我可以從資料裡面獲得什麼,今天將資料庫導了出來,查看了一下儲存,下面做出解釋:

大家可以先查看一下/data/data/com.android.provider.media目錄下面的databases:external-f042911.db 和 internal.db,

選中後,點擊右上方有個箭頭向左的圖案的表徵圖即可將資料庫匯出到電腦檔案夾中,然後下載一個SQLite資料庫查看軟體,我是在Mac下,下載的軟體名叫MesaSQLite ,之後開啟資料庫,我們來查看一下:

首先是external-f042911.db資料庫,這個資料庫裡面有很多表,如下:

這裡很明顯有兩個thumbnails表,我查看的就是thumbnails表格,下面是表格內容:

總共11張縮圖,我們可以看到每張縮圖除了有一個_id之外,還有一個image_id(這個是關鍵?)。

然後要看的表格當然就是images,這個Table Store的是什麼呢?如下,這個表表頭很長,我截取兩端:

這是第一張,可以看到什嗎??首先當然是同樣的_id欄位,這是和上面對應好的嗎??其次,我們可以找到圖片的大小,類型,名稱等屬性,最重要的是其絕對實體路徑!

這是第二張,是表格後面一段的屬性,這張圖上面最最重要的一個列就是"bucket_display_name",稍微對應一下我們就能發現這裡面記錄的是圖片所在的檔案夾(做相簿的時候是很需要這個的!)

然後我再查看兩個表:

第一個是albums表,這個表裡面是什麼呢?

這對我是個意外之喜,QIDUO是我建立的一個檔案夾,我在裡面儲存了一些檔案和一個amr錄音檔案,所以我就很好奇了,Android如何判定一個檔案夾為album呢?

再看一個表:audio_meta,更是一個驚喜:

這個神奇的表格裡面居然記錄了我錄製的amr音頻,大家看到木有啊?有絕對路徑,有尺寸,有時間長度!讓人非常驚訝!

所以,到現在我有如下幾個疑問:

1)是否所有的多媒體檔案(我指的是視頻和圖片)都有縮圖?

2)縮圖和原始圖是如何對應的?

3)album是如何定義的?

首先回答問題2):其實問題2)寫一個程式即可驗證,事實不是我們猜想的那樣,兩個_id欄位是對應的,而是:

表thumbnails和images通過thumbnails.image_id與images._id關聯的,通過images的_id,就可以找出來thumbnails表中的圖片和images表中圖片的映射關係了。原始圖片的位置就是images表中的_data欄位的值。

關於第1)個問題,我們貌似要瞭解一下,縮圖到底是如何?的?這裡有一個類:MediaScanner(詳細要研究可見:http://blog.csdn.net/zqiang_55/article/details/7060171 )這個類是負責掃描所有的圖片並將圖片儲存進入MediaStore(MediaScannerReceiver用來接收任務的,它收到廣播後,會啟動MediaService進行掃描工作。好複雜的樣子。。。)我插一張圖:

MediaScanner可以通過手動控制,在ANDROID系統中,已經定製了三種事件會觸發MediaScanner去掃描磁碟檔案:ACTION_BOOT_COMPLETED、ACTION_MEDIA_MOUNTED、 ACTION_MEDIA_SCANNER_SCAN_FILE。其中ACTION_BOOT_COMPLETED是系統啟動完後發出這個訊息,ACTION_MEDIA_MOUNTED是插卡事件觸發的訊息,ACTION_MEDIA_SCANNER_SCAN_FILE訊息一般是在一些檔案操作後,開發人員手動發出的一個重新掃描多媒體檔案的訊息。發送訊息通過sendBroadcast函數完成,比如廣播一個ACTION_MEDIA_MOUNTED訊息:

1 sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));

由上可知是通過發送了一個廣播(傳遞對應的掃描要求)來觸發重新掃描磁碟事件,那麼可以猜測系統肯定存在一個廣播接收器(何時何地註冊?),在收到這個廣播訊息後,通過對應參數啟動MediaScannerService。MediaScannerService調用一個公用類MediaScanner去處理真正的工作。MediaScannerReceiver維持兩種掃描目錄:一種是內部卷(internal volume)指向$(ANDROID_ROOT)/media. 另一種是外部卷(external volume)指向$(EXTERNAL_STORAGE),掃描的位置可以修改(一般外部不用修改,預設為SDCARD,內部根據驅動命名的INAND路經名做對應的修改)。

所以對於問題1),如果你儲存了圖片但是沒有啟動磁碟掃描,就會造成縮圖不全。

關於第三點待續~

代碼:

1)擷取縮圖:

 1 cr = getContentResolver(); 2 String[] projection = { Thumbnails._ID, Thumbnails.IMAGE_ID, Thumbnails.DATA }; 3 Cursor cursor = cr.query(Thumbnails.EXTERNAL_CONTENT_URI, projection, null, null, null); 4 getColumnData(cursor); 5  6 private void getColumnData(Cursor cur) { 7     if (cur.moveToFirst()) { 8         int _id; 9         int image_id;10         String image_path;11         int _idColumn = cur.getColumnIndex(Thumbnails._ID);12         int image_idColumn = cur.getColumnIndex(Thumbnails.IMAGE_ID);13         int dataColumn = cur.getColumnIndex(Thumbnails.DATA);14 15         do {16             // Get the field values17             _id = cur.getInt(_idColumn);18             image_id = cur.getInt(image_idColumn);19             image_path = cur.getString(dataColumn);20 21             // Do something with the values.22             Log.i(TAG, _id + " image_id:" + image_id + " path:"23                         + image_path + "---");24             HashMap<String, String> hash = new HashMap<String, String>();25             hash.put("image_id", image_id + "");26             hash.put("path", image_path);27             list.add(hash);28 29         } while (cur.moveToNext());30 31      }32 }

2)擷取實際圖片

 1 String columns[] = new String[] { Media.DATA, Media._ID, Media.TITLE, Media.DISPLAY_NAME, Media.SIZE };   2 // 得到一個遊標   3 cursor = this.getContentResolver().query(Media.EXTERNAL_CONTENT_URI, columns, null, null, null);   4 // 擷取指定列的索引   5 photoIndex = cursor.getColumnIndexOrThrow(Media.DATA);   6 photoNameIndex = cursor.getColumnIndexOrThrow(Media.DISPLAY_NAME);   7 photoIDIndex = cursor.getColumnIndexOrThrow(Media._ID);   8 photoTitleIndex = cursor.getColumnIndexOrThrow(Media.TITLE);   9 photoSizeIndex = cursor.getColumnIndexOrThrow(Media.SIZE);  10 // 擷取圖片總數  11 totalNum = cursor.getCount(); 

3)縮圖和原始圖的對應

 1 OnItemClickListener listener = new OnItemClickListener() {    2     @Override   3     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {   4         // TODO Auto-generated method stub   5         String image_id = list.get(position).get("image_id");   6         Log.i(TAG, "---(^o^)----" + image_id);   7        String[] projection = { Media._ID, Media.DATA };   8        Cursor cursor = cr.query(Media.EXTERNAL_CONTENT_URI, projection,   9                              Media._ID + "=" + image_id, null, null);  10        if (cursor != null) {  11            cursor.moveToFirst();  12            String path = cursor.getString(cursor.getColumnIndex(Media.DATA));  13            Intent intent = new Intent(ThumbnailActivity.this, ImageViewer.class);  14            intent.putExtra("path", path);  15            startActivity(intent);  16        } else {  17            Toast.makeText(ThumbnailActivity.this, "Image doesn't exist!",  18                                  Toast.LENGTH_SHORT).show();  19           }20       }  21 };

有關具體的縮圖可以通過getThumbnail(ContentResolver cr, long origId, int kind, BitmapFactory.Options options) 或getThumbnail(ContentResolver cr, long origId, long groupId, int kind, BitmapFactory.Options options) 方法擷取,這兩種方法返回Bitmap類型,而縮圖的解析度可以從HEIGHT和WIDTH兩個欄位提取,在Android上縮圖分為兩種,通過讀取
KIND欄位來獲得,分別為MICRO_KIND和MINI_KIND 分別為微型和迷你兩種縮減模式,前者的解析度更低。這樣我們平時擷取檔案系統的某個圖片預覽時,可以直接調用系統縮圖,而不用自己重新計算。

縮圖儲存在SD卡的DCIM目錄,裡面的.thumbnails是圖片的,而.video_thumbnails是視頻的,這兩個檔案夾為隱藏屬性。

從Android2.2開始系統新增了一個縮圖ThumbnailUtils類,位於framework的 android.media.ThumbnailUtils位置,可以協助我們從mediaprovider中擷取系統中的視頻或圖片檔案的縮圖,該類提供了三種靜態方法可以直接調用擷取。

1. static Bitmap createVideoThumbnail(String filePath, int kind)
//擷取視頻檔案的縮圖,第一個參數為視頻檔案的位置,比如/sdcard/android123.3gp,而第二個參數可以為MINI_KIND或 MICRO_KIND最終和解析度有關

2. static Bitmap extractThumbnail(Bitmap source, int width, int height, int options)
//直接對Bitmap進行縮減操作,最後一個參數定義為OPTIONS_RECYCLE_INPUT,來回收資源

3. static Bitmap extractThumbnail(Bitmap source, int width, int height)
// 這個和上面的方法一樣,無options選項

 http://www.cnblogs.com/lqminn/archive/2012/10/16/2726583.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.