2010-11-10 23 views
60

Tôi đang tải hình ảnh từ URL do bên thứ ba cung cấp. Không có phần mở rộng tệp (hoặc tên tệp cho vấn đề đó) trên URL (vì nó là một URL bị che khuất). Tôi có thể lấy dữ liệu từ này (dưới dạng NSData) và tải nó vào một UIImage và hiển thị nó tốt.Tìm loại hình ảnh từ NSData hoặc UIImage

Tôi muốn lưu dữ liệu này vào một tệp. Tuy nhiên, tôi không biết định dạng dữ liệu trong (PNG, JPG, BMP) là gì? Tôi giả sử nó là JPG (vì nó là một hình ảnh từ web) nhưng có một cách lập trình để tìm ra chắc chắn? Tôi đã nhìn xung quanh StackOverflow và tại các tài liệu và đã không thể tìm thấy bất cứ điều gì.

TIA.


Chỉnh sửa: Tôi có thực sự cần phần mở rộng tệp không? Tôi kiên trì nó với một lưu trữ ngoài (Amazon S3) nhưng xem xét nó sẽ luôn được sử dụng trong ngữ cảnh của iOS hoặc trình duyệt (cả hai đều có vẻ tốt trong việc giải thích dữ liệu mà không có phần mở rộng) có lẽ đây không phải là vấn đề .

+0

Tại sao bạn cần biết? Nếu UIImage hiển thị tốt, tôi không thấy lý do tại sao bạn không thể duy trì nó mà không có phần mở rộng. – kennytm

+0

Hình ảnh cũng sẽ được hiển thị trên trang web trong tương lai. Tôi thấy, bây giờ, các trình duyệt có thể hiển thị hình ảnh thô (không có phần mở rộng tệp) một cách chính xác. – pschang

Trả lời

137

Nếu bạn có NSData cho các tập tin hình ảnh, sau đó bạn có thể đoán ở kiểu nội dung bằng cách nhìn vào byte đầu tiên:

+ (NSString *)contentTypeForImageData:(NSData *)data { 
    uint8_t c; 
    [data getBytes:&c length:1]; 

    switch (c) { 
    case 0xFF: 
     return @"image/jpeg"; 
    case 0x89: 
     return @"image/png"; 
    case 0x47: 
     return @"image/gif"; 
    case 0x49: 
    case 0x4D: 
     return @"image/tiff"; 
    } 
    return nil; 
} 
+2

Great trick man. thực sự đã giúp !! Hãy tiếp tục phát huy. –

+0

Giải pháp hoàn hảo. Cảm ơn! – marimba

+0

Tuyệt vời, tôi rất cần điều này! – theory

8

Nếu bạn đang truy xuất hình ảnh từ URL, có thể bạn có thể kiểm tra tiêu đề phản hồi HTTP. Đầu đề Content-Type có chứa bất kỳ điều gì hữu ích không? (Tôi sẽ tưởng tượng nó sẽ xảy ra vì một trình duyệt có thể sẽ hiển thị hình ảnh một cách chính xác, và nó chỉ có thể làm điều đó nếu loại nội dung được đặt thích hợp)

+0

Ồ vâng. Tôi đã không nghĩ về điều này! Ý tưởng tốt. – pschang

1

Nếu nó thực sự quan trọng với bạn, tôi tin rằng bạn sẽ phải kiểm tra bytestream. JPEG sẽ bắt đầu bằng byte FF D8. PNG sẽ bắt đầu với 89 50 4E 47 0D 0A 1A 0A. Tôi không biết liệu BMP có tiêu đề tương tự hay không, nhưng tôi không nghĩ rằng bạn quá có khả năng chạy vào các trang web đó trong năm 2010.

Nhưng điều đó có thực sự quan trọng đối với bạn không? Bạn không thể coi nó như một hình ảnh không rõ và để Cocoa Touch làm công việc?

+0

Tôi đang lưu trữ nó trên một bên thứ ba (Amazon S3) và cuối cùng cũng có ý định sử dụng hình ảnh này trên một trang web. Mặc dù, bây giờ tôi có nó làm việc, tôi thấy rằng trình duyệt biết làm thế nào để kết xuất hình ảnh bất kể phần mở rộng tập tin. Và chúng tôi biết UIImage của iOS không quan tâm. Vì vậy, có lẽ nó không quan trọng? – pschang

+0

Đoán của tôi là nó không quan trọng, nhưng nếu bạn quan tâm đến IE làm điều đúng với các tập tin mà không có phần mở rộng, bạn có lẽ nên kiểm tra nó là tốt. –

0

Thực hiện một kiểm tra chữ ký cho mỗi định dạng hình ảnh nổi tiếng. Đây là một chức năng Objective-C nhanh chóng nào đó cho dữ liệu PNG:

// Verify that NSData contains PNG data by checking the signature 

- (BOOL) isPNGData:(NSData*)data 
{ 
    // Verify that the PNG file signature matches 

    static const 
    unsigned char png_sign[8] = {137, 80, 78, 71, 13, 10, 26, 10}; 

    unsigned char sig[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 

    if ([data length] <= 8) { 
    return FALSE; 
    } 

    [data getBytes:&sig length:8]; 

    BOOL same = (memcmp(sig, png_sign, 8) == 0); 

    return same; 
} 
18

Việc cải thiện wl.'s answer, đây là một cách nhiều hơn nữa mở rộng và chính xác để dự đoán kiểu MIME của hình ảnh dựa trên chữ ký. Mã này phần lớn được lấy cảm hứng từ số ext/standard/image.c của php.

- (NSString *)mimeTypeByGuessingFromData:(NSData *)data { 

    char bytes[12] = {0}; 
    [data getBytes:&bytes length:12]; 

    const char bmp[2] = {'B', 'M'}; 
    const char gif[3] = {'G', 'I', 'F'}; 
    const char swf[3] = {'F', 'W', 'S'}; 
    const char swc[3] = {'C', 'W', 'S'}; 
    const char jpg[3] = {0xff, 0xd8, 0xff}; 
    const char psd[4] = {'8', 'B', 'P', 'S'}; 
    const char iff[4] = {'F', 'O', 'R', 'M'}; 
    const char webp[4] = {'R', 'I', 'F', 'F'}; 
    const char ico[4] = {0x00, 0x00, 0x01, 0x00}; 
    const char tif_ii[4] = {'I','I', 0x2A, 0x00}; 
    const char tif_mm[4] = {'M','M', 0x00, 0x2A}; 
    const char png[8] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a}; 
    const char jp2[12] = {0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a}; 


    if (!memcmp(bytes, bmp, 2)) { 
     return @"image/x-ms-bmp"; 
    } else if (!memcmp(bytes, gif, 3)) { 
     return @"image/gif"; 
    } else if (!memcmp(bytes, jpg, 3)) { 
     return @"image/jpeg"; 
    } else if (!memcmp(bytes, psd, 4)) { 
     return @"image/psd"; 
    } else if (!memcmp(bytes, iff, 4)) { 
     return @"image/iff"; 
    } else if (!memcmp(bytes, webp, 4)) { 
     return @"image/webp"; 
    } else if (!memcmp(bytes, ico, 4)) { 
     return @"image/vnd.microsoft.icon"; 
    } else if (!memcmp(bytes, tif_ii, 4) || !memcmp(bytes, tif_mm, 4)) { 
     return @"image/tiff"; 
    } else if (!memcmp(bytes, png, 8)) { 
     return @"image/png"; 
    } else if (!memcmp(bytes, jp2, 12)) { 
     return @"image/jp2"; 
    } 

    return @"application/octet-stream"; // default type 

} 

Các phương pháp trên nhận các loại hình ảnh sau đây:

  • image/x-ms-bmp (bmp)
  • image/gif (gif)
  • image/jpeg (jpg, jpeg)
  • image/psd (psd)
  • image/iff (iff)
  • image/webp (webp)
  • image/vnd.microsoft.icon (ico)
  • image/tiff (tif, tiff)
  • image/png (png)
  • image/jp2 (jp2)

Thật không may, không có cách nào đơn giản để có được loại thông tin này từ một cá thể UIImage, vì dữ liệu bitmap được đóng gói của nó không thể truy cập được.

+0

Danh sách tuyệt vời, cảm ơn. Tôi đang gặp sự cố với loại hình ảnh .heic mới được sử dụng trong iOS11. Bạn có thể cập nhật câu trả lời của mình để bao gồm loại mới này không? – alfonso

5

Swift3 phiên bản: UTI

let data: Data = UIImagePNGRepresentation(yourImage)! 

extension Data { 
    var format: String { 
     let array = [UInt8](self) 
     let ext: String 
     switch (array[0]) { 
     case 0xFF: 
      ext = "jpg" 
     case 0x89: 
      ext = "png" 
     case 0x47: 
      ext = "gif" 
     case 0x49, 0x4D : 
      ext = "tiff" 
     default: 
      ext = "unknown" 
     } 
     return ext 
    } 
} 
0

Một thay thế câu trả lời chấp nhận được kiểm tra hình ảnh với image I/O frameWork. Bạn có thể đạt được hình thức loại hình ảnh UTI. thử điều này:

CGImageSourceRef imgSrc = CGImageSourceCreateWithData((CFDataRef)data, NULL); 
NSString *uti = (NSString*)CGImageSourceGetType(imgSrc); 
NSLog(@"%@",uti); 

Ví dụ, UTI một hình ảnh GIF là "com.compuserve.gif" và UTI PNG hình ảnh là "public.png" .Nhưng bạn không thể đạt UTI so với hình ảnh mà image I/O frameWork doesn' t được công nhận.

6

@ Giải pháp của Lê Lê cho Swift 3 là gán toàn bộ dữ liệu vào mảng byte. Nếu một hình ảnh lớn, nó có thể gây ra sự cố. Giải pháp này chỉ gán một byte đơn:

import Foundation 

public extension Data { 
    var fileExtension: String { 
     var values = [UInt8](repeating:0, count:1) 
     self.copyBytes(to: &values, count: 1) 

     let ext: String 
     switch (values[0]) { 
     case 0xFF: 
      ext = ".jpg" 
     case 0x89: 
      ext = ".png" 
     case 0x47: 
      ext = ".gif" 
     case 0x49, 0x4D : 
      ext = ".tiff" 
     default: 
      ext = ".png" 
     } 
     return ext 
    } 
} 
+0

Hoàn hảo, cảm ơn! – BEm

Các vấn đề liên quan