Finding image type from NSData or UIImage
If you're retrieving the image from a URL, then presumably you can inspect the HTTP response headers. Does the Content-Type
header contain anything useful? (I'd imagine it would since a browser would probably be able to display the image correctly, and it could only do that if the content type were appropriately set)
Improving upon wl.'s answer, here's a much more extended and precise way to predict the image's MIME type based on the signature. The code was largely inspired by php's 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
}
The above method recognizes the following image 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)
Unfortunately, there is no simple way to get this kind of information from a UIImage
instance, because its encapsulated bitmap data cannot be accessed.
If you have NSData for the image file, then you can guess at the content type by looking at the first 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;
}
@Tai Le's solution for Swift 3 is assigning whole data into byte array. If an image large, it can cause crash. This solution just assigns single 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
}
}