How to identify a NSData's image format?
Asked Answered
R

6

9

If I get a NSData which I know it's a image's data.But I don't know what format it is. So how can I identify which image format is it?Jpeg or PNG?

PS:iOS

Ramonitaramos answered 2/9, 2011 at 9:2 Comment(0)
S
8

You could look at the first bytes and make a guess. There are many lists of magic numbers available on the internet, e.g. http://www.astro.keele.ac.uk/oldusers/rno/Computing/File_magic.html.

Spill answered 2/9, 2011 at 9:11 Comment(0)
P
17

I used Mats answer to build a simple category on NSData which tells me if its content is JPEG or PNG based on its first 4 bytes:

@interface NSData (yourCategory)

- (BOOL)isJPG;
- (BOOL)isPNG;

@end

@implementation NSData (yourCategory)
- (BOOL)isJPG
{
    if (self.length > 4)
    {
        unsigned char buffer[4];
        [self getBytes:&buffer length:4];

        return buffer[0]==0xff && 
               buffer[1]==0xd8 && 
               buffer[2]==0xff &&
               buffer[3]==0xe0;
    }

    return NO;
}

- (BOOL)isPNG
{
    if (self.length > 4)
    {
        unsigned char buffer[4];
        [self getBytes:&buffer length:4];

        return buffer[0]==0x89 &&
               buffer[1]==0x50 &&
               buffer[2]==0x4e &&
               buffer[3]==0x47;
    }

    return NO;
}

@end

And then, simply do a :

CGDataProviderRef imgDataProvider = CGDataProviderCreateWithCFData((CFDataRef) imgData);
CGImageRef imgRef = nil;

if ([imgData isJPG])
    imgRef = CGImageCreateWithJPEGDataProvider(imgDataProvider, NULL, true, kCGRenderingIntentDefault);
else if ([imgData isPNG])
    imgRef = CGImageCreateWithPNGDataProvider(imgDataProvider, NULL, true, kCGRenderingIntentDefault);

UIImage* image = [UIImage imageWithCGImage:imgRef];

CGImageRelease(imgRef);
CGDataProviderRelease(imgDataProvider);
Planarian answered 27/6, 2012 at 12:40 Comment(1)
Just like to add that not all JPEGs have the fourth byte as e0. Turns out that there are multiple "sub-types" made by various companies. See garykessler.net/library/file_sigs.html for at least a partial listing of them. Based on what I've seen so far, it seems that they consistently have the first three bytes as referenced above, and no other file types seem to use those same three bytes, but I don't know if this is written in stone anywhere.Chromatic
S
8

You could look at the first bytes and make a guess. There are many lists of magic numbers available on the internet, e.g. http://www.astro.keele.ac.uk/oldusers/rno/Computing/File_magic.html.

Spill answered 2/9, 2011 at 9:11 Comment(0)
G
1

Here's a Swift version of the @apouche's answer:

extension NSData {
  func firstBytes(length: Int) -> [UInt8] {
    var bytes: [UInt8] = [UInt8](count: length, repeatedValue: 0)
    self.getBytes(&bytes, length: length)
    return bytes
  }

  var isJPEG: Bool {
    let signature:[UInt8] = [0xff, 0xd8, 0xff, 0xe0]
    return firstBytes(4) == signature
  }

  var isPNG: Bool {
    let signature:[UInt8] = [0x89, 0x50, 0x4e, 0x47]
    return firstBytes(4) == signature
  }
}
Graptolite answered 10/7, 2015 at 16:9 Comment(0)
S
0

Can you create an image from that and then just ask that NSImage what format it is?

You can use -initWithData to create the NSImage, for more, see http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSImage_Class/Reference/Reference.html

Substratum answered 2/9, 2011 at 9:4 Comment(1)
How to ask the NSImage it's format? I'm working on iOS and I'm not sure if that solution works on iOSRamonitaramos
F
0

You can create CGImageSourceRef and then ask it for image type

    CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef) imageData, NULL);

    if(imageSource)
    {
        // this is the type of image (e.g., public.jpeg - kUTTypeJPEG )
        // <MobileCoreServices/UTCoreTypes.h>

        CFStringRef UTI = CGImageSourceGetType(imageSource);

        CFRelease(imageSource);
    }

    imageSource = nil;
Furtherance answered 23/9, 2016 at 12:48 Comment(2)
It seems, CGImageSourceGetType decides type based on EXIF tags, not on the actual file encoding.Usia
It is a bit more complex than you think. Apple says that CGImageSourceGetType "Returns the uniform type identifier of the source container.". For example format of the given file can be tiff or dng, but first source container compressed as jpg. Magic numbers are good for fast and wrong checking. developer.apple.com/documentation/imageio/…Furtherance
C
0

If you use UIImage imageWithData, you don't need to know if the data is png or jpg.

// read from file
NSData * thumbnailData = [decoder decodeObjectForKey:kThumbnailKey];     
[UIImage imageWithData:thumbnailData];
Christo answered 10/2, 2023 at 6:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.