Created
February 5, 2010 04:23
-
-
Save atr000/295508 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
// A tiny program that converts PDF documents to high resolution PNG images. | |
// | |
// gcc --std=c99 -Wall -g -o pdf2png pdf2png.m -framework Cocoa | |
// | |
// Written by Evan Jones <[email protected]> Februrary, 2004 | |
// http://www.eng.uwaterloo.ca/~ejones/ | |
// | |
// Released under the "do whatever you want" public domain licence. | |
#include <Cocoa/Cocoa.h> | |
int main( int argc, char* argv[] ) | |
{ | |
int desiredResolution = 200; // in DPI | |
BOOL morePages = YES; | |
int page = 1; | |
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
// Package all arguments as NSStrings in an NSArray | |
NSMutableArray* args = [NSMutableArray arrayWithCapacity: argc - 1]; | |
for ( int i = 1; i < argc; ++ i ) | |
{ | |
[args addObject: [NSString stringWithCString: argv[i]] ]; | |
} | |
// If we have a "--dpi" along with a corresponding argument ... | |
unsigned int index = NSNotFound; | |
if ( (index = [args indexOfObject: @"--dpi"]) != NSNotFound && index + 1 < [args count] ) | |
{ | |
// Parse it as an integer | |
desiredResolution = [[args objectAtIndex: index + 1] intValue]; | |
[args removeObjectAtIndex: index + 1]; | |
[args removeObjectAtIndex: index]; | |
} | |
// If we have a "--page" along with a corresponding argument ... | |
if ( (index = [args indexOfObject: @"--page"]) != NSNotFound && index + 1 < [args count] ) | |
{ | |
// Parse it as an integer | |
page = [[args objectAtIndex: index + 1] intValue]; | |
morePages = NO; | |
[args removeObjectAtIndex: index + 1]; | |
[args removeObjectAtIndex: index]; | |
} | |
if ( [args count] != 1 || [args indexOfObject: @"--help"] != NSNotFound || desiredResolution <= 0 || page <= 0 ) | |
{ | |
fprintf( stderr, "pdf2png [options] file\n" ); | |
fprintf( stderr, "\t--dpi dpi\tSpecifies the resolution at which to export the pages\n" ); | |
fprintf( stderr, "\t--page page\tSingle page to export\n" ); | |
fprintf( stderr, "\t--help\tPrint this help message\n" ); | |
return 1; | |
} | |
NSString* sourcePath = [args objectAtIndex: 0]; | |
NSImage* source = [ [NSImage alloc] initWithContentsOfFile: sourcePath ]; | |
[source setScalesWhenResized: YES]; | |
// Tip from http://www.omnigroup.com/mailman/archive/macosx-dev/2002-February/023366.html | |
// Allows setCurrentPage to do anything | |
[source setDataRetained: YES]; | |
if ( source == nil ) | |
{ | |
fprintf( stderr, "Source image '%s' could not be loaded\n", argv[1] ); | |
return 2; | |
} | |
// The output file name | |
NSString* outputFileFormat = @"%@-p%01d"; | |
// Find the PDF representation | |
NSPDFImageRep* pdfSource = NULL; | |
NSArray* reps = [source representations]; | |
for ( int i = 0; i < [reps count] && pdfSource == NULL; ++ i ) | |
{ | |
if ( [[reps objectAtIndex: i] isKindOfClass: [NSPDFImageRep class]] ) | |
{ | |
pdfSource = [reps objectAtIndex: i]; | |
[pdfSource setCurrentPage: page-1]; | |
// Set the output format to have the correct number of leading zeros | |
unsigned int numDigits = [(NSString*) [NSString stringWithFormat: @"%d", [pdfSource pageCount]] length]; | |
outputFileFormat = [NSString stringWithFormat: @"%%@-p%%0%dd", numDigits]; | |
} | |
} | |
NSSize sourceSize = [source size]; | |
// When loading a PDF document, it reports size in typographic dots. There are 72 dots per inch. | |
// See http://www.macosxguru.net/article.php?story=20031209091834195 | |
// When converting, we need to scale the PDF by this factor | |
double sourceResolution = 72.0; | |
int pixels = [ [source bestRepresentationForDevice: nil] pixelsWide]; | |
if ( pixels != 0 ) sourceResolution = ((double)pixels / sourceSize.width) * 72.0; | |
double scaleFactor = desiredResolution / sourceResolution; | |
NSSize size = NSMakeSize( sourceSize.width * scaleFactor, sourceSize.height * scaleFactor ); | |
[NSApplication sharedApplication]; | |
[[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationHigh]; | |
[source setSize: size]; | |
NSRect destinationRect = NSMakeRect( 0, 0, size.width, size.height ); | |
NSImage* image = [[NSImage alloc] initWithSize:size]; | |
[image lockFocus]; | |
[[NSColor whiteColor] set]; // We fill the rect with white, with full opacity, later on | |
do | |
{ | |
// Set up a temporary release pool so memory will get cleaned up properly | |
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init]; | |
NSRectFillUsingOperation( destinationRect, NSCompositeClear ); | |
[source drawInRect: destinationRect | |
fromRect: destinationRect | |
operation: NSCompositeCopy fraction: 1.0]; | |
NSBitmapImageRep* bitmap = [ [NSBitmapImageRep alloc] | |
initWithFocusedViewRect: destinationRect ]; | |
NSData* data = [bitmap representationUsingType:NSPNGFileType properties:nil]; | |
[bitmap release]; | |
[[NSFileManager defaultManager] | |
createFileAtPath: [ [NSString stringWithFormat: outputFileFormat, [sourcePath stringByDeletingPathExtension], page] stringByAppendingPathExtension: @"png"] | |
contents: data | |
attributes: nil ]; | |
if ( morePages == YES ) | |
{ | |
// Go get the next page | |
if ( pdfSource != NULL && page < [pdfSource pageCount] ) | |
{ | |
[pdfSource setCurrentPage: page]; | |
[source recache]; | |
page ++; | |
} | |
else | |
{ | |
morePages = NO; | |
} | |
} | |
[loopPool release]; | |
} | |
while ( morePages == YES ); | |
[image unlockFocus]; | |
[image release]; | |
[pool release]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment