001: /**
002: * Copyright (c) 2005, www.pdfbox.org
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are met:
007: *
008: * 1. Redistributions of source code must retain the above copyright notice,
009: * this list of conditions and the following disclaimer.
010: * 2. Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: * 3. Neither the name of pdfbox; nor the names of its
014: * contributors may be used to endorse or promote products derived from this
015: * software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
021: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: *
028: * http://www.pdfbox.org
029: *
030: */package org.pdfbox.examples.pdmodel;
031:
032: import org.pdfbox.pdmodel.PDDocument;
033: import org.pdfbox.pdmodel.PDPage;
034: import org.pdfbox.pdmodel.common.PDRectangle;
035: import org.pdfbox.pdmodel.edit.PDPageContentStream;
036: import org.pdfbox.pdmodel.font.PDFont;
037: import org.pdfbox.pdmodel.font.PDType1Font;
038: import org.pdfbox.pdmodel.graphics.color.PDGamma;
039: import org.pdfbox.pdmodel.interactive.action.type.PDActionURI;
040: import org.pdfbox.pdmodel.interactive.annotation.PDAnnotationLine;
041: import org.pdfbox.pdmodel.interactive.annotation.PDAnnotationSquareCircle;
042: import org.pdfbox.pdmodel.interactive.annotation.PDAnnotationTextMarkup;
043: import org.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink;
044: import org.pdfbox.pdmodel.interactive.annotation.PDBorderStyleDictionary;
045:
046: import java.util.List;
047:
048: /**
049: * This is an example on how to add annotations to pages of a PDF document.
050: *
051: * @author Paul King
052: * @version $Revision: 1.2 $
053: */
054: public class Annotation {
055: private Annotation() {
056: //utility class, should not be instantiated.
057: }
058:
059: /**
060: * This will create a doucument showing various annotations.
061: *
062: * @param args The command line arguments.
063: *
064: * @throws Exception If there is an error parsing the document.
065: */
066: public static void main(String[] args) throws Exception {
067: if (args.length != 1) {
068: usage();
069: } else {
070: PDDocument document = new PDDocument();
071:
072: try {
073: PDPage page = new PDPage();
074: document.addPage(page);
075: List annotations = page.getAnnotations();
076:
077: // Setup some basic reusable objects/constants
078: // Annotations themselves can only be used once!
079:
080: float inch = 72;
081: PDGamma colourRed = new PDGamma();
082: colourRed.setR(1);
083: PDGamma colourBlue = new PDGamma();
084: colourBlue.setB(1);
085: PDGamma colourBlack = new PDGamma();
086:
087: PDBorderStyleDictionary borderThick = new PDBorderStyleDictionary();
088: borderThick.setWidth(inch / 12); // 12th inch
089: PDBorderStyleDictionary borderThin = new PDBorderStyleDictionary();
090: borderThin.setWidth(inch / 72); // 1 point
091: PDBorderStyleDictionary borderULine = new PDBorderStyleDictionary();
092: borderULine
093: .setStyle(PDBorderStyleDictionary.STYLE_UNDERLINE);
094: borderULine.setWidth(inch / 72); // 1 point
095:
096: float pw = page.getMediaBox().getUpperRightX();
097: float ph = page.getMediaBox().getUpperRightY();
098:
099: // First add some text, two lines we'll add some annotations to this later
100:
101: PDFont font = PDType1Font.HELVETICA_BOLD;
102:
103: PDPageContentStream contentStream = new PDPageContentStream(
104: document, page);
105: contentStream.beginText();
106: contentStream.setFont(font, 18);
107: contentStream.moveTextPositionByAmount(inch, ph - inch
108: - 18);
109: contentStream.drawString("PDFBox");
110: contentStream.moveTextPositionByAmount(0, -(inch / 2));
111: contentStream.drawString("Click Here");
112: contentStream.endText();
113:
114: contentStream.close();
115:
116: // Now add the markup annotation, a highlight to PDFBox text
117: PDAnnotationTextMarkup txtMark = new PDAnnotationTextMarkup(
118: PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
119: txtMark.setColour(colourBlue);
120: txtMark.setConstantOpacity((float) 0.2); // Make the highlight 20% transparent
121:
122: // Set the rectangle containing the markup
123:
124: float textWidth = (font.getStringWidth("PDFBox") / 1000) * 18;
125: PDRectangle position = new PDRectangle();
126: position.setLowerLeftX(inch);
127: position.setLowerLeftY(ph - inch - 18);
128: position.setUpperRightX(72 + textWidth);
129: position.setUpperRightY(ph - inch);
130: txtMark.setRectangle(position);
131:
132: // work out the points forming the four corners of the annotations
133: // set out in anti clockwise form (Completely wraps the text)
134: // OK, the below doesn't match that description.
135: // It's what acrobat 7 does and displays properly!
136: float[] quads = new float[8];
137:
138: quads[0] = position.getLowerLeftX(); // x1
139: quads[1] = position.getUpperRightY() - 2; // y1
140: quads[2] = position.getUpperRightX(); // x2
141: quads[3] = quads[1]; // y2
142: quads[4] = quads[0]; // x3
143: quads[5] = position.getLowerLeftY() - 2; // y3
144: quads[6] = quads[2]; // x4
145: quads[7] = quads[5]; // y5
146:
147: txtMark.setQuadPoints(quads);
148: txtMark.setContents("Highlighted since it's important");
149:
150: annotations.add(txtMark);
151:
152: // Now add the link annotation, so the clickme works
153: PDAnnotationLink txtLink = new PDAnnotationLink();
154: txtLink.setBorderStyle(borderULine);
155:
156: // Set the rectangle containing the link
157:
158: textWidth = (font.getStringWidth("Click Here") / 1000) * 18;
159: position = new PDRectangle();
160: position.setLowerLeftX(inch);
161: position.setLowerLeftY(ph - (float) (1.5 * inch) - 20); // down a couple of points
162: position.setUpperRightX(72 + textWidth);
163: position.setUpperRightY(ph - (float) (1.5 * inch));
164: txtLink.setRectangle(position);
165:
166: // add an action
167: PDActionURI action = new PDActionURI();
168: action.setURI("http://www.pdfbox.org");
169: txtLink.setAction(action);
170:
171: annotations.add(txtLink);
172:
173: // Now draw a few more annotations
174:
175: PDAnnotationSquareCircle aCircle = new PDAnnotationSquareCircle(
176: PDAnnotationSquareCircle.SUB_TYPE_CIRCLE);
177: aCircle.setContents("Circle Annotation");
178: aCircle.setInteriorColour(colourRed); // Fill in circle in red
179: aCircle.setColour(colourBlue); // The border itself will be blue
180: aCircle.setBorderStyle(borderThin);
181:
182: // Place the annotation on the page, we'll make this 1" round
183: // 3" down, 1" in on the page
184:
185: position = new PDRectangle();
186: position.setLowerLeftX(inch);
187: position.setLowerLeftY(ph - (3 * inch) - inch); // 1" height, 3" down
188: position.setUpperRightX(2 * inch); // 1" in, 1" width
189: position.setUpperRightY(ph - (3 * inch)); // 3" down
190: aCircle.setRectangle(position);
191:
192: // add to the annotations on the page
193: annotations.add(aCircle);
194:
195: // Now a square annotation
196:
197: PDAnnotationSquareCircle aSquare = new PDAnnotationSquareCircle(
198: PDAnnotationSquareCircle.SUB_TYPE_SQUARE);
199: aSquare.setContents("Square Annotation");
200: aSquare.setColour(colourRed); // Outline in red, not setting a fill
201: aSquare.setBorderStyle(borderThick);
202:
203: // Place the annotation on the page, we'll make this 1" (72points) square
204: // 3.5" down, 1" in from the right on the page
205:
206: position = new PDRectangle(); // Reuse the variable, but note it's a new object!
207: position.setLowerLeftX(pw - (2 * inch)); // 1" in from right, 1" wide
208: position
209: .setLowerLeftY(ph - (float) (3.5 * inch) - inch); // 1" height, 3.5" down
210: position.setUpperRightX(pw - inch); // 1" in from right
211: position.setUpperRightY(ph - (float) (3.5 * inch)); // 3.5" down
212: aSquare.setRectangle(position);
213:
214: // add to the annotations on the page
215: annotations.add(aSquare);
216:
217: // Now we want to draw a line between the two, one end with an open arrow
218:
219: PDAnnotationLine aLine = new PDAnnotationLine();
220:
221: aLine
222: .setEndPointEndingStyle(PDAnnotationLine.LE_OPEN_ARROW);
223: aLine.setContents("Circle->Square");
224: aLine.setCaption(true); // Make the contents a caption on the line
225:
226: // Set the rectangle containing the line
227:
228: position = new PDRectangle(); // Reuse the variable, but note it's a new object!
229: position.setLowerLeftX(2 * inch); // 1" in + width of circle
230: position
231: .setLowerLeftY(ph - (float) (3.5 * inch) - inch); // 1" height, 3.5" down
232: position.setUpperRightX(pw - inch - inch); // 1" in from right, and width of square
233: position.setUpperRightY(ph - (3 * inch)); // 3" down (top of circle)
234: aLine.setRectangle(position);
235:
236: // Now set the line position itself
237: float[] linepos = new float[4];
238: linepos[0] = 2 * inch; // x1 = rhs of circle
239: linepos[1] = ph - (float) (3.5 * inch); // y1 halfway down circle
240: linepos[2] = pw - (2 * inch); // x2 = lhs of square
241: linepos[3] = ph - (4 * inch); // y2 halfway down square
242: aLine.setLine(linepos);
243:
244: aLine.setBorderStyle(borderThick);
245: aLine.setColour(colourBlack);
246:
247: // add to the annotations on the page
248: annotations.add(aLine);
249:
250: // Finally all done
251:
252: document.save(args[0]);
253: } finally {
254: document.close();
255: }
256: }
257: }
258:
259: /**
260: * This will print the usage for this document.
261: */
262: private static void usage() {
263: System.err
264: .println("Usage: java org.pdfbox.examples.pdmodel.Annotation <output-pdf>");
265: }
266: }
|