Поиск типа изображения из NSData или UIImage - PullRequest
65 голосов
/ 10 ноября 2010

Я загружаю изображение с URL, предоставленного третьей стороной. В URL нет расширения файла (или имени файла) (так как это скрытый URL). Я могу взять данные из этого (в форме NSData) и загрузить их в UIImage и отобразить его нормально.

Я хочу сохранить эти данные в файле. Тем не менее, я не знаю, в каком формате данные (PNG, JPG, BMP)? Я предполагаю, что это JPG (так как это изображение из Интернета), но есть ли программный способ узнать наверняка? Я осмотрел StackOverflow и документацию и не смог ничего найти.

ТИА.


Редактировать: действительно ли мне нужно расширение файла? Я сохраняю его во внешнем хранилище (Amazon S3), но, учитывая, что он всегда будет использоваться в контексте iOS или браузера (оба из них кажутся хорошими в интерпретации данных без расширения), возможно, это не проблема .

Ответы [ 9 ]

142 голосов
/ 18 февраля 2011

Если у вас есть 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;
}
25 голосов
/ 28 декабря 2014

Улучшение ответа 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, потому что его инкапсулированные данные растрового изображения недоступны.

9 голосов
/ 06 апреля 2017

@ Решением Тай Ле для 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
    }
}
8 голосов
/ 10 ноября 2010

Если вы извлекаете изображение из URL, то, вероятно, вы можете проверить заголовки HTTP-ответа. Содержит ли заголовок Content-Type что-нибудь полезное? (Я полагаю, что так будет, потому что браузер, вероятно, сможет правильно отображать изображение, и он сможет сделать это только при правильной установке типа контента)

5 голосов
/ 29 октября 2016

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
    }
}
1 голос
/ 29 марта 2017

Альтернативой принятого ответа является проверка UTI изображения с помощью image I/O frameWork.Вы можете достичь изображения типа формы UTI.попробуйте это:

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

Например, UTI изображения GIF - это "com.compuserve.gif", а UTI изображения PNG - "public.png". НО вы не можете получить UTI из изображения, которое image I/O frameWork не распознается.

1 голос
/ 10 ноября 2010

Если это действительно имеет значение для вас, я думаю, вам придется изучить этот поток.JPEG начнется с байтов FF D8.PNG начнется с 89 50 4E 47 0D 0A 1A 0A.Я не знаю, есть ли у BMP аналогичный заголовок, но я не думаю, что вы слишком вероятно столкнетесь с тем в Интернете в 2010 году.

Но действительно ли это важно для вас?Разве вы не можете просто воспринимать это как неизвестное изображение и позволить Cocoa Touch делать всю работу?

0 голосов
/ 26 марта 2015

Я сделал библиотеку для проверки типа изображения NSData:

https://github.com/sweetmandm/ImageFormatInspector

0 голосов
/ 10 июня 2011

Реализация проверки подписи для каждого известного формата изображения. Вот быстрая функция 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;
}
...