Created
March 4, 2010 06:37
-
-
Save atr000/321463 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#import <Quartz/Quartz.h> | |
#import <ScreenSaver/ScreenSaver.h> | |
// cmd = "System/Library/Printers/Libraries/./quartzfilter '%s' '%s' '%s'" % (pdffilepath, qfilterpath, tmpfilepath) | |
// Returns the file path of an unused temporary file | |
NSString *getTempFilePath (NSString *extension) { | |
NSString *tempDirectory = NSTemporaryDirectory(); | |
NSFileManager *fileManager = [NSFileManager defaultManager]; | |
NSString *tempFilePath; | |
BOOL pathExists = YES; | |
while (pathExists == YES) { | |
// creating a random integer between 1000 and 9999 with | |
// a convenient function found in the ScreenSaver framework | |
int randnum = SSRandomIntBetween(1000, 9999); | |
// e.g. /TemporaryDirectory/8765.png | |
tempFilePath = [NSString stringWithFormat:@"%@%d.%@", tempDirectory, randnum, extension]; | |
if ([fileManager fileExistsAtPath:tempFilePath] == NO) { | |
pathExists = NO; | |
} | |
} | |
// tempFilePath is an autoreleased object (created with NSSString stringWithFormat) | |
return tempFilePath; | |
} | |
// | |
void printUsage () { | |
printf("Usage: mergepdf -output [PDF path] -folder [PDF folder path] -qfilter [Quartz filter path]\n"); | |
} | |
// | |
int sortPDFNames(id pdfName1, id pdfName2, void * context) | |
{ | |
return [pdfName1 compare:pdfName2 options:NSLiteralSearch]; | |
} | |
int main (int argc, const char * argv[]) { | |
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | |
NSFileManager *fileManager = [NSFileManager defaultManager]; | |
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; | |
NSString *outputPath = [userDefaults stringForKey:@"output"]; | |
if ((outputPath == NULL) || ([outputPath isEqualToString:@""])) { | |
printf("ERROR: Missing or invalid output path\n"); | |
printUsage(); | |
return 1; | |
} | |
BOOL applyQuartzFilter; | |
BOOL isDir; | |
NSString *quartzFilterPath = [userDefaults stringForKey:@"qfilter"]; | |
if (quartzFilterPath == NULL) { | |
applyQuartzFilter = NO; | |
} else { | |
if ([quartzFilterPath isEqualToString:@""]) { | |
printf("ERROR: Missing Quartz filter path\n"); | |
printUsage(); | |
return 1; | |
} else { | |
if ([fileManager fileExistsAtPath:quartzFilterPath] == NO) { | |
NSLog(@"Quartz filter path does not exist"); | |
printf("ERROR: The Quartz filter does not exist:\n%s\n", [quartzFilterPath UTF8String]); | |
return 1; | |
} | |
} | |
applyQuartzFilter = YES; | |
} | |
NSString *folderPath = [userDefaults stringForKey:@"folder"]; | |
if ((folderPath == NULL) || ([folderPath isEqualToString:@""])) { | |
printf("ERROR: Missing or invalid folder path\n"); | |
printUsage(); | |
return 1; | |
} | |
if ([fileManager fileExistsAtPath:folderPath isDirectory:&isDir] == NO) { | |
printf("ERROR: The folder does not exist:\n%s\n", [folderPath UTF8String]); | |
return 1; | |
} else { | |
if (isDir == NO) { | |
printf("ERROR: The given path does not point to a folder:\n%s\n", [folderPath UTF8String]); | |
return 1; | |
} | |
} | |
NSArray *itemNames = [fileManager directoryContentsAtPath:folderPath]; | |
if ([itemNames count] == 0) { | |
printf("ERROR: The given folder path is empty:\n%s\n", [folderPath UTF8String]); | |
} | |
NSMutableArray *pdfPaths = [[NSMutableArray alloc] initWithCapacity:1]; | |
NSEnumerator *itemNamesEnumerator = [itemNames objectEnumerator]; | |
NSString *itemName; | |
while (itemName = [itemNamesEnumerator nextObject]) { | |
// ignoring invisible items | |
if ([itemName characterAtIndex:0] == '.') { | |
continue; | |
} | |
// ignoring directories | |
NSString *itemPath = [folderPath stringByAppendingPathComponent:itemName]; | |
BOOL isDir; | |
if ([fileManager fileExistsAtPath:itemPath isDirectory:&isDir] == YES) { | |
if (isDir == YES) { | |
continue; | |
} | |
// simply discovering PDf files by a .pdf suffix :-) | |
if ([itemName hasSuffix:@".pdf"]) { | |
[pdfPaths addObject:itemPath]; | |
} | |
} | |
} | |
if ([pdfPaths count] == NO) { | |
printf("ERROR: No PDF files found in the given folder:\n%s\n", [folderPath UTF8String]); | |
return 1; | |
} | |
printf("Found %i PDF documents in folder '%s'\n", [pdfPaths count], [folderPath UTF8String]); | |
printf("Sorting found PDF document names alphabetically...\n"); | |
NSMutableArray *pdfNames = [[NSMutableArray alloc] initWithCapacity:1]; | |
NSEnumerator *pdfPathsEnumerator = [pdfPaths objectEnumerator]; | |
NSString *pdfPath; | |
while (pdfPath = [pdfPathsEnumerator nextObject]) { | |
NSString *pdfName = [pdfPath lastPathComponent]; | |
[pdfNames addObject:pdfName]; | |
} | |
[pdfPaths release]; | |
NSArray *sortedPDFNames = [pdfNames sortedArrayUsingFunction:sortPDFNames context:NULL]; | |
PDFDocument *outputPDF; | |
outputPDF = [[PDFDocument alloc] init]; | |
if (outputPDF == NULL) { | |
NSBundle *myBundle = [NSBundle mainBundle]; | |
NSString *parentFolderPath = [myBundle bundlePath]; | |
NSString *dummyPDFPath = [parentFolderPath stringByAppendingPathComponent:@"dummy.pdf"]; | |
if ([fileManager fileExistsAtPath:dummyPDFPath] == NO) { | |
printf("ERROR: Cannot load dummy PDF file supposed to be located at:\n%s\n", [dummyPDFPath UTF8String]); | |
return 1; | |
} else { | |
NSURL *dummyPDFURL = [NSURL fileURLWithPath:dummyPDFPath]; | |
outputPDF = [[PDFDocument alloc] initWithURL:dummyPDFURL]; | |
if (outputPDF == NULL) { | |
printf("ERROR: Could not initialize new PDF document\n"); | |
return 1; | |
} | |
[outputPDF removePageAtIndex:0]; | |
} | |
} | |
PDFDocument *inputPDF; | |
int pagecounter = 0; | |
NSEnumerator *pdfNamesEnumerator = [sortedPDFNames objectEnumerator]; | |
NSString *pdfName; | |
while (pdfName = [pdfNamesEnumerator nextObject]) { | |
NSString *pdfPath = [folderPath stringByAppendingPathComponent:pdfName]; | |
NSURL *pdfURL = [NSURL fileURLWithPath:pdfPath]; | |
inputPDF = [[PDFDocument alloc] initWithURL:pdfURL]; | |
if (inputPDF == NULL) { | |
printf("ERROR: The file does not seem to be a valid PDF:\n\%s\n", [pdfPath UTF8String]); | |
continue; | |
} | |
int pagecount = [inputPDF pageCount]; | |
printf("Processing PDF document: %s (Pages: %i)\n", [pdfName UTF8String], pagecount); | |
int pagenum; | |
for( pagenum = 0; pagenum < pagecount; pagenum++ ) { | |
printf("\tAdding page %i\n", (pagenum + 1)); | |
PDFPage *singlePage = [inputPDF pageAtIndex:pagenum]; | |
[outputPDF insertPage:singlePage atIndex:pagecounter]; | |
pagecounter++; | |
} | |
} | |
[pdfNames release]; | |
if (applyQuartzFilter == YES) { | |
printf("Applying Quartz filter: %s\n", [quartzFilterPath UTF8String]); | |
NSString *tmpFilePath = getTempFilePath(@"pdf"); | |
BOOL tmpWriteSuccess = [outputPDF writeToFile:tmpFilePath]; | |
if (tmpWriteSuccess == NO) { | |
printf("ERROR: Could not write PDF content to temporary file.\n"); | |
return 1; | |
} | |
NSTask *shellCommand = [[NSTask alloc] init]; | |
[shellCommand setLaunchPath:@"/System/Library/Printers/Libraries/./quartzfilter"]; | |
// arrayWithObjects expects nil as the last object | |
[shellCommand setArguments:[NSArray arrayWithObjects:tmpFilePath, quartzFilterPath, outputPath, nil]]; | |
[shellCommand launch]; | |
[shellCommand waitUntilExit]; | |
int shellCommandStatus = [shellCommand terminationStatus]; | |
if (shellCommandStatus != 0) { | |
printf("ERROR: The quartzfilter utility did not run successfully\n"); | |
return 1; | |
} | |
[shellCommand release]; | |
[fileManager removeFileAtPath:tmpFilePath handler:NULL]; | |
printf("Created the new PDF (%i pages): '%s'\n", pagecounter, [outputPath UTF8String]); | |
} else { | |
printf("Writing the new PDF (%i pages): '%s'\n", pagecounter, [outputPath UTF8String]); | |
BOOL writeSuccess = [outputPDF writeToFile:outputPath]; | |
if (writeSuccess == NO) { | |
printf("ERROR: Could not write PDF file:\n%s\n", [outputPath UTF8String]); | |
return 1; | |
} | |
} | |
[outputPDF release]; | |
[inputPDF release]; | |
[pool drain]; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment