#import void SetKeywords (NSArray *stuff, NSArray *files, BOOL flag); @interface NSArray (argvFilesExist) + (NSMutableArray *)argvFilesExist:(NSArray *)files withWritableIPTC:(BOOL)flag; @end @interface NSArray (arrayWithOpts) + (NSArray *)arrayWithOpts:(NSString *)argvKeywords; @end @interface NSArray (keywordsFromFile) + (NSArray *)keywordsFromFile:(char *)fileFromArg; @end @interface NSObject (writeKeywordsToFile) + (void)writeKeywordsToFile:(char *)file keywordsToWrite:(NSArray *)keywords; @end @implementation NSArray (argvFilesExist) + (NSMutableArray *)argvFilesExist:(NSArray *)files withWritableIPTC:(BOOL)flag { NSMutableArray *returnArray = [NSMutableArray array]; NSEnumerator *enumerator = [files objectEnumerator]; CFStringRef file, kind; MDItemRef item; id arg; while (arg = [enumerator nextObject]) { file = CFStringCreateWithFileSystemRepresentation(NULL, [arg UTF8String]); if ([[NSFileManager defaultManager] fileExistsAtPath:(NSString *)file]) { item = MDItemCreate(NULL, file); kind = MDItemCopyAttribute(item, kMDItemContentType); if (flag && ([(NSString *)kind isEqualToString:@"public.tiff"] || [(NSString *)kind isEqualToString:@"public.jpeg"])) [returnArray addObject:(NSString *)file]; if (!flag && ([(NSString *)kind isEqualToString:@"com.adobe.photoshop-image"] || [(NSString *)kind isEqualToString:@"public.tiff"] || [(NSString *)kind isEqualToString:@"public.jpeg"])) [returnArray addObject:(NSString *)file]; } CFRelease(file); } return ([returnArray count] > 0) ? returnArray : nil; } @end @implementation NSArray (arrayWithOpts) + (NSArray *)arrayWithOpts:(NSString *)argvKeywords { NSArray * keywords = [argvKeywords componentsSeparatedByString:@","]; NSEnumerator * enm = [keywords objectEnumerator]; CFStringRef str; CFMutableStringRef copy; int i = 0; id word; while (word = [enm nextObject]) { str = CFArrayGetValueAtIndex((CFArrayRef)keywords, i); copy = CFStringCreateMutableCopy(NULL, CFStringGetLength(str), str); CFStringTrimWhitespace(copy); CFArraySetValueAtIndex((CFMutableArrayRef)keywords, i, copy); CFRelease(copy); i++; } return ([keywords count] > 0) ? keywords : nil; } @end @implementation NSArray (keywordsFromFile) + (NSArray *)keywordsFromFile:(char *)fileFromArg { CFStringRef file = CFStringCreateWithFileSystemRepresentation(NULL, fileFromArg); MDItemRef item = MDItemCreate(NULL, file); CFTypeRef keywords = MDItemCopyAttribute(item, kMDItemKeywords); NSArray * words = [NSArray arrayWithArray:(NSArray *)keywords]; CFRelease(file); return ([words count] > 0) ? words : nil; } @end @implementation NSObject (writeKeywordsToFile) + (void)writeKeywordsToFile:(char *)file keywordsToWrite:(NSArray *)keywords { NSDictionary *iptcKeywords = [NSDictionary dictionaryWithObject:keywords forKey:(NSString *)kCGImagePropertyIPTCKeywords]; NSDictionary *iptcProperties = [NSDictionary dictionaryWithObject:iptcKeywords forKey:(NSString *)kCGImagePropertyIPTCDictionary]; NSMutableData *imageData = [[NSMutableData alloc] init]; CFStringRef input = CFStringCreateWithCString(NULL, file, kCFStringEncodingUTF8); CFStringRef path = CFStringCreateWithFileSystemRepresentation(NULL, file); CGImageSourceRef imageSource = CGImageSourceCreateWithURL ((CFURLRef)[NSURL fileURLWithPath:(NSString *)input], nil); CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((CFMutableDataRef)imageData, CGImageSourceGetType(imageSource), 1, NULL); CGImageDestinationAddImageFromSource(imageDestination, imageSource, 0, (CFDictionaryRef)iptcProperties); if (CGImageDestinationFinalize(imageDestination)) [imageData writeToFile:(NSString *)path atomically:YES]; CFRelease(input); CFRelease(path); CFRelease(imageSource); CFRelease(imageDestination); [imageData release]; } @end int main (int argc, const char * argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSArray *args = [[NSProcessInfo processInfo] arguments]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSString *shortSetOption = [defaults stringForKey:@"s"]; NSString *longSetOption = [defaults stringForKey:@"-set"]; NSString *shortAppendOption = [defaults stringForKey:@"a"]; NSString *longAppendOption = [defaults stringForKey:@"-append"]; NSString *shortArgs = (shortSetOption) ? shortSetOption : ((shortAppendOption) ? shortAppendOption : nil); NSString *longArgs = (longSetOption) ? longSetOption : ((longAppendOption) ? longAppendOption : nil); NSString *optArgs = (shortArgs) ? shortArgs : ((longArgs) ? longArgs : nil); NSEnumerator *enm = [args objectEnumerator]; bool help = false; id arg; while (arg = [enm nextObject]) if ([(NSString *)arg isEqualToString:@"-h"] || [(NSString *)arg isEqualToString:@"--help"]) help = true; if(optArgs) { NSArray *keywords = [NSArray arrayWithOpts:optArgs]; NSArray *files = [NSArray argvFilesExist:args withWritableIPTC:1]; BOOL flag = (shortSetOption || longSetOption) ? 0 : 1; if(files) SetKeywords (keywords, files, flag); if(!files) help = true; } if(!optArgs && !help) { NSArray *files = [NSArray argvFilesExist:args withWritableIPTC:0]; NSEnumerator *enm = [files objectEnumerator]; NSArray *keywords; CFStringRef echo; id word; if(files) while (word = [enm nextObject]) { keywords = [NSArray keywordsFromFile:(char *)[word UTF8String]]; printf("%s -------------\n", [word UTF8String]); echo = (keywords) ? CFStringCreateByCombiningStrings(NULL, (CFArrayRef)keywords, CFSTR(", ")) : CFSTR("No Keywords!"); CFShow(echo); CFRelease(echo); } if(!files) help = true; } if(help) { CFShow(CFSTR("\nmdkw only reads keywords from JPEG, TIFF, and Adobe Photoshop files")); CFShow(CFSTR("mdkw will only write keywords to JPEG and TIFF files\n\n")); CFShow(CFSTR("usage: mdkw [file(s)]")); CFShow(CFSTR("usage: mdkw [-h, --help]")); CFShow(CFSTR("usage: mdkw [-a, --append] ['keyword'] [file(s)]")); CFShow(CFSTR("usage: mdkw [-s, --set] ['keyword'] [file(s)]\n\n")); CFShow(CFSTR("example: mdkw ~/Pictures/Birthday.jpg")); CFShow(CFSTR("example: mdkw -s Cake ~/Pictures/Birthday.jpg")); CFShow(CFSTR("example: mdkw -s 'Birthday Cake' ~/Pictures/Birthday.jpg")); CFShow(CFSTR("example: mdkw -s 'Ballons, Birthday Cake' ~/Pictures/Birthday.jpg\n\n")); } [pool release]; return 0; } void SetKeywords (NSArray *keyWordsFromArgs, NSArray *files, BOOL flag) { // NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSEnumerator *enm = [files objectEnumerator]; NSArray *keywords; CFStringRef echo; unsigned a, b; CFArrayRef merge, writeBack; CFRange range; id word; while (word = [enm nextObject]) { keywords = [NSArray keywordsFromFile:(char *)[word UTF8String]]; if (keywords) { a = [keywords count]; b = [keyWordsFromArgs count]; merge = CFArrayCreateMutableCopy(NULL, a+b, (CFArrayRef)keywords); CFRange range = {0, b}; CFArrayAppendArray((CFMutableArrayRef)merge, (CFArrayRef)keyWordsFromArgs, range); } writeBack = (flag && keywords) ? CFArrayCreateCopy(NULL, merge) : CFArrayCreateCopy(NULL, (CFArrayRef)keyWordsFromArgs); [NSObject writeKeywordsToFile:(char *)[word UTF8String] keywordsToWrite:(NSArray *)writeBack]; printf("%s -------------\n", [word UTF8String]); echo = CFStringCreateByCombiningStrings(NULL, writeBack, CFSTR(", ")); CFShow(echo); } CFRelease(writeBack); CFRelease(merge); // [pool release]; }