76 votes

Trouver le type d'image à partir de NSData ou UIImage

Je charge une image à partir d'une URL fournie par un tiers. Il n'y a pas d'extension de fichier (ni de nom de fichier d'ailleurs) sur l'URL (car il s'agit d'une URL masquée). Je peux prendre les données de cette image (sous la forme de NSData), les charger dans une UIImage et les afficher correctement.

Je veux faire persister ces données dans un fichier. Cependant, je ne sais pas dans quel format sont les données (PNG, JPG, BMP) ? Je suppose qu'il s'agit de JPG (puisqu'il s'agit d'une image provenant du Web), mais existe-t-il un moyen programmatique de le savoir avec certitude ? J'ai cherché sur StackOverflow et dans la documentation, mais je n'ai rien trouvé.

TIA.


Edit : Ai-je vraiment besoin de l'extension du fichier ? Je le persiste vers un stockage externe (Amazon S3) mais en considérant qu'il sera toujours utilisé dans le contexte d'iOS ou d'un navigateur (qui semblent tous deux bien interpréter les données sans extension) peut-être que ce n'est pas un problème.

0 votes

Pourquoi avez-vous besoin de savoir ? Si l'UIImage l'affiche bien, je ne vois pas pourquoi vous ne pourriez pas le conserver sans l'extension.

1 votes

L'image sera également affichée sur un site web à l'avenir. Je constate maintenant que les navigateurs peuvent afficher correctement l'image brute (sans extension de fichier).

146voto

wl. Points 915

Si vous disposez de NSData pour le fichier image, 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;
}

4 votes

Existe-t-il une solution équivalente pour identifier le type de fichiers d'autres types ... tels que rtf, mov, mp3 ?

5 votes

Cela ne m'aide pas en cas d'identification d'un objet UIImage. Pour extraire les NSData d'une UIImage, je dois utiliser soit UIImagePNGRepresentation() soit UIImageJPEGRepresentation() qui convertit les imageData par lui-même.

0 votes

Malheureusement, UIImage ne fournit pas d'accès au contexte de l'image - vous ne serez pas en mesure de déterminer le type d'image sans référence au flux d'octets d'origine.

29voto

akashivskyy Points 11508

Améliorer la situation réponse de wl. Si l'on ne peut pas prédire le type MIME de l'image, voici une méthode beaucoup plus étendue et précise pour prédire le type MIME de l'image à partir de la signature. Le code est largement inspiré de la fonction 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

}

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

  • image/x-ms-bmp (bmp)
  • image/gif (gif)
  • image/jpeg (jpg, jpeg)
  • image/psd (psd)
  • image/iff (si)
  • image/webp (webp)
  • image/vnd.microsoft.icon (ico)
  • image/tiff (tif, tiff)
  • image/png (png)
  • image/jp2 (jp2)

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

16voto

ccoroom Points 370

La solution de @Tai Le pour Swift 3 consiste à assigner des données entières dans un tableau d'octets. Si une image est grande, elle peut provoquer un crash. Cette solution n'assigne qu'un 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
    }
}

9voto

Dave DeLong Points 156978

Si vous récupérez l'image à partir d'une URL, vous pouvez probablement inspecter les en-têtes de réponse HTTP. Est-ce que le Content-Type contient quelque chose d'utile ? (J'imagine que oui, puisqu'un navigateur serait probablement capable d'afficher l'image correctement, et qu'il ne pourrait le faire que si le type de contenu était correctement défini).

0 votes

Oh oui. Je n'avais pas pensé à ça ! Bonne idée.

7voto

Tai Le Points 2489

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X