从NSData或UIImage中查找图像types

我从第三方提供的URL加载图像。 URL上没有文件扩展名(或文件名)(因为它是一个模糊的URL)。 我可以从这个数据(以NSData的forms),并加载到一个UIImage,并显示它很好。

我想将这些数据保存到一个文件中。 但是,我不知道数据格式是什么(PNG,JPG,BMP)? 我认为它是JPG(因为它是一个来自networking的图像),但有没有一个编程的方式来找出肯定? 我查看过周围的StackOverflow和文档,一直没能find任何东西。

TIA。


编辑:我真的需要文件扩展名? 我坚持到外部存储(亚马逊S3),但考虑到它将始终用于iOS或浏览器的环境中(这两者在解释数据时都没有扩展名,似乎很好),但这可能不是问题。

如果您有图像文件的NSData,那么您可以通过查看第一个字节来猜测内容types:

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

根据wl。的答案改进,这里有一个更加扩展和精确的方法来预测基于签名的图像的MIMEtypes。 代码很大程度上受到了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 } 

上述方法可识别以下图像types:

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

不幸的是,没有简单的方法从UIImage实例获取这种信息,因为它的封装的位图数据不能被访问。

如果您从URL中检索图像,那么大概您可以检查HTTP响应标头。 Content-Type头是否包含有用的东西? (我想可能是因为浏览器可能能够正确显示图像,而且只能这样做,如果内容types被适当地设置)

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

@Tai Le的Swift 3的解决scheme是将整个数据分配到字节数组中。 如果图像大,可能会导致崩溃。 这个解决scheme只分配单个字节:

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

如果真的对你很重要,我相信你必须检查字节stream。 JPEG将以字节FF D8开始。 一个PNG将以89 50 4E 47 0D 0A 1A 0A开始。 我不知道BMP是否有类似的标题,但我不认为你有可能在2010年遇到networking上的那些人。

但这对你真的很重要吗? 你不能把它当作一个未知的形象,让cocoa触摸做这个工作吗?

对每个已知的图像格式执行签名检查。 下面是一个快速的Objective-C函数,可以为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; } 

我做了一个库来检查NSData的图像types:

https://github.com/sweetmandm/ImageFormatInspector

接受的答案的替代scheme是使用image I/O frameWork检查图像的UTI。 你可以实现图像types的formsUTI。 尝试这个:

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

例如,GIF图像的UTI是“com.compuserve.gif”,而PNG图像的UTI是“public.png”,但是您无法从image I/O frameWork无法识别的image I/O frameWork获得UTI。