Created
October 11, 2016 17:24
-
-
Save JoelGeraci-Datalogics/2e1878f78812ed6b162f74204b24d722 to your computer and use it in GitHub Desktop.
Converts PDF Note Annotations to Page Content
This file contains 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
/* | |
* Copyright Datalogics, Inc. 2015 | |
*/ | |
import com.adobe.fontengine.font.Font; | |
import com.adobe.internal.io.ByteReader; | |
import com.adobe.internal.io.InputStreamByteReader; | |
import com.adobe.pdfjt.core.types.ASName; | |
import com.adobe.pdfjt.pdf.content.Content; | |
import com.adobe.pdfjt.pdf.content.InstructionFactory; | |
import com.adobe.pdfjt.pdf.contentmodify.ContentWriter; | |
import com.adobe.pdfjt.pdf.contentmodify.ModifiableContent; | |
import com.adobe.pdfjt.pdf.document.PDFDocument; | |
import com.adobe.pdfjt.pdf.document.PDFOpenOptions; | |
import com.adobe.pdfjt.pdf.graphics.PDFRectangle; | |
import com.adobe.pdfjt.pdf.graphics.font.PDFFont; | |
import com.adobe.pdfjt.pdf.graphics.font.PDFFontSimple; | |
import com.adobe.pdfjt.pdf.interactive.annotation.PDFAnnotationEnum; | |
import com.adobe.pdfjt.pdf.interactive.annotation.PDFAnnotationList; | |
import com.adobe.pdfjt.pdf.interactive.annotation.PDFAnnotationMarkup; | |
import com.adobe.pdfjt.pdf.interactive.annotation.PDFAppearanceCharacteristics; | |
import com.adobe.pdfjt.pdf.page.PDFPage; | |
import com.adobe.pdfjt.pdf.page.PDFPageTree; | |
import com.adobe.pdfjt.services.ap.AppearanceService; | |
import com.adobe.pdfjt.services.ap.TextFormatterImpl; | |
import com.adobe.pdfjt.services.ap.spi.APContext; | |
import com.adobe.pdfjt.services.ap.spi.APResources; | |
import com.adobe.pdfjt.services.formflattener.FormFlattener; | |
import com.adobe.pdfjt.services.forms.FormFieldManager; | |
import com.adobe.pdfjt.services.forms.FormFieldService; | |
import com.adobe.pdfjt.services.forms.TextFieldOptions; | |
import com.datalogics.pdf.document.DocumentHelper; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.util.EnumSet; | |
import java.util.HashMap; | |
public class SpeakerNotesToContent { | |
public static final String INPUT = "YOUR_INPUT_FILE_NAME"; | |
public static final double additionalWidth = 2.5 * 72; | |
public static final double margin = .25 * 72; | |
static public void main(String[] args) throws Exception { | |
File file = new File(INPUT); | |
FileInputStream fis = new FileInputStream(file); | |
ByteReader byteReader = new InputStreamByteReader(fis); | |
PDFDocument pdfDocument = PDFDocument.newInstance(byteReader, PDFOpenOptions.newInstance()); | |
// Run a few checks to be sure we have a file that was created by | |
// Acrobat from PowerPoint. | |
if (pdfDocument.getDocumentInfo().getCreator().contains("Acrobat PDFMaker") | |
&& pdfDocument.getDocumentInfo().getCreator().contains("PowerPoint")) { | |
PDFPageTree pages = pdfDocument.requirePages(); | |
// Setup Form Field Manager | |
FormFieldManager formFieldManager = FormFieldService.getAcroFormFieldManager(pdfDocument); | |
TextFieldOptions textFieldOptions = new TextFieldOptions(); | |
textFieldOptions.setFont(PDFFontSimple.newInstance(pdfDocument, ASName.k_Helvetica, ASName.k_Type1)); | |
textFieldOptions.setFontColor(new double[] { 0, 0, 0 }); | |
textFieldOptions.setFontSize(8); | |
textFieldOptions.setMultiLine(true); | |
PDFAppearanceCharacteristics pdfAppearanceCharacteristics = PDFAppearanceCharacteristics.newInstance(pdfDocument); | |
pdfAppearanceCharacteristics.setBackgroundColor(new double[] { 1, 1, 1 }); | |
textFieldOptions.setAppearanceCharacteristics(pdfAppearanceCharacteristics); | |
// Iterate over the pages | |
for (int i = 0; i < pages.size(); i++) { | |
// reset page size to be wider by the "additionalWidth" | |
PDFPage page = pages.getPage(i); | |
PDFRectangle cropBox = page.getCropBox(); | |
PDFRectangle newCropBox = PDFRectangle.newInstance(pdfDocument, 0, 0, cropBox.width() + additionalWidth, cropBox.height()); | |
// Both the CropBox and the MediaBox must be set but they can be | |
// set to the same value | |
page.setCropBox(newCropBox); | |
page.setMediaBox(newCropBox); | |
// Create ContentWriter so we can add new drawing instructions | |
// to the page. | |
ContentWriter contentWriter = ContentWriter | |
.newInstance(ModifiableContent.newInstance(page.getContents(), page.getResources())); | |
// Add gray rectangle on right | |
contentWriter.write(InstructionFactory.newGSave()); | |
contentWriter.write(InstructionFactory.newRectangle(cropBox.width(), 0, additionalWidth, cropBox.height())); | |
contentWriter.write(InstructionFactory.newColorFill(new double[] { .25, .25, .25 })); | |
contentWriter.write(InstructionFactory.newFillPath()); | |
contentWriter.write(InstructionFactory.newGRestore()); | |
// Add the line at the right edge of the presentation | |
contentWriter.write(InstructionFactory.newGSave()); | |
contentWriter.write(InstructionFactory.newMoveTo(cropBox.width(), 0)); | |
contentWriter.write(InstructionFactory.newLineTo(cropBox.width(), cropBox.height())); | |
contentWriter.write(InstructionFactory.newLineWidth(1)); | |
contentWriter.write(InstructionFactory.newStrokePath()); | |
contentWriter.write(InstructionFactory.newGRestore()); | |
// Add shadow for white rectangle on right, use same position | |
// but offset by 3 points. | |
contentWriter.write(InstructionFactory.newGSave()); | |
contentWriter.write(InstructionFactory.newRectangle(cropBox.width() - margin + 3, margin - 3, additionalWidth, | |
cropBox.height() - (margin * 2))); | |
contentWriter.write(InstructionFactory.newColorFill(new double[] { 0, 0, 0 })); | |
contentWriter.write(InstructionFactory.newFillPath()); | |
contentWriter.write(InstructionFactory.newGRestore()); | |
// Add white rectangle on right | |
contentWriter.write(InstructionFactory.newGSave()); | |
contentWriter.write(InstructionFactory.newRectangle(cropBox.width() - margin, 0 + margin, additionalWidth, | |
cropBox.height() - (margin * 2))); | |
contentWriter.write(InstructionFactory.newColorFill(new double[] { 1, 1, 1 })); | |
contentWriter.write(InstructionFactory.newColorStroke(new double[] { 0, 0, 0 })); | |
contentWriter.write(InstructionFactory.newLineWidth(1)); | |
contentWriter.write(InstructionFactory.newCloseFillAndStrokePath()); | |
contentWriter.write(InstructionFactory.newGRestore()); | |
// Add content to page | |
Content newContent = contentWriter.close(); | |
page.getContents().addContents(newContent.getContentStream()); | |
PDFAnnotationList annotationList = page.getAnnotationList(); | |
// Run a few checks to be sure the first annotation is the one | |
// we're expecting. | |
if (annotationList != null && annotationList.size() == 1 && annotationList.get(0).getSubtype() == ASName.k_Text) { | |
PDFAnnotationMarkup speakerTextNote = (PDFAnnotationMarkup) annotationList.get(0); | |
if (speakerTextNote.getTitle().matches("Presenter")) { | |
String speakerTextNoteText = "Slide Notes:\r\n\r\n" + speakerTextNote.getContents(); | |
// remove the annotation | |
annotationList.remove(speakerTextNote); | |
// Add a text field whose value is the same as the | |
// content | |
// of the annotation added by Acrobat and using the text | |
// field options defined above. | |
formFieldManager.addTextField("PresenterNotePage_" + page.getPageNumber(), speakerTextNoteText, | |
PDFRectangle.newInstance(pdfDocument, cropBox.width(), (margin * 2), | |
cropBox.width() + additionalWidth - (margin * 2), cropBox.height() - (margin * 2)), | |
page, textFieldOptions); | |
} | |
} | |
} | |
// Set up the Appearance Context so we can generate the appearances | |
// of the text fields. | |
APResources apResources = new APResources(pdfDocument.getCosDocument().getOptions().getFontSet(), | |
pdfDocument.getCosDocument().getOptions().getDocLocale(), new HashMap<Font, PDFFont>()); | |
APContext apContext = new APContext(apResources, true, null); | |
apContext.setAnnotationsToBeProcessed(EnumSet.of(PDFAnnotationEnum.Widget)); | |
// Generate appearances for the newly added text fields then flatten | |
// them. | |
AppearanceService.generateAppearances(pdfDocument, apContext, new TextFormatterImpl(pdfDocument)); | |
FormFlattener.flattenDocument(apContext, pdfDocument, new TextFormatterImpl(pdfDocument)); | |
DocumentHelper.saveFullAndClose(pdfDocument, INPUT.replace("input", "output").replace(".pdf", "_Notes.pdf")); | |
} else { | |
System.out.println("Not a PDF from PowerPoint"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment