Найти тип изображения из nsdata или uiimage
Вопрос
Я загружаю изображение из URL, предоставленного третьей стороной. На URL нет расширения файла (или имени файла или имени файла) (как это скрытый URL). Я могу принять данные из этого (в виде NSDATA) и загрузить ее в Uiimage и отобразить его в порядке.
Я хочу сохранить эти данные в файл. Тем не менее, я не знаю, в каком формате данных находится данные (PNG, JPG, BMP)? Я предполагаю, что это JPG (так как это изображение из Интернета), но есть ли программный способ узнать наверняка? Я посмотрел вокруг StackoverFlow и в документации и не смог ничего найти.
TIA.
Редактировать: Мне действительно нужно расширение файла? Я устанавливаю его на внешнее хранилище (Amazon S3), но учитывая, что он всегда будет использоваться в контексте iOS или браузера (оба из которых кажутся в порядке в интерпретации данных без расширения) Возможно, это не проблема Отказ
Решение
Если у вас есть 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 Image на основе подписи. Код был в значительной степени вдохновлен 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
(Гиф)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
экземпляр, потому что его инкапсулированные данные растропа не могут быть доступен.
Решение @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
}
}
Если вы извлекаете изображение с URL, то, по-видимому, вы можете проверить заголовки отклика HTTP. Делает Content-Type
Заголовок содержат что-нибудь полезное? (Я бы представил, что это будет, поскольку браузер, вероятно, сможет правильно отобразить изображение, и это может сделать только, если тип контента был надлежащим образом установлен)
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 сделать работу?
Альтернатива принятого ответа проверяет ITI изображения с image I/O frameWork
. Отказ Вы можете добиться типа Image Form UTI. попробуй это:
CGImageSourceRef imgSrc = CGImageSourceCreateWithData((CFDataRef)data, NULL);
NSString *uti = (NSString*)CGImageSourceGetType(imgSrc);
NSLog(@"%@",uti);
Например, UTI Gif Image - «Com.compuserve.gif», и UTI PNG Image's - «public.png». Но вы не можете достичь UTI из Image, который image I/O frameWork
не признается.
Реализуйте проверку подписи для каждого известного формата изображения. Вот функция быстрого объекта, которая делает это для данных 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:
Мое улучшенное решение на основе @ccroom
// Data+ImageContentType.swift
import Foundation
extension Data {
enum ImageContentType: String {
case jpg, png, gif, tiff, unknown
var fileExtension: String {
return self.rawValue
}
}
var imageContentType: ImageContentType {
var values = [UInt8](repeating: 0, count: 1)
self.copyBytes(to: &values, count: 1)
switch (values[0]) {
case 0xFF:
return .jpg
case 0x89:
return .png
case 0x47:
return .gif
case 0x49, 0x4D :
return .tiff
default:
return .unknown
}
}
}
Некоторые примеры использования:
//load some image
do {
let imageData = try Data(contentsOf: URL(string: "https://myServer/images/test.jpg")!)
} catch {
print("Unable to load image: \(error)")
}
//content type check
guard [Data.ImageContentType.jpg,
Data.ImageContentType.png].contains(imageData.imageContentType) else {
print("unsupported image type")
return
}
//set file extension
let image = "myImage.\(imageData.imageContentType.fileExtension)" //myImage.jpg