Encontrar el tipo de imagen de NSData o UIImage

Estoy cargando una imagen desde una URL proporcionada por un tercero. No hay una extensión de archivo (o nombre de archivo para el caso) en la URL (ya que es una URL oscurecida). Puedo tomar los datos de esto (en forma de NSData) y cargarlo en un UIImage y mostrarlo bien.

Quiero persistir esta información en un archivo. Sin embargo, no sé en qué formato están los datos (PNG, JPG, BMP)? Supongo que es JPG (ya que es una imagen de la web), pero ¿hay alguna manera programática de averiguarlo con certeza? He buscado en StackOverflow y en la documentación y no he podido encontrar nada.

TIA.


Editar: ¿Realmente necesito la extensión de archivo? Lo estoy persistiendo en un almacenamiento externo (Amazon S3) pero teniendo en cuenta que siempre se utilizará en el contexto de iOS o un navegador (ambos parecen estar bien para interpretar los datos sin una extensión), quizás esto no sea un problema. .

Si tiene NSData para el archivo de imagen, puede adivinar el tipo de contenido mirando el primer 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; } 

Mejorando la respuesta de wl. , Aquí hay una manera mucho más amplia y precisa de predecir el tipo MIME de la imagen en función de la firma. El código fue inspirado en gran medida por ext / standard / image.c de 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 } 

El método anterior reconoce los siguientes tipos de imágenes:

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

Desafortunadamente, no hay una forma simple de obtener este tipo de información de una instancia de UIImage , porque no se puede acceder a sus datos de bitmap encapsulados.

Si está recuperando la imagen de una URL, es de suponer que puede inspeccionar los encabezados de respuesta HTTP. ¿ Content-Type encabezado Content-Type contiene algo útil? (Me imagino que lo haría ya que un navegador probablemente podría mostrar la imagen correctamente, y solo podría hacerlo si el tipo de contenido estuviera configurado adecuadamente)

La solución de @Tai Le para Swift 3 está asignando datos completos en una matriz de bytes. Si una imagen es grande, puede causar un locking. Esta solución simplemente asigna un solo 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 } } 

La versión Swift3:

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

Si realmente le importa a usted, creo que tendrá que examinar la stream secundaria. Un JPEG comenzará con los bytes FF D8. Un PNG comenzará con 89 50 4E 47 0D 0A 1A 0A. No sé si BMP tiene un encabezado similar, pero no creo que sea demasiado probable que te encuentres con aquellos en la web en 2010.

Pero, ¿realmente te importa? ¿No puedes tratarlo como una imagen desconocida y dejar que Cocoa Touch haga el trabajo?

Una alternativa de respuesta aceptada es verificar la UTI de la image I/O frameWork con la image I/O frameWork . Puede lograr el tipo de imagen de UTI. prueba esto:

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

Por ejemplo, una UTI de una imagen GIF es “com.compuserve.gif” y la UTI de la imagen PNG es “public.png”. PERO no puede lograr UTI a partir de la imagen que la image I/O frameWork no reconoce.

Implemente una verificación de firma para cada formato de imagen conocido. Aquí hay una función rápida de Objective-C que hace eso para datos 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; } 

Hice una biblioteca para verificar el tipo de imagen de NSData:

https://github.com/sweetmandm/ImageFormatInspector