// A re-implementation of "mutool merge" in JavaScript. function graftObject(dstDoc, srcDoc, srcObj, map) { var srcNum, dstRef, dstObj if (!map) map = [] if (srcObj.isIndirect()) { srcNum = srcObj.toIndirect() if (map[srcNum]) return map[srcNum] map[srcNum] = dstRef = dstDoc.createObject() dstRef.writeObject(graftObject(dstDoc, srcDoc, srcObj.resolve(), map)) if (srcObj.isStream()) dstRef.writeRawStream(srcObj.readRawStream()) return dstRef } if (srcObj.isArray()) { dstObj = dstDoc.newArray() srcObj.forEach(function (key, val) { dstObj[key] = graftObject(dstDoc, srcDoc, val, map) }) return dstObj } if (srcObj.isDictionary()) { dstObj = dstDoc.newDictionary() srcObj.forEach(function (key, val) { dstObj[key] = graftObject(dstDoc, srcDoc, val, map) }) return dstObj } return srcObj /* primitive objects are not bound to a document */ } function copyPage(dstDoc, srcDoc, pageNumber, map) { var srcPage, dstPage, offset srcPage = srcDoc.findPage(pageNumber) dstPage = dstDoc.newDictionary() dstPage.Type = dstDoc.newName("Page") if (srcPage.MediaBox) dstPage.MediaBox = graftObject(dstDoc, srcDoc, srcPage.MediaBox, map) if (srcPage.Rotate) dstPage.Rotate = graftObject(dstDoc, srcDoc, srcPage.Rotate, map) if (srcPage.Resources) dstPage.Resources = graftObject(dstDoc, srcDoc, srcPage.Resources, map) if (srcPage.Contents) dstPage.Contents = graftObject(dstDoc, srcDoc, srcPage.Contents, map) dstDoc.insertPage(-1, dstDoc.addObject(dstPage)) } function impose() { var imposed, back, front, i imposed = new PDFDocument() back = new PDFDocument('reordered-nup.pdf') front = new PDFDocument('systems-rotated.pdf') print('Mixing cover and objects') copyPage(imposed, back, 0, []); copyPage(imposed, back, 1, []); for (i=0;i<8;i++) { copyPage(imposed, back, i+2, []); copyPage(imposed, front, i, []); } print('Writing cover') imposed.save('species-mixed.pdf', 'compress') } impose()