Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the type of a file in Cocoa

You could use Uniform Type Identifiers. Since UTIs are organised into hierarchies, one possibility is to check whether the preferred UTI for a given file conforms to a top-level UTI, e.g. public.image for images or public.movie for movies. The Core Services framework includes functions that operate on UTIs as well as constants representing known UTIs.

For instance, working on file name extensions:

NSString *file = @"…"; // path to some file
CFStringRef fileExtension = (CFStringRef) [file pathExtension];
CFStringRef fileUTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension, NULL);

if (UTTypeConformsTo(fileUTI, kUTTypeImage)) NSLog(@"It's an image");
else if (UTTypeConformsTo(fileUTI, kUTTypeMovie)) NSLog(@"It's a movie");
else if (UTTypeConformsTo(fileUTI, kUTTypeText)) NSLog(@"It's text");

CFRelease(fileUTI);

If you have a MIME type instead of a file name extension, you can use kUTTagClassMIMEType instead of kUTTagClassFilenameExtension.

For a list of known UTIs, see this document.


[[NSWorkspace sharedWorkspace] typeOfFile:pathToFile error:nil]

Example to check whether a path is an image type, can be change to match other UTI classes. Note the Tech Note Technical Q&A QA1518 uses FSPathMakeRef which is now deprecated to get the uti via LSCopyItemAttributes - the NSWorkspace solution above is the best way to get the UTI then you just need to add code to compare with a list of UTIs: (the matching array can be pre allocated and initialised/released elsewhere if desired)

- (BOOL)isImageFile:(NSString*)filePath
{
/* get an array of utis to match against, this gets supported CG/NS image formats */

CFArrayRef supportedTypes = CGImageSourceCopyTypeIdentifiers();
CFIndex    typeCount      = CFArrayGetCount(supportedTypes);

/* get the uti of the filepath and check against the list with the UTI API */

BOOL isImage     = NO;
NSString * uti   = [[NSWorkspace sharedWorkspace] typeOfFile:filePath error:nil];

if ( uti != nil){
    for (CFIndex i = 0; i < typeCount; i++)
    {
        CFStringRef supportedUTI = CFArrayGetValueAtIndex(supportedTypes, i);
        if (UTTypeConformsTo(supportedUTI, CFSTR("public.image")))
        {
            if (UTTypeConformsTo((CFStringRef)uti, supportedUTI))
            {
                isImage = YES;
                break;
            }
        }
    } // i
}
/* clean up */
CFRelease(supportedTypes);
return isImage;
}

You can also determine the image type without relying on the path extension with CGImageSource (part of the ImageIO framework).

The following example uses a file URL, but you can also create an image source from a CFDataRef.

CFStringRef typeOfImageAtURL(NSURL *imageURL) {
    const void * keys[] = { kCGImageSourceShouldCache };
    const void * values[] = { kCFBooleanFalse };
    CFDictionaryRef options = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 1, NULL, NULL);
    CGImageSourceRef imageSource = CGImageSourceCreateWithURL((__bridge CFURLRef)imageURL, options);
    CFStringRef imageType = CGImageSourceGetType(imageSource);
    CFRelease(options);
    CFRelease(imageSource);
    return imageType;
}

The return value will be a constant that you can compare with the uniform type identifier values declared in CoreServices/MobileCoreServices (e.g., kUTTypeJPEG, kUTTypeGIF, etc).

The icing on the cake: you can pass in an optional "hint" UTI if you have reason to anticipate one file type or another. Combine this approach with Bavarious' and you'll have a lean, mean image format detection machine.


This will get the 'kind' of file.

+ (NSString *)humanReadableFileType:(NSString *)path{
    NSString *kind = nil;
    NSURL *url = [NSURL fileURLWithPath:[path stringByExpandingTildeInPath]];
    LSCopyKindStringForURL((CFURLRef)url, (CFStringRef *)&kind);
    return kind ? [kind autorelease] : @"";
}

Source: http://importantshock.wordpress.com/2007/01/07/cocoa-snippet-finding-a-files-kind/#post-19