Question

Je suis le chargement d'une image à partir d'une URL fournie par un tiers. Il n'y a pas d'extension de fichier (ou nom de fichier pour cette question) sur l'URL (comme il est une URL obscurci). Je peux prendre les données de cette (sous forme de NSData) et le charger dans un UIImage et l'afficher bien.

Je veux persister ces données dans un fichier. Cependant, je ne sais pas quel format les données sont dans (PNG, JPG, BMP)? Je suppose que c'est JPG (car il est une image à partir du Web), mais est-il un moyen de programmation de savoir à coup sûr? Je l'ai regardé autour StackOverflow et à la documentation et n'ont pas été en mesure de trouver quoi que ce soit.

TIA.


Edit: Ai-je vraiment besoin de l'extension de fichier? Je suis à un persistant stockage externe (Amazon S3), mais étant donné qu'il sera toujours utilisé dans le contexte d'iOS ou d'un navigateur (qui ont tous deux semblent très bien dans l'interprétation des données sans extension) peut-être cela est un non-problème .

Était-ce utile?

La solution

Si vous avez NSData pour le fichier d'image, alors vous pouvez deviner le type de contenu en regardant le premier octet:

+ (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;
}

Autres conseils

wl répondre à ., Voici beaucoup plus étendu et précis moyen de prédire le type MIME de l'image en fonction sur la signature. Le code a été largement inspiré par php de ext / image standard /. 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

}

La méthode ci-dessus reconnaît les types d'image suivants:

  • image/x-ms-bmp (bmp)
  • image/gif (GIF)
  • image/jpeg (jpg, jpeg)
  • image/psd (dsp)
  • image/iff (IFF)
  • image/webp (webp)
  • image/vnd.microsoft.icon (ico)
  • image/tiff (TIF, tiff)
  • image/png (.png)
  • image/jp2 (JP2)

Malheureusement, il n'y a pas moyen simple d'obtenir ce genre d'information à partir d'une instance de UIImage, parce que ses données bitmap encapsulées ne sont pas accessibles.

La solution de @Tai Le Swift 3 est l'attribution des données entières dans le tableau d'octets. Si une image grande, il peut causer l'accident. Cette solution affecte simplement seul octet:

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
    }
}

Si vous récupérez l'image à partir d'une URL, on peut supposer que vous pouvez inspecter les en-têtes de réponse HTTP. Est-ce que l'en-tête de Content-Type contient quelque chose d'utile? (J'imagine que ce serait depuis un navigateur serait probablement en mesure d'afficher l'image correctement, et il ne pouvait le faire que si le type de contenu a été réglé de manière appropriée)

Version 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
    }
}

Si cela est vraiment important pour vous, je crois que vous devrez examiner la bytestream. Un JPEG commence par les octets FF J8. Un PNG commencera par 89 50 4E 47 0D 0A 1A 0A. Je ne sais pas si BMP a un en-tête semblable, mais je ne pense pas que vous êtes trop susceptible de se heurter ceux sur le web en 2010.

Mais est-ce vraiment pour vous? Tu ne peux pas juste traiter comme une image inconnue et LET Cocoa Touch faire le travail?

Une alternative de réponse acceptée est la vérification UTI image avec image I/O frameWork. Vous pouvez obtenir le type de formulaire d'image UTI. essayez ceci:

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

Par exemple, une infection urinaire d'image GIF est "com.compuserve.gif" et UTI image PNG est "public.png" .mais vous ne pouvez pas obtenir une infection urinaire de l'image qui ne image I/O frameWork pas reconnu.

Mettre en œuvre une vérification de signature pour chaque format d'image connue. Voici une fonction Objective-C rapide qui fait que pour les données 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;
}

J'ai fait une bibliothèque pour vérifier le type d'image de NSData:

https://github.com/sweetmandm/ImageFormatInspector

Mon améliorée solution basée sur @ccoroom

//  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
        }
    }
}

Voici quelques exemples d'utilisation:

//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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top