Wyszukiwanie typu obrazu z Nsdata lub UIImage

Ładuję obraz z adresu URL dostarczonego przez stronę trzecią. Nie ma rozszerzenia pliku (lub nazwy pliku w tym przypadku) na adresie URL (ponieważ jest to zasłonięty adres URL). Mogę pobrać dane z tego (w postaci NSData) i załadować je do UIImage i wyświetlić go dobrze.

Chcę zapisać te dane do pliku. Nie wiem jednak w jakim formacie są dane (PNG, JPG, BMP)? Zakładam, że jest to JPG (bo to obrazek z sieci), ale czy jest jakiś programowy sposób na upewnienie się na pewno? Ja rozejrzałem się po StackOverflow i po dokumentacji i nie mogłem nic znaleźć.

TIA.


Edit: czy naprawdę potrzebuję rozszerzenia pliku? Utrzymuję go na zewnętrznej pamięci masowej (Amazon S3), ale biorąc pod uwagę, że zawsze będzie używany w kontekście iOS lub przeglądarki (obaj wydają się dobrze interpretować dane bez rozszerzenia), być może nie jest to problem.

Author: pschang, 2010-11-10

9 answers

Jeśli masz NSData dla pliku obrazu, możesz odgadnąć typ zawartości patrząc na pierwszy bajt:

+ (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;
}
 140
Author: wl.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-18 14:20:03

Poprawa po wl.odpowiedź , Oto znacznie bardziej rozbudowany i precyzyjny sposób przewidywania typu MIME obrazu na podstawie podpisu. Kod został w dużej mierze zainspirowany przez 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

}

Powyższa metoda rozpoznaje następujące typy obrazów:

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

Niestety, nie ma prostego sposobu na uzyskanie tego rodzaju informacji z instancji UIImage, ponieważ nie można uzyskać do niej dostępu.

 21
Author: akashivskyy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:10

Jeśli pobierasz obraz z adresu URL, prawdopodobnie możesz sprawdzić nagłówki odpowiedzi HTTP. Czy nagłówek Content-Type zawiera coś użytecznego? (Wyobrażam sobie, że tak będzie, ponieważ przeglądarka prawdopodobnie byłaby w stanie poprawnie wyświetlić obraz i mogłaby to zrobić tylko wtedy, gdy typ treści byłby odpowiednio ustawiony)

 8
Author: Dave DeLong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-10 17:44:54

@Tai le rozwiązaniem dla Swift 3 jest przypisanie całych danych do tablicy bajtów. Jeśli obraz jest duży, może spowodować awarię. Rozwiązanie to przypisuje tylko jeden bajt:

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
Author: ccoroom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-06 09:18:13

Wersja 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
    }
}
 5
Author: Tai Le,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-29 08:01:32

Jeśli to naprawdę ma dla Ciebie znaczenie, sądzę, że będziesz musiał zbadać bajt. JPEG zaczyna się od bajtów FF D8. PNG zacznie się od 89 50 4E 47 0D 0A 1a 0a. Nie wiem, czy BMP ma podobny nagłówek, ale nie sądzę, aby w 2010 roku można było na nie natrafić.

Ale czy to naprawdę ma dla Ciebie znaczenie? Nie możesz po prostu traktować tego jako nieznanego obrazu i pozwolić Cocoa Touch wykonać pracę?

 1
Author: Steven Fisher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-10 17:45:49

Alternatywą zaakceptowanej odpowiedzi jest sprawdzenie UTI obrazu za pomocą image I/O frameWork. Możesz uzyskać formularz UTI typu obrazu. spróbuj tego:

CGImageSourceRef imgSrc = CGImageSourceCreateWithData((CFDataRef)data, NULL);
NSString *uti = (NSString*)CGImageSourceGetType(imgSrc);
NSLog(@"%@",uti);
Na przykład UTI obrazu GIF to " com.compuserve.GIF "i PNG image' s UTI to " public.png".Ale nie można uzyskać UTI z obrazu, który image I/O frameWork nie jest rozpoznawany.
 1
Author: ooOlly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-29 12:55:32

Zaimplementuj sprawdzanie podpisu dla każdego znanego formatu obrazu. Oto szybka funkcja Objective-C, która robi to dla danych 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;
}
 0
Author: MoDJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-09 20:46:19

Zrobiłem bibliotekę, aby sprawdzić typ obrazu NSData:

Https://github.com/sweetmandm/ImageFormatInspector

 0
Author: jankins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-26 15:15:00