Поиск типа изображения из NSData или UIImage
я загружаю изображение с URL-адреса, предоставленного третьей стороной. На URL-адресе нет расширения файла (или имени файла, если на то пошло) (поскольку это скрытый URL-адрес). Я могу взять данные из этого (в виде NSData) и загрузить его в UIImage и отобразить его нормально.
Я хочу сохранить эти данные в файл. Однако я не знаю, в каком формате находятся данные (PNG, JPG, BMP)? Я предполагаю, что это jpg (так как это картинка из интернета), но есть ли программный способ узнать для точно? Я осмотрел StackOverflow и документацию и не смог ничего найти.
ТИА.
Edit: мне действительно нужно расширение файла? Я сохраняю его на внешнем хранилище (Amazon S3), но учитывая, что он всегда будет использоваться в контексте iOS или браузера (оба из которых кажутся прекрасными в интерпретации данных без расширения), возможно, это не проблема.
9 ответов:
Если у вас есть NSData для файла изображения, то вы можете угадать тип контента, посмотрев на первый байт:
+ (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.'ы ответ, вот гораздо более расширенный и точный способ предсказать тип MIME изображения на основе подписи. Код был в значительной степени вдохновлен 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 }
вышеуказанный метод распознает следующие типы изображений:
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
заголовок содержит что-нибудь полезное? (Я бы предположил, что это так, поскольку браузер, вероятно, сможет правильно отображать изображение, и он может сделать это только в том случае, если тип контента будет установлен соответствующим образом)
решение@Tai Le для Swift 3-это назначение целых данных в массив байтов. Если изображение большое, это может вызвать сбой. Это решение просто назначает один байт:
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 } }
версия 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 } }
Если это действительно важно для вас, я считаю, что вам придется изучить bytestream. JPEG будет начинаться с байтов FF D8. PNG будет начинаться с 89 50 4E 47 0D 0A 1A 0A. я не знаю, имеет ли BMP аналогичный заголовок, но я не думаю, что вы слишком вероятно столкнетесь с ними в интернете в 2010 году.
но это действительно имеет значение для вас? Разве вы не можете просто относиться к нему как к неизвестному изображению и позволить Cocoa Touch делать работу?
альтернативой принятого ответа является проверка UTI изображения с помощью
image I/O frameWork
. Вы можете достичь типа изображения формы UTI. попробуйте это:CGImageSourceRef imgSrc = CGImageSourceCreateWithData((CFDataRef)data, NULL); NSString *uti = (NSString*)CGImageSourceGetType(imgSrc); NSLog(@"%@",uti);
например, UTI GIF-изображения - это " com.компьюсерв.gif "и PNG изображение UTI является" публичным.формат PNG."Но вы не можете достичь UTI из изображения, которое
image I/O frameWork
не признала.
выполнить проверку подписи для каждого известного формата изображения. Вот быстрая функция 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; }