Skip to content

Instantly share code, notes, and snippets.

@atr000
Created March 4, 2010 06:37
Show Gist options
  • Save atr000/321463 to your computer and use it in GitHub Desktop.
Save atr000/321463 to your computer and use it in GitHub Desktop.
#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