2010-11-10 16 views
60

Sto caricando un'immagine da un URL fornito da una terza parte. Non esiste un'estensione di file (o un nome file) sull'URL (poiché è un URL oscurato). Posso prendere i dati da questo (sotto forma di NSData) e caricarli in una UIImage e visualizzarli bene.Ricerca del tipo di immagine da NSData o UIImage

Voglio mantenere questi dati su un file. Tuttavia, non so in che formato sono i dati (PNG, JPG, BMP)? Presumo che sia JPG (dal momento che è un'immagine dal web) ma c'è un modo programmatico per scoprirlo di sicuro? Ho guardato in giro StackOverflow e alla documentazione e non sono stato in grado di trovare nulla.

TIA.


Modifica: ho davvero bisogno dell'estensione del file? Lo sto persistendo su un archivio esterno (Amazon S3) ma considerando che verrà sempre utilizzato nel contesto di iOS o di un browser (entrambi sembrano perfettamente utili nell'interpretazione dei dati senza un'estensione) forse questo è un non-problema .

+0

Perché è necessario sapere? Se la UIImage lo visualizza bene, non vedo un motivo per cui non puoi persistere senza l'estensione. – kennytm

+0

L'immagine verrà anche visualizzata su un sito Web in futuro. Vedo, ora, che i browser possono visualizzare correttamente l'immagine grezza (senza un'estensione di file). – pschang

risposta

137

Se avete NSData per il file di immagine, allora si può indovinare il tipo di contenuto, cercando in primo byte:

+ (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

Grande truffatore. davvero aiutato !! Mantenere il buon lavoro. –

+0

Soluzione perfetta. Grazie! – marimba

+0

Fantastico, ne avevo tanto bisogno! – theory

8

Se si sta recuperando l'immagine da un URL, presumibilmente è possibile ispezionare le intestazioni delle risposte HTTP. L'intestazione Content-Type contiene qualcosa di utile? (Immagino che sarebbe in quanto un browser sarebbe probabilmente in grado di visualizzare correttamente l'immagine, e potrebbe farlo solo se il tipo di contenuto fosse impostato correttamente)

+0

Oh sì. Non ci avevo pensato! Buona idea. – pschang

1

Se è davvero importante per te, credo che tu possa devo esaminare il filmato. Un JPEG inizierà con i byte FF D8. Un PNG inizierà con 89 50 4E 47 0D 0A 1A 0A. Non so se BMP abbia un'intestazione simile, ma non penso che tu abbia troppe probabilità di imbatterti in quelli sul web nel 2010.

Ma è davvero importante per te? Non puoi semplicemente trattarlo come un'immagine sconosciuta e lasciare che Cocoa Touch faccia il lavoro?

+0

Beh, lo sto memorizzando su una terza parte (Amazon S3) e alla fine intendo di usare questa immagine anche su un sito web. Anche se, ora che lo faccio funzionare, vedo che il browser sa come rendere l'immagine indipendentemente da un'estensione di file. E sappiamo che a UIImage di iOS non importa. Quindi forse non importa? – pschang

+0

La mia ipotesi è che non ha importanza, ma se ti interessa che IE faccia la cosa giusta per i file senza estensioni, dovresti probabilmente testarlo anche tu. –

0

implementare un controllo di firma per ogni formato di immagine conosciuta. Ecco una rapida funzione di Objective-C che lo fa per i dati 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

Migliorare su wl.'s answer, ecco un modo molto più esteso e precisi per prevedere il tipo MIME dell'immagine in base alla firma. Il codice è stato in gran parte ispirato da php ext/standard/image.c.

- (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 

} 

Il metodo sopra riconosce i seguenti tipi di immagine:

  • 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)

Purtroppo, non v'è alcun modo semplice per ottenere questo tipo di informazioni da un'istanza UIImage, poiché non è possibile accedere ai dati bitmap incapsulati.

+0

Grande lista, grazie. Sto avendo problemi con il nuovo tipo di immagine .heic utilizzato in iOS11. Potresti aggiornare la tua risposta per includere questo nuovo tipo? – alfonso

5

Swift3 versione: 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

Un'alternativa di risposta accettata è il controllo di immagine con image I/O frameWork. È possibile ottenere il tipo di immagine UTI. provare questo:

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

Per esempio, UTI un'immagine GIF di un è "com.compuserve.gif" e UTI immagine di PNG è "public.png" .ma non è possibile ottenere UTI da un'immagine che image I/O frameWork doesn' t riconosciuto.

6

@Tai Le's solution per Swift 3 sta assegnando interi dati in serie di byte. Se un'immagine grande, può causare crash. Questa soluzione assegna solo un singolo byte:

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

Perfetto, grazie! – BEm