Determine MIME type from NSData?
Asked Answered
B

4

36

How would you determine the mime type for an NSData object? I plan to have the user to upload a video/picture from their iPhone and have that file be wrapped in a NSData class.

I was wondering if I can tell the mime type from the NSData. There are only a few answers to this question and the most recent one is from 2010 (4 years ago!). Thanks!

NSData *data; // can be an image or video
NSString *mimeType = [data getMimetype]; // how would I implement getMimeType
Bitternut answered 14/2, 2014 at 21:23 Comment(3)
You could have another field that declares the MIME type and send that along as well.Emmeram
There is no (accurate) way to determine the MIME type of data from the data itself. At best you can make an educated guess.Respirable
Should you wish to add extra MIME types, you can find their hex values here: en.wikipedia.org/wiki/List_of_file_signaturesJeremiahjeremias
P
54

Based on ml's answer from a similar post, I've added the mime types determination for NSData:

ObjC:

+ (NSString *)mimeTypeForData:(NSData *)data {
    uint8_t c;
    [data getBytes:&c length:1];

    switch (c) {
        case 0xFF:
            return @"image/jpeg";
            break;
        case 0x89:
            return @"image/png";
            break;
        case 0x47:
            return @"image/gif";
            break;
        case 0x49:
        case 0x4D:
            return @"image/tiff";
            break;
        case 0x25:
            return @"application/pdf";
            break;
        case 0xD0:
            return @"application/vnd";
            break;
        case 0x46:
            return @"text/plain";
            break;
        default:
            return @"application/octet-stream";
    }
    return nil;
}

Swift:

static func mimeType(for data: Data) -> String {

    var b: UInt8 = 0
    data.copyBytes(to: &b, count: 1)

    switch b {
    case 0xFF:
        return "image/jpeg"
    case 0x89:
        return "image/png"
    case 0x47:
        return "image/gif"
    case 0x4D, 0x49:
        return "image/tiff"
    case 0x25:
        return "application/pdf"
    case 0xD0:
        return "application/vnd"
    case 0x46:
        return "text/plain"
    default:
        return "application/octet-stream"
    }
}

This handle main file types only, but you can complete it to fit your needs: all the files signature are available here, just use the same pattern as I did.

PS: all the corresponding mime types are available here

Pusillanimous answered 24/9, 2015 at 15:49 Comment(10)
Hey @blee908, this could be a valid answer, what do you think? :)Pusillanimous
How can we detect Audio files ?Ruthful
@Ruthful check the list of signatures as mentioned above en.wikipedia.org/wiki/List_of_file_signaturesPusillanimous
then find the audio file types you want to detect and a case for each file type. Example: according to the array of files signature, WMA first byte is 0x30 so add case 0x30: return @"audio/x-ms-wma"; break;Pusillanimous
This can return a lot of false positives.Dionysian
@maddy thank you for letting us know, but it doesn't really help to understand why or how to fix the false positive cases...Pusillanimous
@Pusillanimous How can we add support for docx file?Fp
@JigarTarsariya As I mentioned in my original answer, please have a look at the mime types list available here: en.wikipedia.org/wiki/List_of_file_signatures. Docx is mentioned.Pusillanimous
@Pusillanimous for .doc extension files I am getting application/vnd rather that application/wsword..I am not sure why is thatTherese
what about doc ? docx ?Hayrack
M
39

❤️ Swift

extension Data {
    private static let mimeTypeSignatures: [UInt8 : String] = [
        0xFF : "image/jpeg",
        0x89 : "image/png",
        0x47 : "image/gif",
        0x49 : "image/tiff",
        0x4D : "image/tiff",
        0x25 : "application/pdf",
        0xD0 : "application/vnd",
        0x46 : "text/plain",
        ]

    var mimeType: String {
        var c: UInt8 = 0
        copyBytes(to: &c, count: 1)
        return Data.mimeTypeSignatures[c] ?? "application/octet-stream"
    }
}
Madrigalist answered 25/7, 2017 at 13:48 Comment(4)
Works perfectlyBoding
can we set type for doc or ppt file ?Fp
This can return a lot of false positives.Dionysian
what about doc? or docx ???Hayrack
J
4

Since you say that you're uploading this data, you should already know the MIME type. You created the data object, you know where the data came from, and there are a limited number of MIME types. So use whichever one applies to your data. For an image it's probably image/jpeg or image/png. For videos there are a bunch of video/ types. You can find a long list of MIME type strings on your Mac in /etc/apache2/mime.types. You'll want one or more of those depending on what kind of video you have.

Determining the MIME type is a sticky problem; an NSData can encode any kind of binary data. The only way to determine what was encoded is to examine the bytes. That in turn means having some understanding of what byte streams exist in different file types. It should be possible to use a lookup dictionary in many (but not all) cases, and there might be an open source implementation somewhere for common file types. To get an idea of what's involved, try man file on your Mac and look in /usr/share/file/magic/ to see how various file types are identified (the file command doesn't produce MIME types but it does analyze file contents to try and identify file types, so it's the same principle).

Jacobite answered 14/2, 2014 at 21:33 Comment(4)
Thanks for the explanation. Well, the backstory is a bit more complicated. I'm writing an API call and I don't know what the user is passing in. All I know is that its an NSData class and it can be a image or video. And I need the MIME type too properly upload the file via AFNetworking.Bitternut
Does your server need to know the exact MIME type? You can always fall back on application/octet-stream to indicate "some kind of binary data". If you need something more specific, the best way might be to load it into an AVFoundation class (maybe AVAsset) and then look at the metadata to choose a MIME type.Jacobite
Very close. It turns out that "application/octet-stream" seems to work (i tested png and jpeg, but entered in the same MIME type), but AFNetworking needs to know the file extension, so you need to pass in an NSString *filename with "mypic.jpeg" or "mypic.png" not "mypic"Bitternut
OK, well, I don't use AFNetworking, so I don't know about that. It's open source though, so changing it is always an option.Jacobite
N
3

As far as I know, NSData is a just a data object that wraps a byte array:

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSData_Class/Reference/Reference.html

...so one way I can think of if you wanted to discover its MIME type is to inspect the bytes themselves and then surmise the type from there. There's an example of that in here: Finding image type from NSData or UIImage

I also found this: Determine MIME Type of NSData Loaded From a File; which refers to some internal database (I guess) that can be used for a MIME type look-up.

But like Tom Harrington says in his answer, it could get tricky depending on what you're dealing with.

Edit...

Of course, that second solution relies on the file extension, which you obviously don't have, but I'm sure you noticed that already.

Noontide answered 14/2, 2014 at 21:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.