iOS 下載圖片前如何預取圖片的大小

最近練習做一個微博的項目,看到新浪微博的圖片其實是可以根據圖片的大小進行預覽區域大小的設置,如果固定區域大小有時候會導致圖片變形比較難看。google了很久,一直沒有找到答案,如果是打圖片的大小單獨對應一組數據然後放在微博的json數據中返回過來,那麼也好解決,但是微博並沒有提供這樣的接口。後來我又想是否有這樣的請求命令可以直接索取圖片的大小,那樣的話我也可以不用加載完圖片才能知道圖片的大小。可惜也沒找到這樣的命令。

  後來我覺得從最原始的方式開始探索,我覺得圖片就是文件,文件就有文件頭,一般的文件頭裏面都會有文件的一些常規信息,可能也包括圖片的大小。所以,我在數據請求的時候,第一次請求文件頭的數據或是更精確的話得到圖片大小所對應的字段的數據,那麼整個包可能只需要很少的字節就能得到圖片的大小,有了圖片得大小,我們就能設置預覽區域的大小。

  但是,還有一個問題,圖片有很多種格式,所以文件頭肯定是不一樣的,沒辦法這裏我是根據URL請求的後綴名進行區分的。後續我測試了下,微博圖片主要就jpg和gif兩種格式,然後我再加上常用的png格式,這個demo中我就是分析典型的三種圖片格式。

  首先,對於這三種格式,大家可以百度下,會有比較詳細的格式介紹,當然很多內容我們並不需要,這裏我們只要知道圖片大小所在的據數段的位置即可。

  具體格式的信息我這邊就不描述了,百度就很容易的查到。

  當然jpg格式有點複雜,因爲我在測試的時候,圖片大小所在的字段位置是不固定的,所以會麻煩些,具體見Demo中的分析。

png的分析,png格式圖片大小的字段是在16-23,所以請求的時候只需要請求8字節即可(是不是很小)


複製代碼
  1. - (void)downloadPngImage
  2. {
  3.     NSString *URLString = @"http://img2.3lian.com/img2007/13/29/20080409094710646.png";
  4.     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:URLString]];
  5.     [request setValue:@"bytes=16-23" forHTTPHeaderField:@"Range"];
  6.     [[NSURLConnection connectionWithRequest:request delegate:self] start];
  7. }


對應的每一位都需要進行轉化,就能得到具體的數值

複製代碼
  1. - (CGSize)pngImageSizeWithHeaderData:(NSData *)data
  2. {
  3.     int w1 = 0, w2 = 0, w3 = 0, w4 = 0;
  4.     [data getBytes:&w1 range:NSMakeRange(0, 1)];
  5.     [data getBytes:&w2 range:NSMakeRange(1, 1)];
  6.     [data getBytes:&w3 range:NSMakeRange(2, 1)];
  7.     [data getBytes:&w4 range:NSMakeRange(3, 1)];
  8.     int w = (w1 << 24) + (w2 << 16) + (w3 << 8) + w4;
  9.     int h1 = 0, h2 = 0, h3 = 0, h4 = 0;
  10.     [data getBytes:&h1 range:NSMakeRange(4, 1)];
  11.     [data getBytes:&h2 range:NSMakeRange(5, 1)];
  12.     [data getBytes:&h3 range:NSMakeRange(6, 1)];
  13.     [data getBytes:&h4 range:NSMakeRange(7, 1)];
  14.     int h = (h1 << 24) + (h2 << 16) + (h3 << 8) + h4;
  15.     return CGSizeMake(w, h);
  16. }


jpg格式比較複雜所以先得了解清楚具體個字段的意思

因爲圖片大小所在的字段區域不確定,所以我們要擴大請求範圍

這裏209字節裏面應該就已經包含全了所有的數據(這裏我查了一些資料,也看了幾個不同jpg的文件頭16進制信息)

不一定就完全正確,但是分析微博的jpg圖片大小暫時沒有什麼問題

複製代碼
  1. - (void)downloadJpgImage
  2. {
  3.     NSString *URLString = @"http://ww3.sinaimg.cn/thumbnail/673c0421jw1e9a6au7h5kj218g0rsn23.jpg";
  4.     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:URLString]];
  5.     [request setValue:@"bytes=0-209" forHTTPHeaderField:@"Range"];
  6.     [[NSURLConnection connectionWithRequest:request delegate:self] start];
  7. }



複製代碼
  1. - (CGSize)jpgImageSizeWithHeaderData:(NSData *)data
  2. {
  3.     if ([data length] <= 0x58) {
  4.         return CGSizeZero;
  5.     }
  6.     if ([data length] < 210) {// 肯定只有一個DQT字段
  7.         short w1 = 0, w2 = 0;
  8.         [data getBytes:&w1 range:NSMakeRange(0x60, 0x1)];
  9.         [data getBytes:&w2 range:NSMakeRange(0x61, 0x1)];
  10.         short w = (w1 << 8) + w2;
  11.         short h1 = 0, h2 = 0;
  12.         [data getBytes:&h1 range:NSMakeRange(0x5e, 0x1)];
  13.         [data getBytes:&h2 range:NSMakeRange(0x5f, 0x1)];
  14.         short h = (h1 << 8) + h2;
  15.         return CGSizeMake(w, h);
  16.     } else {
  17.         short word = 0x0;
  18.         [data getBytes:&word range:NSMakeRange(0x15, 0x1)];
  19.         if (word == 0xdb) {
  20.             [data getBytes:&word range:NSMakeRange(0x5a, 0x1)];
  21.             if (word == 0xdb) {// 兩個DQT字段
  22.                 short w1 = 0, w2 = 0;
  23.                 [data getBytes:&w1 range:NSMakeRange(0xa5, 0x1)];
  24.                 [data getBytes:&w2 range:NSMakeRange(0xa6, 0x1)];
  25.                 short w = (w1 << 8) + w2;
  26.                 short h1 = 0, h2 = 0;
  27.                 [data getBytes:&h1 range:NSMakeRange(0xa3, 0x1)];
  28.                 [data getBytes:&h2 range:NSMakeRange(0xa4, 0x1)];
  29.                 short h = (h1 << 8) + h2;
  30.                 return CGSizeMake(w, h);
  31.             } else {// 一個DQT字段
  32.                 short w1 = 0, w2 = 0;
  33.                 [data getBytes:&w1 range:NSMakeRange(0x60, 0x1)];
  34.                 [data getBytes:&w2 range:NSMakeRange(0x61, 0x1)];
  35.                 short w = (w1 << 8) + w2;
  36.                 short h1 = 0, h2 = 0;
  37.                 [data getBytes:&h1 range:NSMakeRange(0x5e, 0x1)];
  38.                 [data getBytes:&h2 range:NSMakeRange(0x5f, 0x1)];
  39.                 short h = (h1 << 8) + h2;
  40.                 return CGSizeMake(w, h);
  41.             }
  42.         } else {
  43.             return CGSizeZero;
  44.         }
  45.     }
  46. }


gif的分析和png差不多,不過這裏得到得應該是第一張圖片的大小

複製代碼
  1. - (void)downloadGifImage
  2. {
  3.     NSString *URLString = @"http://img4.21tx.com/2009/1116/92/20392.gif";
  4.     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:URLString]];
  5.     [request setValue:@"bytes=6-9" forHTTPHeaderField:@"Range"];
  6.     [[NSURLConnection connectionWithRequest:request delegate:self] start];
  7. }



複製代碼
  1. - (CGSize)gifImageSizeWithHeaderData:(NSData *)data
  2. {
  3.     short w1 = 0, w2 = 0;
  4.     [data getBytes:&w1 range:NSMakeRange(0, 1)];
  5.     [data getBytes:&w2 range:NSMakeRange(1, 1)];
  6.     short w = w1 + (w2 << 8);
  7.     short h1 = 0, h2 = 0;
  8.     [data getBytes:&h1 range:NSMakeRange(2, 1)];
  9.     [data getBytes:&h2 range:NSMakeRange(3, 1)];
  10.     short h = h1 + (h2 << 8);
  11.     return CGSizeMake(w, h);
  12. }




Github Demo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章