Command line concatenate PDFs on OS X

A great post at http://gotofritz.net/blog/howto/joining-pdf-files-in-os-x-from-the-command-line/ which does what it says on the tin.

He explains how to link to a python script included in OS X since some years ago so as to make concatenating PDFs as easy as typing

pdfconcat -o output.pdf *.pdf

The heavy lifting is all done with calls to OS X Quartz.CoreGraphics module so this isn't going to work on other platforms, but for the curious it demonstrates how easily you can do such stuff on OS X.

#! /usr/bin/python
#
# join
#   Joing pages from a a collection of PDF files into a single PDF file.
#
#   join [--output <file>] [--shuffle] [--verbose]"
#
#   Parameter:
#
#   --shuffle
#	Take a page from each PDF input file in turn before taking another from each file.
#	If this option is not specified then all of the pages from a PDF file are appended
#	to the output PDF file before the next input PDF file is processed.
#
#   --verbose
#   Write information about the doings of this tool to stderr.
#
import sys
import os
import getopt
import tempfile
import shutil
from CoreFoundation import *
from Quartz.CoreGraphics import *

verbose = False

def createPDFDocumentWithPath(path):
	global verbose
	if verbose:
		print "Creating PDF document from file %s" % (path)
	return CGPDFDocumentCreateWithURL(CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, path, len(path), False))

def writePageFromDoc(writeContext, doc, pageNum):

	global verbose
	page = CGPDFDocumentGetPage(doc, pageNum)
	if page:
		mediaBox = CGPDFPageGetBoxRect(page, kCGPDFMediaBox)
		if CGRectIsEmpty(mediaBox):
			mediaBox = None
			
		CGContextBeginPage(writeContext, mediaBox)
		CGContextDrawPDFPage(writeContext, page)
		CGContextEndPage(writeContext)
		if verbose:
			print "Copied page %d from %s" % (pageNum, doc)

def shufflePages(writeContext, docs, maxPages):
	
	for pageNum in xrange(1, maxPages + 1):
		for doc in docs:
			writePageFromDoc(writeContext, doc, pageNum)
				
def append(writeContext, docs, maxPages):

	for doc in docs:
		for pageNum in xrange(1, maxPages + 1) :
			writePageFromDoc(writeContext, doc, pageNum)

def main(argv):

	global verbose

	# The PDF context we will draw into to create a new PDF
	writeContext = None

	# If True then generate more verbose information
	source = None
	shuffle = False
	
	# Parse the command line options
	try:
		options, args = getopt.getopt(argv, "o:sv", ["output=", "shuffle", "verbose"])

	except getopt.GetoptError:
		usage()
		sys.exit(2)

	for option, arg in options:

		if option in ("-o", "--output") :
			if verbose:
				print "Setting %s as the destination." % (arg)
			writeContext = CGPDFContextCreateWithURL(CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, arg, len(arg), False), None, None)

		elif option in ("-s", "--shuffle") :
			if verbose :
				print "Shuffle pages to the output file."
			shuffle = True

		elif option in ("-v", "--verbose") :
			print "Verbose mode enabled."
			verbose = True

		else :
			print "Unknown argument: %s" % (option)
	
	if writeContext:
		# create PDFDocuments for all of the files.
		docs = map(createPDFDocumentWithPath, args)
		
		# find the maximum number of pages.
		maxPages = 0
		for doc in docs:
			if CGPDFDocumentGetNumberOfPages(doc) > maxPages:
				maxPages = CGPDFDocumentGetNumberOfPages(doc)
	
		if shuffle:
			shufflePages(writeContext, docs, maxPages)
		else:
			append(writeContext, docs, maxPages)
		
		CGPDFContextClose(writeContext)
		del writeContext
		#CGContextRelease(writeContext)
    
def usage():
	print "Usage: join [--output <file>] [--shuffle] [--verbose]"

if __name__ == "__main__":
	main(sys.argv[1:])

Compile & Build Mono on Mac OS X

In spite of what you might still read on http://www.mono-project.com/, mono source moved to github.com/mono/mono. To build and compile on the mac however the simplest instructions are still the "One Stop Shop Build Script" at the bottom of http://www.mono-project.com/Compiling_Mono_on_OSX. They worked for me first time although I hit a couple of issues:

  1. Having a space in the path to where I built it broke the build script
  2. Fetching the mono repo from git failed several times. This may - or may not - be related to the OS X 10.9 Mavericks / Versions issue noted at http://www.git-tower.com/blog/make-git-rebase-safe-on-osx/ but I've had no further problems since following their instruction to
    git config --global core.trustctime false

New Microsoft Remote Desktop client for Mac

Remote desktop for Mac is old, and can't always connect. It can't connect to Windows 8.1 for instance. I keep getting the "Remote desktop connection cannot verify the identity of the computer that you want to connect to", even though I tell it to connect anyway.

If like me your first reaction to "it doesn't work" was to try the "Check for Upgrades" menu item then you'll want to know that _that_ doesn't work either.

Instead, go straight to the App store and install it from there. The spiffy new version is a great new app and works just fine.

Asp.Net MVC 4 on Mono and Windows

Having at last got an Asp.Net Mvc 4 project template working on the Mac/Xamarin/Mono, I came to grief again when deploying it to a Windows hosted server. The problem is that whereas mono works without Microsoft.Web.Infrastructure.dll (and indeed is likely to give errors if you have it), for hosting on Windows you must re-include it.
So my deploy process now includes putting Microsoft.Web.Infrastructure.dll back in the web application bin/ directory; and now I can develop on the Mac and deploy to a Windows Server.