Codebase list libpdfbox2-java / 4539669
New upstream version 2.0.19 Markus Koschany 4 years ago
88 changed file(s) with 2684 addition(s) and 804 deletion(s). Raw diff Collapse all Expand all
0 Release Notes -- Apache PDFBox -- Version 2.0.18
0 Release Notes -- Apache PDFBox -- Version 2.0.19
11
22 Introduction
33 ------------
44
55 The Apache PDFBox library is an open source Java tool for working with PDF documents.
66
7 This is an incremental bugfix release based on the earlier 2.0.17 release. It contains
7 This is an incremental bugfix release based on the earlier 2.0.18 release. It contains
88 a couple of fixes and small improvements.
99
1010 For more details on these changes and all the other fixes and improvements
1313
1414 Bug
1515
16 [PDFBOX-4654] - PDFToImage shows reader image formats in usage
17 [PDFBOX-4655] - ImageIOUtil.WriteImage creates huge PNG images when used with default quality on jdk11
18 [PDFBOX-4659] - PDFBOX-3531 has re-appeared when trying to use "sun.java2d.cmm.kcms.KcmsServiceProvider" in JAVA 1.8_222
19 [PDFBOX-4661] - Regression No Unicode mapping with Identity-H font
20 [PDFBOX-4662] - ClassCastException: org.bouncycastle.asn1.DLTaggedObject cannot be cast to org.bouncycastle.asn1.DERTaggedObject
21 [PDFBOX-4665] - PDImageXObject createFromFileByExtension does not close FileInputStream in event of error
22 [PDFBOX-4666] - StackOverflowError with PDFTextStripper.getText()
23 [PDFBOX-4667] - Issue in FontMapperImpl#isCharSetMatch when font codePageRange is -1
24 [PDFBOX-4672] - Draws the attachment image to the PDF document, and the image displays as a black block
25 [PDFBOX-4674] - PDF Page Render Background Image has Gray Smudges
26 [PDFBOX-4678] - Use PDFontFactory. CreateDefaultFont font to render text, the exported PDF document has a mistake
27 [PDFBOX-4683] - Could not find referenced cmap stream Adobe-Japan1-7
28 [PDFBOX-4687] - "Iterator.next()" methods should throw "NoSuchElementException"
29 [PDFBOX-4688] - "BigDecimal(double)" should not be used
30 [PDFBOX-4693] - PDF documents with rotated form field(90° degrees in my case) that apply form flattening appear squ
31 [PDFBOX-4696] - Endless loop in OCSP certificate check
32 [PDFBOX-4701] - TextPosition.equal() fails after getDir()
33 [PDFBOX-4706] - support /UserUnit
34 [PDFBOX-4711] - java.lang.ClassCastException: org.apache.pdfbox.cos.COSDictionary cannot be cast to org.apache.pdfbox.cos.COSStream
35 [PDFBOX-4712] - Appearance dictionary should not be empty
36 [PDFBOX-4713] - /AS is required if /AP contains a subdictionary
37 [PDFBOX-4716] - ipag00303.php does not exist, mvn clean install!
16 [PDFBOX-4720] - cmap entries "<0000> <FFFF> <0000>" are cut
17 [PDFBOX-4722] - TestTextStripper doesn't detect when less output
18 [PDFBOX-4724] - Wrong calculation of position in InputStreamSource#readFully
19 [PDFBOX-4727] - ExtractEmbeddedFiles.java example uses name tree keys as file names
20 [PDFBOX-4730] - /OC in form and image XObjects not handled
21 [PDFBOX-4738] - getDocument().getObjects() returns nothing for split result documents
22 [PDFBOX-4741] - NullPointerException in PlainText constructor
23 [PDFBOX-4742] - Incorrect handling of float Infinity and NaN
24 [PDFBOX-4745] - COSObjectKey.hashCode doesn't work for generation numbers > 0
25 [PDFBOX-4750] - java.io.IOException: Error:Unknown type in content stream:COSNull{}
26 [PDFBOX-4753] - NumberFormatException while parsing a certain PDF document
27 [PDFBOX-4755] - Fonts improperly rendered
28 [PDFBOX-4756] - ScratchFileBuffer seek beyond the last page
29 [PDFBOX-4760] - wordSeparator not being inserted when word ends with " "
30 [PDFBOX-4763] - Can't get inline image raw data
31 [PDFBOX-4765] - NPE in ExtractImages.ImageGraphicsEngine().run()
32 [PDFBOX-4771] - JPEG image with transparency can't be extracted
33 [PDFBOX-4772] - Improve memory consumption of PDAbstractAppearanceHandler (2)
34 [PDFBOX-4777] - Avoid OOM for malformed PDFs using a huge First valkue within object streams
3835
3936 New Feature
4037
41 [PDFBOX-4682] - NPE at PDSimpleFont.isStandard14()
38 [PDFBOX-4721] - Move Apache PDFBox from a low-API model
4239
4340 Improvement
4441
45 [PDFBOX-4341] - [Patch] PNGConverter: PNG bytes to PDImageXObject converter
46 [PDFBOX-4653] - Clarify what font is missing when not in resources
47 [PDFBOX-4657] - Use smooth interpolation for stencils too
48 [PDFBOX-4685] - Add example of usage of separation color (spot color)
49 [PDFBOX-4686] - Add text to AcroForm examples
50 [PDFBOX-4689] - Invisible Signature should have empty Appearance Dictionary
51 [PDFBOX-4691] - JPEGFactory should not decode JPEG files when only meta data is needed
52 [PDFBOX-4694] - LockedContents flag
53 [PDFBOX-4695] - PDPropBuildDataDict missing setNonEFontNoWarn
54 [PDFBOX-4710] - allow precise RGB stroke colors with setStrokingColor
55
56 Wish
57
58 [PDFBOX-4699] - ERROR FeatureRecord array not alphabetically sorted by FeatureTag
42 [PDFBOX-4734] - ExtractImages should create CCITT G4 compressed TIFF files when possible
43 [PDFBOX-4735] - WriteDecodedDoc should create an xref table instead of an xref stream
44 [PDFBOX-4762] - Inconsistent handling of incorrect data
45 [PDFBOX-4766] - PDInlineImage.getSuffix() returns null
46 [PDFBOX-4779] - PDFBOX: Update Bouncy Castle Crypto to version 1.64
5947
6048 Task
6149
62 [PDFBOX-4708] - Add PDAcroFormFlattenTest to 2.0 branch
63 [PDFBOX-4715] - Need to add release version for maven-compiler-plugin
50 [PDFBOX-4757] - Enable as much PDAcroFormFlattenTest tests as possible
51 [PDFBOX-4759] - Add tests for PDFBOX-4153 and PDFBOX-4490
6452
6553 Sub-task
6654
67 [PDFBOX-4703] - Support acroform /Ff flag for signature fields
55 [PDFBOX-4731] - Support RenderDestination
56 [PDFBOX-4732] - Support ImageType
6857
6958 Release Contents
7059 ----------------
2222 <parent>
2323 <groupId>org.apache.pdfbox</groupId>
2424 <artifactId>pdfbox-parent</artifactId>
25 <version>2.0.18</version>
25 <version>2.0.19</version>
2626 <relativePath>../parent/pom.xml</relativePath>
2727 </parent>
2828
2222 <parent>
2323 <groupId>org.apache.pdfbox</groupId>
2424 <artifactId>pdfbox-parent</artifactId>
25 <version>2.0.18</version>
25 <version>2.0.19</version>
2626 <relativePath>../parent/pom.xml</relativePath>
2727 </parent>
2828
9595 import org.apache.pdfbox.debugger.ui.ErrorDialog;
9696 import org.apache.pdfbox.debugger.ui.ExtensionFileFilter;
9797 import org.apache.pdfbox.debugger.ui.FileOpenSaveDialog;
98 import org.apache.pdfbox.debugger.ui.ImageTypeMenu;
9899 import org.apache.pdfbox.debugger.ui.LogDialog;
99100 import org.apache.pdfbox.debugger.ui.MapEntry;
100101 import org.apache.pdfbox.debugger.ui.OSXAdapter;
103104 import org.apache.pdfbox.debugger.ui.PageEntry;
104105 import org.apache.pdfbox.debugger.ui.ReaderBottomPanel;
105106 import org.apache.pdfbox.debugger.ui.RecentFiles;
107 import org.apache.pdfbox.debugger.ui.RenderDestinationMenu;
106108 import org.apache.pdfbox.debugger.ui.RotationMenu;
107109 import org.apache.pdfbox.debugger.ui.Tree;
108110 import org.apache.pdfbox.debugger.ui.WindowPrefs;
522524 RotationMenu rotationMenu = RotationMenu.getInstance();
523525 rotationMenu.setEnableMenu(false);
524526 viewMenu.add(rotationMenu.getMenu());
527
528 ImageTypeMenu imageTypeMenu = ImageTypeMenu.getInstance();
529 imageTypeMenu.setEnableMenu(false);
530 viewMenu.add(imageTypeMenu.getMenu());
531
532 RenderDestinationMenu renderDestinationMenu = RenderDestinationMenu.getInstance();
533 renderDestinationMenu.setEnableMenu(false);
534 viewMenu.add(renderDestinationMenu.getMenu());
525535
526536 viewMenu.addSeparator();
527537
851861 * Show a Panel describing color spaces in more detail and interactive way.
852862 * @param csNode the special color space containing node.
853863 */
854 private void showColorPane(Object csNode)
864 private void showColorPane(Object csNode) throws IOException
855865 {
856866 csNode = getUnderneathObject(csNode);
857867
13541364 DocumentEntry documentEntry = new DocumentEntry(document, file.getName());
13551365 ZoomMenu.getInstance().resetZoom();
13561366 RotationMenu.getInstance().setRotationSelection(RotationMenu.ROTATE_0_DEGREES);
1367 ImageTypeMenu.getInstance().setImageTypeSelection(ImageTypeMenu.IMAGETYPE_RGB);
1368 RenderDestinationMenu.getInstance().setRenderDestinationSelection(RenderDestinationMenu.RENDER_DESTINATION_EXPORT);
13571369 tree.setModel(new PDFTreeModel(documentEntry));
13581370 // Root/Pages/Kids/[0] is not always the first page, so use the first row instead:
13591371 tree.setSelectionPath(tree.getPathForRow(1));
3030 import org.apache.pdfbox.cos.COSArray;
3131 import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceN;
3232
33
34 /**
35 *@author Khyrul Bashar.
36 */
37
3833 /**
3934 * A class that provides the necessary UI and functionalities to show the DeviceN color space.
35 *
36 * @author Khyrul Bashar.
37 *
4038 */
4139 public class CSDeviceN
4240 {
43 private PDDeviceN deviceN;
41 private final PDDeviceN deviceN;
4442 private JPanel panel;
4543
4644 /**
4745 * Constructor
4846 *
49 * @param array COSArray instance that holds DeviceN color space
47 * @param array COSArray instance that holds the DeviceN color space
5048 */
51 public CSDeviceN(COSArray array)
49 public CSDeviceN(COSArray array) throws IOException
5250 {
53 try
54 {
55 deviceN = new PDDeviceN(array);
56 DeviceNColorant[] colorants = getColorantData();
57 initUI(colorants);
58 }
59 catch (IOException e)
60 {
61 throw new RuntimeException(e);
62 }
51 deviceN = new PDDeviceN(array);
52 DeviceNColorant[] colorants = getColorantData();
53 initUI(colorants);
6354 }
6455
6556 /**
3333 import org.apache.pdfbox.pdmodel.graphics.color.PDIndexed;
3434
3535 /**
36 * A class that provides the necessary UI and functionalities to show the Indexed colorspace.
37 *
3638 * @author Khyrul Bashar.
37 */
38
39 /**
40 * A class that provides the necessary UI and functionalities to show the Indexed colorspace.
4139 */
4240 public class CSIndexed
4341 {
44 private PDIndexed indexed;
42 private final PDIndexed indexed;
4543 private JPanel panel;
46 private int colorCount;
44 private final int colorCount;
4745
4846 /**
4947 * Constructor.
50 * @param array COSArray instance for Indexed Colorspace.
48 * @param array COSArray instance for Indexed color space.
49 * @throws java.io.IOException
5150 */
52 public CSIndexed(COSArray array)
51 public CSIndexed(COSArray array) throws IOException
5352 {
54 try
55 {
56 indexed = new PDIndexed(array);
57 colorCount = getHival(array) + 1;
58 initUI(getColorantData());
59 }
60 catch (IOException e)
61 {
62 throw new RuntimeException(e);
63 }
53 indexed = new PDIndexed(array);
54 colorCount = getHival(array) + 1;
55 initUI(getColorantData());
6456 }
6557
6658 /**
3939 import org.apache.pdfbox.pdmodel.graphics.color.PDSeparation;
4040
4141 /**
42 * A class that provides the necessary UI and functionalities to show the Separation color space.
43 *
4244 * @author Khyrul Bashar.
43 */
44
45 /**
46 *A class that provides the necessary UI and functionalities to show the Separation color space.
4745 */
4846 public class CSSeparation implements ChangeListener, ActionListener
4947 {
5250 private JLabel colorBar;
5351 private JPanel panel;
5452
55 private PDSeparation separation;
53 private final PDSeparation separation;
5654 private float tintValue = 1;
5755
5856 /**
5957 * Constructor
60 * @param array COSArray instance of the separation color space.
61 */
62 public CSSeparation(COSArray array)
63 {
64 try
65 {
66 separation = new PDSeparation(array);
67 }
68 catch (IOException e)
69 {
70 throw new RuntimeException(e);
71 }
58 *
59 * @param array COSArray instance of the Separation color space.
60 *
61 * @throws java.io.IOException
62 */
63 public CSSeparation(COSArray array) throws IOException
64 {
65 separation = new PDSeparation(array);
7266 initUI();
7367 initValues();
7468 }
7670 /**
7771 * initialize all the UI elements and arrange them.
7872 */
79 private void initUI()
73 private void initUI() throws IOException
8074 {
8175 Font boldFont = new Font(Font.MONOSPACED, Font.BOLD, 20);
8276
204198 @Override
205199 public void stateChanged(ChangeEvent changeEvent)
206200 {
207 int value = slider.getValue();
208 tintValue = getFloatRepresentation(value);
209 tintField.setText(Float.toString(tintValue));
201 int value = slider.getValue();
202 tintValue = getFloatRepresentation(value);
203 tintField.setText(Float.toString(tintValue));
204 try
205 {
210206 updateColorBar();
207 }
208 catch (IOException ex)
209 {
210 tintField.setText(ex.getMessage());
211 }
211212 }
212213
213214 /**
228229 {
229230 tintField.setText(Float.toString(tintValue));
230231 }
231 }
232
233 private void updateColorBar()
234 {
235 try
236 {
237 float[] rgbValues = separation.toRGB(new float[] {tintValue});
238 colorBar.setBackground(new Color(rgbValues[0], rgbValues[1], rgbValues[2]));
239 }
240 catch (IOException e)
241 {
242 throw new RuntimeException(e);
243 }
232 catch (IOException ex)
233 {
234 tintField.setText(ex.getMessage());
235 }
236 }
237
238 private void updateColorBar() throws IOException
239 {
240 float[] rgbValues = separation.toRGB(new float[] {tintValue});
241 colorBar.setBackground(new Color(rgbValues[0], rgbValues[1], rgbValues[2]));
244242 }
245243
246244 /**
247245 * Set a little border around colorbar. color of the border is the darkest of the colorant.
248246 */
249 private void setColorBarBorder()
250 {
251 try
252 {
253 float[] rgbValues = separation.toRGB(new float[] {1});
254 Color darkest= new Color(rgbValues[0], rgbValues[1], rgbValues[2]);
255 colorBar.setBorder(new BevelBorder(BevelBorder.LOWERED, darkest, darkest));
256 }
257 catch (IOException e)
258 {
259 throw new RuntimeException(e);
260 }
247 private void setColorBarBorder() throws IOException
248 {
249 float[] rgbValues = separation.toRGB(new float[] {1});
250 Color darkest= new Color(rgbValues[0], rgbValues[1], rgbValues[2]);
251 colorBar.setBorder(new BevelBorder(BevelBorder.LOWERED, darkest, darkest));
261252 }
262253
263254 private float getFloatRepresentation(int value)
180180 cs.beginText();
181181 cs.setFont(font, scale / Math.min(Math.abs(scalingFactorX), Math.abs(scalingFactorY)));
182182 // can't use showText() because there's no guarantee we have the unicode
183 cs.appendRawCommands(String.format("<%02X> Tj\n", index).getBytes(Charsets.ISO_8859_1));
183 cs.appendRawCommands(String.format("<%02X> Tj%n", index).getBytes(Charsets.ISO_8859_1));
184184 cs.endText();
185185 cs.close();
186186 doc.addPage(page);
4949 import org.apache.pdfbox.rendering.PDFRenderer;
5050 import org.apache.pdfbox.debugger.PDFDebugger;
5151 import org.apache.pdfbox.debugger.ui.HighResolutionImageIcon;
52 import org.apache.pdfbox.debugger.ui.ImageTypeMenu;
53 import org.apache.pdfbox.debugger.ui.RenderDestinationMenu;
5254 import org.apache.pdfbox.pdmodel.common.PDRectangle;
5355 import org.apache.pdfbox.pdmodel.interactive.action.PDAction;
5456 import org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo;
7779 private JLabel label;
7880 private ZoomMenu zoomMenu;
7981 private RotationMenu rotationMenu;
82 private ImageTypeMenu imageTypeMenu;
83 private RenderDestinationMenu renderDestinationMenu;
8084 private final JLabel statuslabel;
8185 private final PDPage page;
8286 private String labelText = "";
228232 String actionCommand = actionEvent.getActionCommand();
229233 if (ZoomMenu.isZoomMenu(actionCommand) ||
230234 RotationMenu.isRotationMenu(actionCommand) ||
235 ImageTypeMenu.isImageTypeMenu(actionCommand) ||
236 RenderDestinationMenu.isRenderDestinationMenu(actionCommand) ||
231237 actionEvent.getSource() == PDFDebugger.allowSubsampling)
232238 {
233239 startRendering();
239245 {
240246 // render in a background thread: rendering is read-only, so this should be ok, despite
241247 // the fact that PDDocument is not officially thread safe
242 new RenderWorker(ZoomMenu.getZoomScale(),
243 RotationMenu.getRotationDegrees(),
244 PDFDebugger.allowSubsampling.isSelected()
245 ).execute();
248 new RenderWorker().execute();
246249 zoomMenu.setPageZoomScale(ZoomMenu.getZoomScale());
247250 }
248251
255258 rotationMenu = RotationMenu.getInstance();
256259 rotationMenu.addMenuListeners(this);
257260 rotationMenu.setEnableMenu(true);
261
262 imageTypeMenu = ImageTypeMenu.getInstance();
263 imageTypeMenu.addMenuListeners(this);
264 imageTypeMenu.setEnableMenu(true);
265
266 renderDestinationMenu = RenderDestinationMenu.getInstance();
267 renderDestinationMenu.addMenuListeners(this);
268 renderDestinationMenu.setEnableMenu(true);
258269
259270 PDFDebugger.allowSubsampling.setEnabled(true);
260271 PDFDebugger.allowSubsampling.addActionListener(this);
265276 {
266277 zoomMenu.setEnableMenu(false);
267278 rotationMenu.setEnableMenu(false);
279 imageTypeMenu.setEnableMenu(false);
280 renderDestinationMenu.setEnableMenu(false);
268281
269282 PDFDebugger.allowSubsampling.setEnabled(false);
270283 PDFDebugger.allowSubsampling.removeActionListener(this);
369382 */
370383 private final class RenderWorker extends SwingWorker<BufferedImage, Integer>
371384 {
372 private final float scale;
373 private final int rotation;
374 private final boolean allowSubsampling;
375
376 private RenderWorker(float scale, int rotation, boolean allowSubsampling)
377 {
378 this.scale = scale;
379 this.rotation = rotation;
380 this.allowSubsampling = allowSubsampling;
381 }
382
383385 @Override
384386 protected BufferedImage doInBackground() throws IOException
385387 {
388 // rendering can take a long time, so remember all options that are used later
389 float scale = ZoomMenu.getZoomScale();
390 int rotation = RotationMenu.getRotationDegrees();
391
386392 label.setIcon(null);
387393 labelText = "Rendering...";
388394 label.setText(labelText);
395
389396 PDFRenderer renderer = new PDFRenderer(document);
390 renderer.setSubsamplingAllowed(allowSubsampling);
397 renderer.setSubsamplingAllowed(PDFDebugger.allowSubsampling.isSelected());
398
391399 long t0 = System.currentTimeMillis();
392400 statuslabel.setText(labelText);
393 BufferedImage bim = renderer.renderImage(pageIndex, scale);
401 BufferedImage bim = renderer.renderImage(pageIndex, scale, ImageTypeMenu.getImageType(), RenderDestinationMenu.getRenderDestination());
394402 float t = (System.currentTimeMillis() - t0) / 1000f;
395403 labelText = "Rendered in " + t + " second" + (t > 1 ? "s" : "");
396404 statuslabel.setText(labelText);
5252 import org.apache.pdfbox.cos.COSDictionary;
5353 import org.apache.pdfbox.cos.COSFloat;
5454 import org.apache.pdfbox.cos.COSName;
55 import org.apache.pdfbox.cos.COSNull;
5556 import org.apache.pdfbox.cos.COSNumber;
5657 import org.apache.pdfbox.cos.COSStream;
5758 import org.apache.pdfbox.cos.COSString;
456457 }
457458 docu.insertString(docu.getLength(), ">> ", null);
458459 }
460 else if (obj instanceof COSNull)
461 {
462 docu.insertString(docu.getLength(), "null ", null);
463 }
459464 else
460465 {
461466 String str = obj.toString();
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.pdfbox.debugger.ui;
18
19 import javax.swing.ButtonGroup;
20 import javax.swing.JMenu;
21 import javax.swing.JRadioButtonMenuItem;
22
23 import org.apache.pdfbox.rendering.ImageType;
24
25 /**
26 * @author Tilman Hausherr
27 *
28 * A singleton class that provides the imagetype menu for the menubar. To act upon the menu item
29 * selection, the user of the class must add ActionListener which will check for the action command
30 * and act accordingly.
31 */
32 public final class ImageTypeMenu extends MenuBase
33 {
34 public static final String IMAGETYPE_RGB = "RGB";
35 public static final String IMAGETYPE_ARGB = "ARGB";
36 public static final String IMAGETYPE_GRAY = "Gray";
37 public static final String IMAGETYPE_BITONAL = "Bitonal";
38
39 private static ImageTypeMenu instance;
40 private JRadioButtonMenuItem rgbItem;
41 private JRadioButtonMenuItem argbItem;
42 private JRadioButtonMenuItem grayItem;
43 private JRadioButtonMenuItem bitonalItem;
44
45 /**
46 * Constructor.
47 */
48 private ImageTypeMenu()
49 {
50 setMenu(createMenu());
51 }
52
53 /**
54 * Provides the ImageTypeMenu instance.
55 * @return ImageTypeMenu instance.
56 */
57 public static ImageTypeMenu getInstance()
58 {
59 if (instance == null)
60 {
61 instance = new ImageTypeMenu();
62 }
63 return instance;
64 }
65
66 /**
67 * Set the image type selection.
68 * @param selection String instance.
69 */
70 public void setImageTypeSelection(String selection)
71 {
72 if (IMAGETYPE_RGB.equals(selection))
73 {
74 rgbItem.setSelected(true);
75 }
76 else if (IMAGETYPE_ARGB.equals(selection))
77 {
78 argbItem.setSelected(true);
79 }
80 else if (IMAGETYPE_GRAY.equals(selection))
81 {
82 grayItem.setSelected(true);
83 }
84 else if (IMAGETYPE_BITONAL.equals(selection))
85 {
86 bitonalItem.setSelected(true);
87 }
88 else
89 {
90 throw new IllegalArgumentException();
91 }
92 }
93
94 public static boolean isImageTypeMenu(String actionCommand)
95 {
96 return IMAGETYPE_RGB.equals(actionCommand) || IMAGETYPE_ARGB.equals(actionCommand) ||
97 IMAGETYPE_GRAY.equals(actionCommand) || IMAGETYPE_BITONAL.equals(actionCommand);
98 }
99
100 public static ImageType getImageType()
101 {
102 if (instance.argbItem.isSelected())
103 {
104 return ImageType.ARGB;
105 }
106 if (instance.grayItem.isSelected())
107 {
108 return ImageType.GRAY;
109 }
110 if (instance.bitonalItem.isSelected())
111 {
112 return ImageType.BINARY;
113 }
114 return ImageType.RGB;
115 }
116
117 public static ImageType getImageType(String actionCommand)
118 {
119 if (IMAGETYPE_RGB.equals(actionCommand))
120 {
121 return ImageType.RGB;
122 }
123 else if (IMAGETYPE_ARGB.equals(actionCommand))
124 {
125 return ImageType.ARGB;
126 }
127 else if (IMAGETYPE_GRAY.equals(actionCommand))
128 {
129 return ImageType.GRAY;
130 }
131 else if (IMAGETYPE_BITONAL.equals(actionCommand))
132 {
133 return ImageType.BINARY;
134 }
135 else
136 {
137 throw new IllegalArgumentException();
138 }
139 }
140
141 private JMenu createMenu()
142 {
143 JMenu menu = new JMenu();
144 menu.setText("Image type");
145
146 rgbItem = new JRadioButtonMenuItem();
147 argbItem = new JRadioButtonMenuItem();
148 grayItem = new JRadioButtonMenuItem();
149 bitonalItem = new JRadioButtonMenuItem();
150 rgbItem.setSelected(true);
151
152 ButtonGroup bg = new ButtonGroup();
153 bg.add(rgbItem);
154 bg.add(argbItem);
155 bg.add(grayItem);
156 bg.add(bitonalItem);
157
158 rgbItem.setText(IMAGETYPE_RGB);
159 argbItem.setText(IMAGETYPE_ARGB);
160 grayItem.setText(IMAGETYPE_GRAY);
161 bitonalItem.setText(IMAGETYPE_BITONAL);
162
163 menu.add(rgbItem);
164 menu.add(argbItem);
165 menu.add(grayItem);
166 menu.add(bitonalItem);
167
168 return menu;
169 }
170 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.pdfbox.debugger.ui;
18
19 import javax.swing.ButtonGroup;
20 import javax.swing.JMenu;
21 import javax.swing.JRadioButtonMenuItem;
22
23 import org.apache.pdfbox.rendering.RenderDestination;
24
25 /**
26 * @author Tilman Hausherr
27 *
28 * A singleton class that provides the RenderDestination menu for the menubar. To act upon the menu
29 * item selection, the user of the class must add ActionListener which will check for the action
30 * command and act accordingly.
31 */
32 public final class RenderDestinationMenu extends MenuBase
33 {
34 public static final String RENDER_DESTINATION_EXPORT = "Export";
35 public static final String RENDER_DESTINATION_PRINT = "Print";
36 public static final String RENDER_DESTINATION_VIEW = "View";
37
38 private static RenderDestinationMenu instance;
39 private JRadioButtonMenuItem exportItem;
40 private JRadioButtonMenuItem printItem;
41 private JRadioButtonMenuItem viewItem;
42
43 /**
44 * Constructor.
45 */
46 private RenderDestinationMenu()
47 {
48 setMenu(createMenu());
49 }
50
51 /**
52 * Provides the RenderDestination instance.
53 * @return RenderDestination instance.
54 */
55 public static RenderDestinationMenu getInstance()
56 {
57 if (instance == null)
58 {
59 instance = new RenderDestinationMenu();
60 }
61 return instance;
62 }
63
64 /**
65 * Set the render destination selection.
66 * @param selection String instance.
67 */
68 public void setRenderDestinationSelection(String selection)
69 {
70 if (RENDER_DESTINATION_EXPORT.equals(selection))
71 {
72 exportItem.setSelected(true);
73 }
74 else if (RENDER_DESTINATION_PRINT.equals(selection))
75 {
76 printItem.setSelected(true);
77 }
78 else if (RENDER_DESTINATION_VIEW.equals(selection))
79 {
80 viewItem.setSelected(true);
81 }
82 else
83 {
84 throw new IllegalArgumentException();
85 }
86 }
87
88 public static boolean isRenderDestinationMenu(String actionCommand)
89 {
90 return RENDER_DESTINATION_EXPORT.equals(actionCommand) || RENDER_DESTINATION_PRINT.equals(actionCommand) ||
91 RENDER_DESTINATION_VIEW.equals(actionCommand);
92 }
93
94 public static RenderDestination getRenderDestination()
95 {
96 if (instance.printItem.isSelected())
97 {
98 return RenderDestination.PRINT;
99 }
100 if (instance.viewItem.isSelected())
101 {
102 return RenderDestination.VIEW;
103 }
104 return RenderDestination.EXPORT;
105 }
106
107 public static RenderDestination getRenderDestination(String actionCommand)
108 {
109 if (RENDER_DESTINATION_EXPORT.equals(actionCommand))
110 {
111 return RenderDestination.EXPORT;
112 }
113 else if (RENDER_DESTINATION_PRINT.equals(actionCommand))
114 {
115 return RenderDestination.PRINT;
116 }
117 else if (RENDER_DESTINATION_VIEW.equals(actionCommand))
118 {
119 return RenderDestination.VIEW;
120 }
121 else
122 {
123 throw new IllegalArgumentException();
124 }
125 }
126
127 private JMenu createMenu()
128 {
129 JMenu menu = new JMenu();
130 menu.setText("Render destination");
131
132 exportItem = new JRadioButtonMenuItem();
133 printItem = new JRadioButtonMenuItem();
134 viewItem = new JRadioButtonMenuItem();
135 exportItem.setSelected(true);
136
137 ButtonGroup bg = new ButtonGroup();
138 bg.add(exportItem);
139 bg.add(printItem);
140 bg.add(viewItem);
141
142 exportItem.setText(RENDER_DESTINATION_EXPORT);
143 printItem.setText(RENDER_DESTINATION_PRINT);
144 viewItem.setText(RENDER_DESTINATION_VIEW);
145
146 menu.add(exportItem);
147 menu.add(printItem);
148 menu.add(viewItem);
149
150 return menu;
151 }
152 }
4444
4545 private float pageZoomScale = 1;
4646 private float imageZoomScale = 1;
47 private static final int[] ZOOMS = new int[] { 25, 50, 100, 200, 400, 1000 };
47 private static final int[] ZOOMS = new int[] { 25, 50, 100, 150, 200, 400, 1000, 2000 };
4848
4949 private static ZoomMenu instance;
5050 private final JMenu menu;
2222 <parent>
2323 <groupId>org.apache.pdfbox</groupId>
2424 <artifactId>pdfbox-parent</artifactId>
25 <version>2.0.18</version>
25 <version>2.0.19</version>
2626 <relativePath>../parent/pom.xml</relativePath>
2727 </parent>
2828
2222 <parent>
2323 <groupId>org.apache.pdfbox</groupId>
2424 <artifactId>pdfbox-parent</artifactId>
25 <version>2.0.18</version>
25 <version>2.0.19</version>
2626 <relativePath>../parent/pom.xml</relativePath>
2727 </parent>
2828
127127 {
128128 for (Entry<String, PDComplexFileSpecification> entry : names.entrySet())
129129 {
130 String filename = entry.getKey();
131130 PDComplexFileSpecification fileSpec = entry.getValue();
132131 PDEmbeddedFile embeddedFile = getEmbeddedFile(fileSpec);
133132 if (embeddedFile != null)
134133 {
135 extractFile(filePath, filename, embeddedFile);
134 extractFile(filePath, fileSpec.getFilename(), embeddedFile);
136135 }
137136 }
138137 }
4646 private static final String XOBJECT_DO = "Do\n";
4747 private static final String SPACE = " ";
4848
49 private static final NumberFormat formatDecimal = NumberFormat.getNumberInstance( Locale.US );
49 private static final NumberFormat FORMATDECIMAL = NumberFormat.getNumberInstance( Locale.US );
5050
5151 /**
5252 * Add a rubber stamp with an jpg image to every page of the given document.
8585 PDImageXObject ximage = PDImageXObject.createFromFile(args[2], document);
8686
8787 // define and set the target rectangle
88 int lowerLeftX = 250;
89 int lowerLeftY = 550;
90 int formWidth = 150;
91 int formHeight = 25;
92 int imgWidth = 50;
93 int imgHeight = 25;
88 float lowerLeftX = 250;
89 float lowerLeftY = 550;
90 float formWidth = 150;
91 float formHeight = 25;
92 float imgWidth = 50;
93 float imgHeight = 25;
9494
9595 PDRectangle rect = new PDRectangle();
9696 rect.setLowerLeftX(lowerLeftX);
138138 COSName xObjectId = resources.add(xobject);
139139
140140 appendRawCommands( os, SAVE_GRAPHICS_STATE );
141 appendRawCommands( os, formatDecimal.format( width ) );
141 appendRawCommands( os, FORMATDECIMAL.format( width ) );
142142 appendRawCommands( os, SPACE );
143 appendRawCommands( os, formatDecimal.format( 0 ) );
143 appendRawCommands( os, FORMATDECIMAL.format( 0 ) );
144144 appendRawCommands( os, SPACE );
145 appendRawCommands( os, formatDecimal.format( 0 ) );
145 appendRawCommands( os, FORMATDECIMAL.format( 0 ) );
146146 appendRawCommands( os, SPACE );
147 appendRawCommands( os, formatDecimal.format( height ) );
147 appendRawCommands( os, FORMATDECIMAL.format( height ) );
148148 appendRawCommands( os, SPACE );
149 appendRawCommands( os, formatDecimal.format( x ) );
149 appendRawCommands( os, FORMATDECIMAL.format( x ) );
150150 appendRawCommands( os, SPACE );
151 appendRawCommands( os, formatDecimal.format( y ) );
151 appendRawCommands( os, FORMATDECIMAL.format( y ) );
152152 appendRawCommands( os, SPACE );
153153 appendRawCommands( os, CONCATENATE_MATRIX );
154154 appendRawCommands( os, SPACE );
3636 */
3737 public UsingTextMatrix()
3838 {
39 super();
4039 }
4140
4241 /**
9998 // text scaling and translation
10099 for (int i=0;i<10;i++)
101100 {
102 contentStream.setTextMatrix(new Matrix(12 + (i * 6), 0, 0, 12+(i*6), 100, 100+i*50));
101 contentStream.setTextMatrix(new Matrix(12f + (i * 6), 0, 0, 12f + (i * 6),
102 100, 100f + i * 50));
103103 contentStream.showText(message + " " + i);
104104 }
105105 contentStream.endText();
4444 /**
4545 * Entry point.
4646 */
47 public static void main(String args[]) throws PrinterException, IOException
47 public static void main(String[] args) throws PrinterException, IOException
4848 {
4949 if (args.length != 1)
5050 {
8181 @Override
8282 public void appendRectangle(Point2D p0, Point2D p1, Point2D p2, Point2D p3) throws IOException
8383 {
84 System.out.printf("appendRectangle %.2f %.2f, %.2f %.2f, %.2f %.2f, %.2f %.2f\n",
84 System.out.printf("appendRectangle %.2f %.2f, %.2f %.2f, %.2f %.2f, %.2f %.2f%n",
8585 p0.getX(), p0.getY(), p1.getX(), p1.getY(),
8686 p2.getX(), p2.getY(), p3.getX(), p3.getY());
8787 }
101101 @Override
102102 public void moveTo(float x, float y) throws IOException
103103 {
104 System.out.printf("moveTo %.2f %.2f\n", x, y);
104 System.out.printf("moveTo %.2f %.2f%n", x, y);
105105 }
106106
107107 @Override
108108 public void lineTo(float x, float y) throws IOException
109109 {
110 System.out.printf("lineTo %.2f %.2f\n", x, y);
110 System.out.printf("lineTo %.2f %.2f%n", x, y);
111111 }
112112
113113 @Override
114114 public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) throws IOException
115115 {
116 System.out.printf("curveTo %.2f %.2f, %.2f %.2f, %.2f %.2f\n", x1, y1, x2, y2, x3, y3);
116 System.out.printf("curveTo %.2f %.2f, %.2f %.2f, %.2f %.2f%n", x1, y1, x2, y2, x3, y3);
117117 }
118118
119119 @Override
6767 Enumeration<String> aliases = keystore.aliases();
6868 String alias;
6969 Certificate cert = null;
70 while (aliases.hasMoreElements())
70 while (cert == null && aliases.hasMoreElements())
7171 {
7272 alias = aliases.nextElement();
7373 setPrivateKey((PrivateKey) keystore.getKey(alias, pin));
7474 Certificate[] certChain = keystore.getCertificateChain(alias);
75 if (certChain == null)
75 if (certChain != null)
7676 {
77 continue;
77 setCertificateChain(certChain);
78 cert = certChain[0];
79 if (cert instanceof X509Certificate)
80 {
81 // avoid expired certificate
82 ((X509Certificate) cert).checkValidity();
83
84 SigUtils.checkCertificateUsage((X509Certificate) cert);
85 }
7886 }
79 setCertificateChain(certChain);
80 cert = certChain[0];
81 if (cert instanceof X509Certificate)
82 {
83 // avoid expired certificate
84 ((X509Certificate) cert).checkValidity();
85
86 SigUtils.checkCertificateUsage((X509Certificate) cert);
87 }
88 break;
8987 }
9088
9189 if (cert == null)
5757 */
5858 public class DrawPrintTextLocations extends PDFTextStripper
5959 {
60 private BufferedImage image;
6160 private AffineTransform flipAT;
6261 private AffineTransform rotateAT;
6362 private AffineTransform transAT;
202201 private void stripPage(int page) throws IOException
203202 {
204203 PDFRenderer pdfRenderer = new PDFRenderer(document);
205 image = pdfRenderer.renderImage(page, SCALE);
206
204 BufferedImage image = pdfRenderer.renderImage(page, SCALE);
207205 PDPage pdPage = document.getPage(page);
208206 PDRectangle cropBox = pdPage.getCropBox();
209207
2020 <parent>
2121 <groupId>org.apache.pdfbox</groupId>
2222 <artifactId>pdfbox-parent</artifactId>
23 <version>2.0.18</version>
23 <version>2.0.19</version>
2424 <relativePath>../parent/pom.xml</relativePath>
2525 </parent>
2626
411411 {
412412 return 0d;
413413 }
414 return Double.valueOf(sb.toString());
414 try
415 {
416 return Double.valueOf(sb.toString());
417 }
418 catch (NumberFormatException ex)
419 {
420 throw new IOException(ex);
421 }
415422 }
416423
417424 private CFFFont parseFont(CFFDataInput input, String name, byte[] topDictIndex) throws IOException
3939 private static final Log LOG = LogFactory.getLog(Type1CharString.class);
4040
4141 private Type1CharStringReader font;
42 private final String fontName, glyphName;
42 private final String fontName;
43 private final String glyphName;
4344 private GeneralPath path = null;
4445 private int width = 0;
4546 private Point2D.Float leftSideBearing = null;
181182 }
182183 else if ("vmoveto".equals(name))
183184 {
184 if (numbers.size() >= 1)
185 if (!numbers.isEmpty())
185186 {
186187 if (isFlex)
187188 {
196197 }
197198 else if ("hmoveto".equals(name))
198199 {
199 if (numbers.size() >= 1)
200 if (!numbers.isEmpty())
200201 {
201202 if (isFlex)
202203 {
218219 }
219220 else if ("hlineto".equals(name))
220221 {
221 if (numbers.size() >= 1)
222 if (!numbers.isEmpty())
222223 {
223224 rlineTo(numbers.get(0), 0);
224225 }
225226 }
226227 else if ("vlineto".equals(name))
227228 {
228 if (numbers.size() >= 1)
229 if (!numbers.isEmpty())
229230 {
230231 rlineTo(0, numbers.get(0));
231232 }
292293 }
293294 else if ("callothersubr".equals(name))
294295 {
295 if (numbers.size() >= 1)
296 if (!numbers.isEmpty())
296297 {
297298 callothersubr(numbers.get(0).intValue());
298299 }
4444 static final int CALLOTHERSUBR = 16;
4545 static final int POP = 17;
4646
47 private final String fontName, glyphName;
47 private final String fontName;
48 private final String glyphName;
4849
4950 /**
5051 * Constructs a new Type1CharStringParser object.
210210 else if ("hintmask".equals(name) || "cntrmask".equals(name))
211211 {
212212 numbers = clearStack(numbers, numbers.size() % 2 != 0);
213 if (numbers.size() > 0)
213 if (!numbers.isEmpty())
214214 {
215215 expandStemHints(numbers, false);
216216 }
307307
308308 private void drawAlternatingLine(List<Number> numbers, boolean horizontal)
309309 {
310 while (numbers.size() > 0)
310 while (!numbers.isEmpty())
311311 {
312312 addCommand(numbers.subList(0, 1), new CharStringCommand(
313313 horizontal ? 6 : 7));
3030 private int vstemCount = 0;
3131 private List<Object> sequence = null;
3232 @SuppressWarnings("unused")
33 private final String fontName, glyphName;
33 private final String fontName;
34 @SuppressWarnings("unused")
35 private final String glyphName;
3436
3537 /**
3638 * Constructs a new Type1CharStringParser object for a Type 1-equivalent font.
390390 // PDFBOX-3450: ignore <>
391391 if (tokenBytes.length > 0)
392392 {
393 // PDFBOX-4661: avoid overflow of the last byte, all following values are undefined
394 int values = Math.min(end - start,
395 255 - (tokenBytes[tokenBytes.length - 1] & 0xFF)) + 1;
396 addMappingFrombfrange(result, startCode, values, tokenBytes);
393 // PDFBOX-4720:
394 // some pdfs use the malformed bfrange <0000> <FFFF> <0000>. Add support by adding a identity
395 // mapping for the whole range instead of cutting it after 255 entries
396 // TODO find a more efficient method to represent all values for a identity mapping
397 if (tokenBytes.length == 2 && start == 0 && end == 0xffff
398 && tokenBytes[0] == 0 && tokenBytes[1] == 0)
399 {
400 for (int i = 0; i < 256; i++)
401 {
402 startCode[1] = (byte) i;
403 tokenBytes[1] = (byte) i;
404 addMappingFrombfrange(result, startCode, 0xff, tokenBytes);
405
406 }
407 }
408 else
409 {
410 // PDFBOX-4661: avoid overflow of the last byte, all following values are undefined
411 int values = Math.min(end - start,
412 255 - (tokenBytes[tokenBytes.length - 1] & 0xFF)) + 1;
413 addMappingFrombfrange(result, startCode, values, tokenBytes);
414 }
397415 }
398416 }
399417 }
3535 /**
3636 * Uses a byte instead of a char buffer for efficiency reasons.
3737 */
38 private final byte buffer[];
38 private final byte[] buffer;
3939 private int bufend = 0;
4040 private int bufpos = 0;
4141
145145 * {@inheritDoc}
146146 */
147147 @Override
148 public int read(byte b[], int off, int len) throws IOException
148 public int read(byte[] b, int off, int len) throws IOException
149149 {
150150 int leftover = bufend - bufpos;
151151 if (len <= leftover)
3636 {
3737 private static final Log LOG = LogFactory.getLog(CmapSubtable.class);
3838
39 private static final long LEAD_OFFSET = 0xD800 - (0x10000 >> 10);
40 private static final long SURROGATE_OFFSET = 0x10000 - (0xD800 << 10) - 0xDC00;
39 private static final long LEAD_OFFSET = 0xD800l - (0x10000 >> 10);
40 private static final long SURROGATE_OFFSET = 0x10000l - (0xD800 << 10) - 0xDC00;
4141
4242 private int platformId;
4343 private int platformEncodingId;
704704 // encoding record
705705 writeUint16(out, CmapTable.PLATFORM_WINDOWS); // platformID
706706 writeUint16(out, CmapTable.ENCODING_WIN_UNICODE_BMP); // platformSpecificID
707 writeUint32(out, 4 * 2 + 4); // offset
707 writeUint32(out, 12); // offset 4 * 2 + 4
708708
709709 // build Format 4 subtable (Unicode BMP)
710710 Iterator<Entry<Integer, Integer>> it = uniToGID.entrySet().iterator();
895895 if (glyphId <= lastgid)
896896 {
897897 // copy width and lsb
898 offset = glyphId * 4;
898 offset = glyphId * 4l;
899899 lastOffset = copyBytes(is, bos, offset, lastOffset, 4);
900900 }
901901 else
905905 // one time only: copy width from lastgid, whose width applies
906906 // to all later glyphs
907907 needLastGidWidth = false;
908 offset = lastgid * 4;
908 offset = lastgid * 4l;
909909 lastOffset = copyBytes(is, bos, offset, lastOffset, 2);
910910
911911 // then go on with lsb from actual glyph (lsb are individual even in monotype fonts)
912912 }
913913
914914 // copy lsb only, as we are beyond numOfHMetrics
915 offset = h.getNumberOfHMetrics() * 4 + (glyphId - h.getNumberOfHMetrics()) * 2;
915 offset = h.getNumberOfHMetrics() * 4l + (glyphId - h.getNumberOfHMetrics()) * 2l;
916916 lastOffset = copyBytes(is, bos, offset, lastOffset, 2);
917917 }
918918 }
3232
3333 <groupId>org.apache.pdfbox</groupId>
3434 <artifactId>pdfbox-parent</artifactId>
35 <version>2.0.18</version>
35 <version>2.0.19</version>
3636 <packaging>pom</packaging>
3737
3838 <name>PDFBox parent</name>
5252 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
5353 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
5454
55 <bouncycastle.version>1.60</bouncycastle.version>
55 <bouncycastle.version>1.64</bouncycastle.version>
5656
5757 <!-- PDFBOX-4479 to build on jdk6 on newer Jenkins -->
5858 <jdk.path>${env.JAVA_HOME}</jdk.path>
6363 <dependency>
6464 <groupId>junit</groupId>
6565 <artifactId>junit</artifactId>
66 <version>4.12</version>
66 <version>4.13</version>
6767 <scope>test</scope>
6868 </dependency>
6969 <dependency>
193193 <plugin>
194194 <groupId>org.owasp</groupId>
195195 <artifactId>dependency-check-maven</artifactId>
196 <version>5.2.4</version>
196 <version>5.3.0</version>
197197 <configuration>
198198 <failBuildOnAnyVulnerability>true</failBuildOnAnyVulnerability>
199199 <!-- https://github.com/jeremylong/DependencyCheck/issues/1574 -->
526526 </developers>
527527
528528 <scm>
529 <connection>scm:svn:http://svn.apache.org/repos/asf/maven/pom/tags/2.0.18/pdfbox-parent</connection>
530 <developerConnection>scm:svn:https://svn.apache.org/repos/asf/maven/pom/tags/2.0.18/pdfbox-parent</developerConnection>
531 <url>http://svn.apache.org/viewvc/maven/pom/tags/2.0.18/pdfbox-parent</url>
529 <connection>scm:svn:http://svn.apache.org/repos/asf/maven/pom/tags/2.0.19/pdfbox-parent</connection>
530 <developerConnection>scm:svn:https://svn.apache.org/repos/asf/maven/pom/tags/2.0.19/pdfbox-parent</developerConnection>
531 <url>http://svn.apache.org/viewvc/maven/pom/tags/2.0.19/pdfbox-parent</url>
532532 </scm>
533533 </project>
2222 <parent>
2323 <groupId>org.apache.pdfbox</groupId>
2424 <artifactId>pdfbox-parent</artifactId>
25 <version>2.0.18</version>
25 <version>2.0.19</version>
2626 <relativePath>../parent/pom.xml</relativePath>
2727 </parent>
2828
657657 <sha512>ed55a65bad6f91104846d28e9e7dcb18b11efbf980a74781350551428bbaecba375d9e22af02edf0f91263c7f668e93ec7c52d397898b7640c2d60e7dd3ae940</sha512>
658658 </configuration>
659659 </execution>
660 <execution>
661 <id>PDFBOX-4750</id>
662 <phase>generate-test-resources</phase>
663 <goals>
664 <goal>wget</goal>
665 </goals>
666 <configuration>
667 <url>https://issues.apache.org/jira/secure/attachment/12991833/PDFBOX-4750-test.pdf</url>
668 <outputDirectory>${project.build.directory}/pdfs</outputDirectory>
669 <outputFileName>PDFBOX-4750.pdf</outputFileName>
670 <sha512>add66ca86b5eb3bfd44fd8c273a81695586d76f6e630b714d4b8db6db5aee5b80e7a6d47b9863a42506773c2c0ee2181469d5cd717dba185b70ef5db7ffb80b9</sha512>
671 </configuration>
672 </execution>
673 <execution>
674 <id>PDFBOX-4153</id>
675 <phase>generate-test-resources</phase>
676 <goals>
677 <goal>wget</goal>
678 </goals>
679 <configuration>
680 <url>https://issues.apache.org/jira/secure/attachment/12914331/WXMDXCYRWFDCMOSFQJ5OAJIAFXYRZ5OA.pdf</url>
681 <outputDirectory>${project.build.directory}/pdfs</outputDirectory>
682 <outputFileName>PDFBOX-4153-WXMDXCYRWFDCMOSFQJ5OAJIAFXYRZ5OA.pdf</outputFileName>
683 <sha512>e69a4ee7ba17c384770d8679586273a23fead36a5775669e5ed4d882d738e8d7c5b5cd48deff2ddeea7900efdb13dee8f4899f9db7945d040ddae8628faea465</sha512>
684 </configuration>
685 </execution>
686 <execution>
687 <id>PDFBOX-4490</id>
688 <phase>generate-test-resources</phase>
689 <goals>
690 <goal>wget</goal>
691 </goals>
692 <configuration>
693 <url>https://issues.apache.org/jira/secure/attachment/12962991/NeS1078.pdf</url>
694 <outputDirectory>${project.build.directory}/pdfs</outputDirectory>
695 <outputFileName>PDFBOX-4490.pdf</outputFileName>
696 <sha512>5ae7f232c47c13ed31997eb2c368e7deb1013c1321d70bf79369f8d709b33406191d94c21a5d27b4c4bb48241bafd9328a0a6d2d093d4e540d5044e9503bd099</sha512>
697 </configuration>
698 </execution>
660699 </executions>
661700 </plugin>
662701 </plugins>
3636 @Override
3737 public void process(Operator operator, List<COSBase> arguments) throws IOException
3838 {
39 COSName name = (COSName)arguments.get(0);
40
41 PDColorSpace cs = context.getResources().getColorSpace(name);
39 COSBase base = arguments.get(0);
40 if (!(base instanceof COSName))
41 {
42 return;
43 }
44 PDColorSpace cs = context.getResources().getColorSpace((COSName) base);
4245 context.getGraphicsState().setNonStrokingColorSpace(cs);
4346 context.getGraphicsState().setNonStrokingColor(cs.getInitialColor());
4447 }
2121 import java.util.Arrays;
2222 import java.util.Calendar;
2323 import java.util.Collection;
24 import java.util.LinkedHashMap;
2524 import java.util.List;
2625 import java.util.Map;
2726 import java.util.Set;
2928 import org.apache.pdfbox.io.IOUtils;
3029 import org.apache.pdfbox.pdmodel.common.COSObjectable;
3130 import org.apache.pdfbox.util.DateConverter;
31 import org.apache.pdfbox.util.SmallMap;
3232
3333 /**
3434 * This class represents a dictionary where name/value pairs reside.
4444 /**
4545 * The name-value pairs of this dictionary. The pairs are kept in the order they were added to the dictionary.
4646 */
47 protected Map<COSName, COSBase> items = new LinkedHashMap<COSName, COSBase>();
47 protected Map<COSName, COSBase> items = new SmallMap<COSName, COSBase>();
4848
4949 /**
5050 * Constructor.
2727
2828 import org.apache.pdfbox.io.IOUtils;
2929 import org.apache.pdfbox.io.ScratchFile;
30 import org.apache.pdfbox.multipdf.Splitter;
3031 import org.apache.pdfbox.pdfparser.PDFObjectStreamParser;
3132 import org.apache.pdfbox.pdmodel.PDDocument;
3233
383384 }
384385
385386 /**
386 * This will get a list of all available objects.
387 * This will get a list of all available objects. This method works only for loaded PDFs. It
388 * will return an empty list for PDFs created from scratch (this includes PDFs generated within
389 * PDFBox, e.g. by {@link Splitter}). This method will be removed in 3.0.
387390 *
388391 * @return A list of all objects, never null.
389392 */
451454 /**
452455 * This will close all storage and delete the tmp files.
453456 *
454 * @throws IOException If there is an error close resources.
457 * @throws IOException If there is an error close resources.
455458 */
456459 @Override
457460 public void close() throws IOException
458461 {
459 if (!closed)
460 {
461 // Make sure that:
462 // - first Exception is kept
463 // - all COSStreams are closed
464 // - ScratchFile is closed
465 // - there's a way to see which errors occurred
466
467 IOException firstException = null;
468
469 // close all open I/O streams
470 for (COSObject object : getObjects())
462 if (closed)
463 {
464 return;
465 }
466
467 // Make sure that:
468 // - first Exception is kept
469 // - all COSStreams are closed
470 // - ScratchFile is closed
471 // - there's a way to see which errors occurred
472
473 IOException firstException = null;
474
475 // close all open I/O streams
476 for (COSObject object : getObjects())
477 {
478 COSBase cosObject = object.getObject();
479 if (cosObject instanceof COSStream)
471480 {
472 COSBase cosObject = object.getObject();
473 if (cosObject instanceof COSStream)
474 {
475 firstException = IOUtils.closeAndLogException((COSStream) cosObject, LOG, "COSStream", firstException);
476 }
481 firstException = IOUtils.closeAndLogException((COSStream) cosObject, LOG, "COSStream", firstException);
477482 }
478 for (COSStream stream : streams)
479 {
480 firstException = IOUtils.closeAndLogException(stream, LOG, "COSStream", firstException);
481 }
482 if (scratchFile != null)
483 {
484 firstException = IOUtils.closeAndLogException(scratchFile, LOG, "ScratchFile", firstException);
485 }
486 closed = true;
487
488 // rethrow first exception to keep method contract
489 if (firstException != null)
490 {
491 throw firstException;
492 }
483 }
484 for (COSStream stream : streams)
485 {
486 firstException = IOUtils.closeAndLogException(stream, LOG, "COSStream", firstException);
487 }
488 if (scratchFile != null)
489 {
490 firstException = IOUtils.closeAndLogException(scratchFile, LOG, "ScratchFile", firstException);
491 }
492 closed = true;
493
494 // rethrow first exception to keep method contract
495 if (firstException != null)
496 {
497 throw firstException;
493498 }
494499 }
495500
9696 @Override
9797 public int hashCode()
9898 {
99 return Long.valueOf(number+generation).hashCode();
99 // most likely generation is 0. Shift number 4 times (fast as multiply)
100 // to support generation numbers up to 15
101 return Long.valueOf((number << 4) + generation).hashCode();
100102 }
101103
102104 @Override
2222 import java.io.InputStream;
2323 import java.io.OutputStream;
2424 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Iterator;
2527 import java.util.List;
28 import java.util.Map.Entry;
29
2630 import org.apache.commons.logging.Log;
2731 import org.apache.commons.logging.LogFactory;
2832 import org.apache.pdfbox.filter.DecodeOptions;
7074 setInt(COSName.LENGTH, 0);
7175 this.scratchFile = scratchFile != null ? scratchFile : ScratchFile.getMainMemoryOnlyInstance();
7276 }
77
78 /**
79 * {@inheritDoc}
80 */
81 @Override
82 public boolean equals(Object o) {
83 if (o == this)
84 {
85 return true;
86 }
87
88 if (!(o instanceof COSStream))
89 {
90 return false;
91 }
92
93 COSStream toBeCompared = (COSStream) o;
94
95 if (toBeCompared.size() != size())
96 {
97 return false;
98 }
99
100 // compare dictionary content
101 Iterator<Entry<COSName, COSBase>> iter = entrySet().iterator();
102 while (iter.hasNext())
103 {
104 Entry<COSName, COSBase> entry = iter.next();
105 COSName key = entry.getKey();
106 COSBase value = entry.getValue();
107
108 if (!toBeCompared.containsKey(key))
109 {
110 return false;
111 }
112 else if (value == null)
113 {
114 if (toBeCompared.getItem(key) != null)
115 {
116 return false;
117 }
118 }
119 else if (!value.equals(toBeCompared.getItem(key)))
120 {
121 return false;
122 }
123 }
124
125 // compare stream content
126 if (!toBeCompared.toTextString().equals(toTextString()))
127 {
128 return false;
129 }
130
131 return true;
132 }
133
134 /**
135 * {@inheritDoc}
136 */
137 @Override
138 public int hashCode() {
139 Object[] members = {items, randomAccess, scratchFile, isWriting};
140 return Arrays.hashCode(members);
141 }
142
143
73144
74145 /**
75146 * Throws if the random access backing store has been closed. Helpful for catching cases where
323323 }
324324
325325 int newPagePosition = (int) (seekToPosition / pageSize);
326 if (seekToPosition % pageSize == 0 && seekToPosition == size)
327 {
328 newPagePosition--; // PDFBOX-4756: Prevent seeking a non-yet-existent page...
329 }
326330
327331 currentPage = pageHandler.readPage(pageIndexes[newPagePosition]);
328332 currentPagePositionInPageIndexes = newPagePosition;
19951995 int stmGenNumber = readGenerationNumber();
19961996 readExpectedString(OBJ_MARKER, true);
19971997 int nrOfObjects = 0;
1998 byte[] numbersBytes = null;
19991998 COSStream stream = null;
20001999 COSInputStream is = null;
2000 List<Long> objectNumbers = null;
20012001 try
20022002 {
20032003 COSDictionary dict = parseCOSDictionary();
20132013 {
20142014 securityHandler.decryptStream(stream, stmObjNumber, stmGenNumber);
20152015 }
2016 is = stream.createInputStream();
2017 numbersBytes = new byte[offsetFirstStream];
2018 is.read(numbersBytes);
2016 PDFObjectStreamParser strmParser = new PDFObjectStreamParser(stream, document);
2017 objectNumbers = new ArrayList<Long>(nrOfObjects);
2018 for (int i = 0; i < nrOfObjects; i++)
2019 {
2020 objectNumbers.add(strmParser.readObjectNumber());
2021 strmParser.readLong();
2022 }
20192023 }
20202024 catch (IOException exception)
20212025 {
20342038 stream.close();
20352039 }
20362040 }
2037 int start = 0;
2038 // skip spaces
2039 while (start < numbersBytes.length && numbersBytes[start] == 32)
2040 {
2041 start++;
2042 }
2043 String numbersStr = new String(numbersBytes, start, numbersBytes.length - start,
2044 "ISO-8859-1");
2045 numbersStr = numbersStr.replace('\n', ' ').replace(" ", " ");
2046 String[] numbers = numbersStr.split(" ");
2047 if (numbers.length < nrOfObjects * 2)
2041 if (objectNumbers.size() < nrOfObjects)
20482042 {
20492043 LOG.debug(
20502044 "Skipped corrupt stream: (" + stmObjNumber + " 0 at offset " + offset);
20512045 continue;
20522046 }
20532047 Map<COSObjectKey, Long> xrefOffset = xrefTrailerResolver.getXrefTable();
2054 for (int i = 0; i < nrOfObjects; i++)
2055 {
2056 try
2057 {
2058 long objNumber = Long.parseLong(numbers[i * 2]);
2059 COSObjectKey objKey = new COSObjectKey(objNumber, 0);
2060 Long existingOffset = bfSearchCOSObjectKeyOffsets.get(objKey);
2061 if (existingOffset != null && existingOffset < 0)
2062 {
2063 // translate stream object key to its offset
2064 COSObjectKey objStmKey = new COSObjectKey(Math.abs(existingOffset), 0);
2065 existingOffset = bfSearchCOSObjectKeyOffsets.get(objStmKey);
2066 }
2067 if (existingOffset == null || offset > existingOffset)
2068 {
2069 bfSearchCOSObjectKeyOffsets.put(objKey, -stmObjNumber);
2070 xrefOffset.put(objKey, -stmObjNumber);
2071 }
2072 }
2073 catch (NumberFormatException exception)
2074 {
2075 LOG.debug("Skipped corrupt object key in stream: " + stmObjNumber);
2048 for (Long objNumber : objectNumbers)
2049 {
2050 COSObjectKey objKey = new COSObjectKey(objNumber, 0);
2051 Long existingOffset = bfSearchCOSObjectKeyOffsets.get(objKey);
2052 if (existingOffset != null && existingOffset < 0)
2053 {
2054 // translate stream object key to its offset
2055 COSObjectKey objStmKey = new COSObjectKey(Math.abs(existingOffset), 0);
2056 existingOffset = bfSearchCOSObjectKeyOffsets.get(objStmKey);
2057 }
2058 if (existingOffset == null || offset > existingOffset)
2059 {
2060 bfSearchCOSObjectKeyOffsets.put(objKey, -stmObjNumber);
2061 xrefOffset.put(objKey, -stmObjNumber);
20762062 }
20772063 }
20782064 }
112112 public void unread(byte[] bytes, int start, int len) throws IOException
113113 {
114114 input.unread(bytes, start, len);
115 position -= len - start;
115 position -= len;
116116 }
117117
118118 @Override
128128 {
129129 off += n;
130130 len -= n;
131 position += n;
132131 }
133132 else
134133 {
8181 @Override
8282 public void unread(byte[] bytes, int start, int len) throws IOException
8383 {
84 reader.rewind(len - start);
84 reader.rewind(len);
8585 }
8686
8787 @Override
2828 import org.apache.pdfbox.cos.COSFloat;
2929 import org.apache.pdfbox.cos.COSInteger;
3030 import org.apache.pdfbox.cos.COSName;
31 import org.apache.pdfbox.cos.COSNull;
3132 import org.apache.pdfbox.cos.COSString;
3233 import org.apache.pdfbox.util.Charsets;
3334
143144 output.write(COSWriter.ARRAY_OPEN);
144145 for( int i=0; i<array.size(); i++ )
145146 {
146 writeObject( array.get( i ) );
147 output.write( SPACE );
148 }
149
150 output.write( COSWriter.ARRAY_CLOSE );
147 writeObject(array.get(i));
148 }
149 output.write(COSWriter.ARRAY_CLOSE);
150 output.write(SPACE);
151151 }
152152 else if( o instanceof COSDictionary )
153153 {
157157 {
158158 if (entry.getValue() != null)
159159 {
160 writeObject( entry.getKey() );
161 output.write( SPACE );
162 writeObject( entry.getValue() );
163 output.write( SPACE );
160 writeObject(entry.getKey());
161 writeObject(entry.getValue());
164162 }
165163 }
166164 output.write( COSWriter.DICT_CLOSE );
172170 if (op.getName().equals(OperatorName.BEGIN_INLINE_IMAGE))
173171 {
174172 output.write(OperatorName.BEGIN_INLINE_IMAGE.getBytes(Charsets.ISO_8859_1));
173 output.write(EOL);
175174 COSDictionary dic = op.getImageParameters();
176175 for( COSName key : dic.keySet() )
177176 {
194193 output.write( EOL );
195194 }
196195 }
196 else if (o instanceof COSNull)
197 {
198 output.write("null".getBytes(Charsets.ISO_8859_1));
199 output.write(SPACE);
200 }
197201 else
198202 {
199203 throw new IOException( "Error:Unknown type in content stream:" + o );
14271427 * Writes a real number to the content stream.
14281428 * @param real
14291429 * @throws java.io.IOException
1430 * @throws IllegalArgumentException if the parameter is not a finite number
14301431 */
14311432 protected void writeOperand(float real) throws IOException
14321433 {
1434 if (Float.isInfinite(real) || Float.isNaN(real))
1435 {
1436 throw new IllegalArgumentException(real + " is not a finite number");
1437 }
1438
14331439 int byteCount = NumberFormatUtil.formatFloatFast(real, formatDecimal.getMaximumFractionDigits(), formatBuffer);
14341440
14351441 if (byteCount == -1)
24652465 * @param real the float value to be added to the content stream.
24662466 *
24672467 * @throws IOException if something went wrong
2468 * @throws IllegalArgumentException if the parameter is not a finite number
24682469 */
24692470 protected void writeOperand(float real) throws IOException
24702471 {
2472 if (Float.isInfinite(real) || Float.isNaN(real))
2473 {
2474 throw new IllegalArgumentException(real + " is not a finite number");
2475 }
2476
24712477 int byteCount = NumberFormatUtil.formatFloatFast(real, formatDecimal.getMaximumFractionDigits(), formatBuffer);
24722478
24732479 if (byteCount == -1)
380380 private void visitPage(COSDictionary current)
381381 {
382382 index++;
383 found = searched.equals(current);
383 found = searched == current;
384384 }
385385 }
386386
4242 private final COSArray array;
4343 private final List<E> actual;
4444
45 // indicates that the list has been filtered
46 // i.e. the number of entries in array and actual differ
47 private boolean isFiltered = false;
48
4549 private COSDictionary parentDict;
4650 private COSName dictKey;
4751
5559 }
5660
5761 /**
58 * Constructor.
62 * Create the COSArrayList specifing the List and the backing COSArray.
63 *
64 * <p>User of this constructor need to ensure that the entries in the List and
65 * the backing COSArray are matching i.e. the COSObject of the List entry is
66 * included in the COSArray.
67 *
68 * <p>If the number of entries in the List and the COSArray differ
69 * it is assumed that the List has been filtered. In that case the COSArrayList
70 * shall only be used for reading purposes and no longer for updating.
5971 *
6072 * @param actualList The list of standard java objects
6173 * @param cosArray The COS array object to sync to.
6476 {
6577 actual = actualList;
6678 array = cosArray;
79
80 // if the number of entries differs this may come from a filter being
81 // applied at the PDModel level
82 if (actual.size() != array.size()) {
83 isFiltered = true;
84 }
6785 }
6886
6987 /**
199217 @Override
200218 public boolean remove(Object o)
201219 {
220
221 if (isFiltered) {
222 throw new UnsupportedOperationException("removing entries from a filtered List is not permitted");
223 }
224
202225 boolean retval = true;
203226 int index = actual.indexOf( o );
204227 if( index >= 0 )
205228 {
206 retval = actual.remove( o );
207
208 if (o instanceof COSObjectable) {
209 COSBase cosBase = ((COSObjectable) o).getCOSObject();
210 retval = array.remove(cosBase);
211 }
229 actual.remove( index );
230 array.remove( index );
212231 }
213232 else
214233 {
232251 @Override
233252 public boolean addAll(Collection<? extends E> c)
234253 {
254 if (isFiltered) {
255 throw new UnsupportedOperationException("Apping to a filtered List is not permitted");
256 }
257
235258 //when adding if there is a parentDict then change the item
236259 //in the dictionary from a single item to an array.
237260 if( parentDict != null && c.size() > 0)
251274 @Override
252275 public boolean addAll(int index, Collection<? extends E> c)
253276 {
277
278 if (isFiltered) {
279 throw new UnsupportedOperationException("Inserting to a filtered List is not permitted");
280 }
281
254282 //when adding if there is a parentDict then change the item
255283 //in the dictionary from a single item to an array.
256284 if( parentDict != null && c.size() > 0)
490518 @Override
491519 public boolean removeAll(Collection<?> c)
492520 {
493 array.removeAll( toCOSObjectList( c ) );
521 for (Iterator iterator = c.iterator(); iterator.hasNext();)
522 {
523 COSBase itemCOSBase = ((COSObjectable)iterator.next()).getCOSObject();
524 // remove all indirect objects too by dereferencing them
525 // before doing the comparison
526 for (int i=array.size()-1; i>=0; i--)
527 {
528 if (itemCOSBase.equals(array.getObject(i)))
529 {
530 array.remove(i);
531 }
532 }
533 }
494534 return actual.removeAll( c );
495535 }
496536
500540 @Override
501541 public boolean retainAll(Collection<?> c)
502542 {
503 array.retainAll( toCOSObjectList( c ) );
543 for (Iterator iterator = c.iterator(); iterator.hasNext();)
544 {
545 COSBase itemCOSBase = ((COSObjectable)iterator.next()).getCOSObject();
546 // remove all indirect objects too by dereferencing them
547 // before doing the comparison
548 for (int i=array.size()-1; i>=0; i--)
549 {
550 if (!itemCOSBase.equals(array.getObject(i)))
551 {
552 array.remove(i);
553 }
554 }
555 }
504556 return actual.retainAll( c );
505557 }
506558
554606 @Override
555607 public E set(int index, E element)
556608 {
609
610 if (isFiltered) {
611 throw new UnsupportedOperationException("Replacing an element in a filtered List is not permitted");
612 }
613
557614 if( element instanceof String )
558615 {
559616 COSString item = new COSString( (String)element );
580637 @Override
581638 public void add(int index, E element)
582639 {
640 if (isFiltered) {
641 throw new UnsupportedOperationException("Adding an element in a filtered List is not permitted");
642 }
643
583644 //when adding if there is a parentDict then change the item
584645 //in the dictionary from a single item to an array.
585646 if( parentDict != null )
606667 @Override
607668 public E remove(int index)
608669 {
609 E toBeRemoved = actual.get(index);
610 remove(toBeRemoved);
611 return toBeRemoved;
670 if (isFiltered) {
671 throw new UnsupportedOperationException("removing entries from a filtered List is not permitted");
672 }
673
674 array.remove(index);
675 return actual.remove(index);
612676 }
613677
614678 /**
126126 @Override
127127 public void putAll(Map<? extends K, ? extends V> t)
128128 {
129 throw new RuntimeException( "Not yet implemented" );
129 throw new UnsupportedOperationException("Not yet implemented");
130130 }
131131
132132 /**
134134 */
135135 public void setKids( List<? extends PDNameTreeNode<T>> kids )
136136 {
137 if (kids != null && kids.size() > 0)
137 if (kids != null && !kids.isEmpty())
138138 {
139139 for (PDNameTreeNode<T> kidsNode : kids)
140140 {
166166 else
167167 {
168168 List<PDNameTreeNode<T>> kids = getKids();
169 if (kids != null && kids.size() > 0)
169 if (kids != null && !kids.isEmpty())
170170 {
171171 PDNameTreeNode<T> firstKid = kids.get(0);
172172 PDNameTreeNode<T> lastKid = kids.get(kids.size() - 1);
3434 {
3535
3636 /**
37 * Constructor.
38 *
39 * @param document {@inheritDoc}
37 * {@inheritDoc}
4038 */
4139 public PDEmbeddedFile( PDDocument document )
4240 {
4341 super( document );
4442 getCOSObject().setName(COSName.TYPE, "EmbeddedFile" );
45
46 }
47
48 /**
49 * Constructor.
50 *
51 * @param str The stream parameter.
43 }
44
45 /**
46 * {@inheritDoc}
5247 */
5348 public PDEmbeddedFile( COSStream str )
5449 {
5651 }
5752
5853 /**
59 * Constructor.
60 *
61 * @param doc {@inheritDoc}
62 * @param str {@inheritDoc}
63 *
64 * @throws IOException {@inheritDoc}
54 * {@inheritDoc}
6555 */
6656 public PDEmbeddedFile( PDDocument doc, InputStream str ) throws IOException
6757 {
7060 }
7161
7262 /**
73 * Constructor.
74 *
75 * @param doc {@inheritDoc}
76 * @param input {@inheritDoc}
63 * {@inheritDoc}
7764 * @param filter Filter to apply to the stream.
7865 *
7966 * @throws IOException {@inheritDoc}
624624 gid = cmapMacRoman.getGlyphId(code);
625625 }
626626
627 // PDFBOX-4755 / PDF.js #5501
628 if (gid == 0 && cmapWinUnicode != null)
629 {
630 gid = cmapWinUnicode.getGlyphId(code);
631 }
632
627633 // PDFBOX-3965: fallback for font has that the symbol flag but isn't
628634 if (gid == 0 && cmapWinUnicode != null && encoding != null)
629635 {
677683 {
678684 cmapMacRoman = cmap;
679685 }
686 else if (CmapTable.PLATFORM_UNICODE == cmap.getPlatformId()
687 && CmapTable.ENCODING_UNICODE_1_0 == cmap.getPlatformEncodingId())
688 {
689 // PDFBOX-4755 / PDF.js #5501
690 cmapWinUnicode = cmap;
691 }
680692 }
681693 }
682694 cmapInitialized = true;
2020 import java.io.InputStream;
2121 import org.apache.pdfbox.contentstream.PDContentStream;
2222 import org.apache.pdfbox.cos.COSArray;
23 import org.apache.pdfbox.cos.COSBase;
2324 import org.apache.pdfbox.cos.COSDictionary;
2425 import org.apache.pdfbox.cos.COSFloat;
2526 import org.apache.pdfbox.cos.COSName;
2930 import org.apache.pdfbox.pdmodel.ResourceCache;
3031 import org.apache.pdfbox.pdmodel.common.PDRectangle;
3132 import org.apache.pdfbox.pdmodel.common.PDStream;
33 import org.apache.pdfbox.pdmodel.documentinterchange.markedcontent.PDPropertyList;
3234 import org.apache.pdfbox.pdmodel.graphics.PDXObject;
3335 import org.apache.pdfbox.util.Matrix;
3436
257259 {
258260 getCOSObject().setInt(COSName.STRUCT_PARENTS, structParent);
259261 }
262
263 /**
264 * This will get the optional content group or optional content membership dictionary.
265 *
266 * @return The optional content group or optional content membership dictionary or null if there
267 * is none.
268 */
269 public PDPropertyList getOptionalContent()
270 {
271 COSBase base = getCOSObject().getDictionaryObject(COSName.OC);
272 if (base instanceof COSDictionary)
273 {
274 return PDPropertyList.create((COSDictionary) base);
275 }
276 return null;
277 }
278
279 /**
280 * Sets the optional content group or optional content membership dictionary.
281 *
282 * @param oc The optional content group or optional content membership dictionary.
283 */
284 public void setOptionalContent(PDPropertyList oc)
285 {
286 getCOSObject().setItem(COSName.OC, oc);
287 }
260288 }
3535 import org.apache.commons.logging.LogFactory;
3636 import org.apache.pdfbox.cos.COSArray;
3737 import org.apache.pdfbox.cos.COSBase;
38 import org.apache.pdfbox.cos.COSDictionary;
3839 import org.apache.pdfbox.cos.COSInputStream;
3940 import org.apache.pdfbox.cos.COSName;
4041 import org.apache.pdfbox.cos.COSObject;
4647 import org.apache.pdfbox.pdmodel.PDResources;
4748 import org.apache.pdfbox.pdmodel.common.PDMetadata;
4849 import org.apache.pdfbox.pdmodel.common.PDStream;
50 import org.apache.pdfbox.pdmodel.documentinterchange.markedcontent.PDPropertyList;
4951 import org.apache.pdfbox.pdmodel.graphics.PDXObject;
5052 import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
5153 import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceGray;
899901 return null;
900902 }
901903 }
904
905 /**
906 * This will get the optional content group or optional content membership dictionary.
907 *
908 * @return The optional content group or optional content membership dictionary or null if there
909 * is none.
910 */
911 public PDPropertyList getOptionalContent()
912 {
913 COSBase base = getCOSObject().getDictionaryObject(COSName.OC);
914 if (base instanceof COSDictionary)
915 {
916 return PDPropertyList.create((COSDictionary) base);
917 }
918 return null;
919 }
920
921 /**
922 * Sets the optional content group or optional content membership dictionary.
923 *
924 * @param oc The optional content group or optional content membership dictionary.
925 */
926 public void setOptionalContent(PDPropertyList oc)
927 {
928 getCOSObject().setItem(COSName.OC, oc);
929 }
902930 }
325325 in = new ByteArrayInputStream(out.toByteArray());
326326 }
327327 }
328 return new ByteArrayInputStream(out.toByteArray());
328 return in;
329329 }
330330
331331 @Override
390390 @Override
391391 public String getSuffix()
392392 {
393 // TODO implement me
394 return null;
393 List<String> filters = getFilters();
394
395 if (filters == null || filters.isEmpty())
396 {
397 return "png";
398 }
399 if (filters.contains(COSName.DCT_DECODE.getName()) ||
400 filters.contains(COSName.DCT_DECODE_ABBREVIATION.getName()))
401 {
402 return "jpg";
403 }
404 if (filters.contains(COSName.CCITTFAX_DECODE.getName()) ||
405 filters.contains(COSName.CCITTFAX_DECODE_ABBREVIATION.getName()))
406 {
407 return "tiff";
408 }
409 // JPX and JBIG2 don't exist for inline images
410 return "png";
395411 }
396412 }
195195 }
196196
197197 /**
198 * {@inheritDoc}
199 */
200 @Override
201 public boolean equals (Object o) {
202 if (o == this)
203 {
204 return true;
205 }
206
207 if (!(o instanceof PDAnnotation))
208 {
209 return false;
210 }
211
212 COSDictionary toBeCompared = ((PDAnnotation) o).getCOSObject();
213 return toBeCompared.equals(getCOSObject());
214 }
215
216 /**
217 * {@inheritDoc}
218 */
219 @Override
220 public int hashCode()
221 {
222 return dictionary.hashCode();
223 }
224
225
226 /**
198227 * The annotation rectangle, defining the location of the annotation on the page in default user space units. This
199228 * is usually required and should not return null on valid PDF documents. But where this is a parent form field with
200229 * children, such as radio button collections then the rectangle will be null.
868868 PDAppearanceHandler appearanceHandler = null;
869869 if (SUB_TYPE_CARET.equals(getSubtype()))
870870 {
871 appearanceHandler = new PDCaretAppearanceHandler(this);
871 appearanceHandler = new PDCaretAppearanceHandler(this, document);
872872 }
873873 else if (SUB_TYPE_FREETEXT.equals(getSubtype()))
874874 {
875 appearanceHandler = new PDFreeTextAppearanceHandler(this);
875 appearanceHandler = new PDFreeTextAppearanceHandler(this, document);
876876 }
877877 else if (SUB_TYPE_INK.equals(getSubtype()))
878878 {
879 appearanceHandler = new PDInkAppearanceHandler(this);
879 appearanceHandler = new PDInkAppearanceHandler(this, document);
880880 }
881881 else if (SUB_TYPE_POLYGON.equals(getSubtype()))
882882 {
883 appearanceHandler = new PDPolygonAppearanceHandler(this);
883 appearanceHandler = new PDPolygonAppearanceHandler(this, document);
884884 }
885885 else if (SUB_TYPE_POLYLINE.equals(getSubtype()))
886886 {
887 appearanceHandler = new PDPolylineAppearanceHandler(this);
887 appearanceHandler = new PDPolylineAppearanceHandler(this, document);
888888 }
889889 else if (SUB_TYPE_SOUND.equals(getSubtype()))
890890 {
891 appearanceHandler = new PDSoundAppearanceHandler(this);
891 appearanceHandler = new PDSoundAppearanceHandler(this, document);
892892 }
893893
894894 if (appearanceHandler != null)
130130 return getCOSObject().getNameAsString(COSName.SUBTYPE);
131131 }
132132
133 /**
133 /**
134134 * Set a custom appearance handler for generating the annotations appearance streams.
135 *
135 *
136136 * @param appearanceHandler
137137 */
138 @Override
138139 public void setCustomAppearanceHandler(PDAppearanceHandler appearanceHandler)
139140 {
140141 customAppearanceHandler = appearanceHandler;
154155 PDAppearanceHandler appearanceHandler = null;
155156 if (SUB_TYPE_HIGHLIGHT.equals(getSubtype()))
156157 {
157 appearanceHandler = new PDHighlightAppearanceHandler(this);
158 appearanceHandler = new PDHighlightAppearanceHandler(this, document);
158159 }
159 else if (SUB_TYPE_SQUIGGLY.equals(getSubtype()))
160 else if (SUB_TYPE_SQUIGGLY.equals(getSubtype()))
160161 {
161 appearanceHandler = new PDSquigglyAppearanceHandler(this);
162 appearanceHandler = new PDSquigglyAppearanceHandler(this, document);
162163 }
163 else if (SUB_TYPE_STRIKEOUT.equals(getSubtype()))
164 else if (SUB_TYPE_STRIKEOUT.equals(getSubtype()))
164165 {
165 appearanceHandler = new PDStrikeoutAppearanceHandler(this);
166 appearanceHandler = new PDStrikeoutAppearanceHandler(this, document);
166167 }
167 else if (SUB_TYPE_UNDERLINE.equals(getSubtype()))
168 else if (SUB_TYPE_UNDERLINE.equals(getSubtype()))
168169 {
169 appearanceHandler = new PDUnderlineAppearanceHandler(this);
170 appearanceHandler = new PDUnderlineAppearanceHandler(this, document);
170171 }
171172
172173 if (appearanceHandler != null)
290290 cs.addRect(xOffset, clipY, clipWidth, clipHeight);
291291 cs.clip();
292292
293 cs.beginText();
294 cs.setFont(font, fontSize);
295 cs.setNonStrokingColor(textColor.getComponents());
296 AppearanceStyle appearanceStyle = new AppearanceStyle();
297 appearanceStyle.setFont(font);
298 appearanceStyle.setFontSize(fontSize);
299 PlainTextFormatter formatter = new PlainTextFormatter.Builder(cs)
300 .style(appearanceStyle)
301 .text(new PlainText(annotation.getContents()))
302 .width(width - ab.width * 4)
303 .wrapLines(true)
304 .initialOffset(xOffset, yOffset)
305 // Adobe ignores the /Q
306 //.textAlign(annotation.getQ())
307 .build();
308 try
309 {
310 formatter.format();
311 }
312 catch (IllegalArgumentException ex)
313 {
314 throw new IOException(ex);
315 }
316 cs.endText();
317
293 if (annotation.getContents() != null)
294 {
295 cs.beginText();
296 cs.setFont(font, fontSize);
297 cs.setNonStrokingColor(textColor.getComponents());
298 AppearanceStyle appearanceStyle = new AppearanceStyle();
299 appearanceStyle.setFont(font);
300 appearanceStyle.setFontSize(fontSize);
301 PlainTextFormatter formatter = new PlainTextFormatter.Builder(cs)
302 .style(appearanceStyle)
303 .text(new PlainText(annotation.getContents()))
304 .width(width - ab.width * 4)
305 .wrapLines(true)
306 .initialOffset(xOffset, yOffset)
307 // Adobe ignores the /Q
308 //.textAlign(annotation.getQ())
309 .build();
310 try
311 {
312 formatter.format();
313 }
314 catch (IllegalArgumentException ex)
315 {
316 throw new IOException(ex);
317 }
318 finally
319 {
320 cs.endText();
321 }
322 }
318323
319324 if (pathsArray.length > 0)
320325 {
2020 import org.apache.commons.logging.LogFactory;
2121 import org.apache.pdfbox.cos.COSDictionary;
2222 import org.apache.pdfbox.cos.COSName;
23 import org.apache.pdfbox.cos.COSStream;
2423 import org.apache.pdfbox.io.IOUtils;
2524 import org.apache.pdfbox.pdmodel.PDFormContentStream;
2625 import org.apache.pdfbox.pdmodel.PDResources;
129128 r1.setBlendMode(BlendMode.MULTIPLY);
130129 cs.setGraphicsStateParameters(r0);
131130 cs.setGraphicsStateParameters(r1);
132 //TODO replace with document.getDocument().createCOSStream()
133 // or call new PDFormXObject(document)
134131 PDFormXObject frm1 = new PDFormXObject(createCOSStream());
135132 PDFormXObject frm2 = new PDFormXObject(createCOSStream());
136133 frm1.setResources(new PDResources());
7878 /**
7979 * The default font size used for multiline text
8080 */
81 private static final float DEFAULT_FONT_SIZE = 12;
81 private static final float DEFAULT_FONT_SIZE = 12;
82
83 /**
84 * The minimum/maximum font sizes used for multiline text auto sizing
85 */
86 private static final float MINIMUM_FONT_SIZE = 4;
87 private static final float MAXIMUM_FONT_SIZE = 300;
8288
8389 /**
8490 * The default padding applied by Acrobat to the fields bbox.
786792 {
787793 if (isMultiLine())
788794 {
795 PlainText textContent = new PlainText(value);
796 if (textContent.getParagraphs() != null)
797 {
798 float width = contentRect.getWidth() - contentRect.getLowerLeftX();
799 float fs = MINIMUM_FONT_SIZE;
800 while (fs <= MAXIMUM_FONT_SIZE)
801 {
802 // determine the number of lines needed for this font and contentRect
803 int numLines = 0;
804 for (PlainText.Paragraph paragraph : textContent.getParagraphs())
805 {
806 numLines += paragraph.getLines(font, fs, width).size();
807 }
808 // calculate the height required for this font size
809 float fontScaleY = fs / FONTSCALE;
810 float leading = font.getBoundingBox().getHeight() * fontScaleY;
811 float height = leading * numLines;
812
813 // if this font size didn't fit, use the prior size that did fit
814 if (height > contentRect.getHeight())
815 {
816 return Math.max(fs - 1, MINIMUM_FONT_SIZE);
817 }
818 fs++;
819 }
820 return Math.min(fs, MAXIMUM_FONT_SIZE);
821 }
822
789823 // Acrobat defaults to 12 for multiline text with size 0
790824 return DEFAULT_FONT_SIZE;
791825 }
8383 import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
8484 import org.apache.pdfbox.pdmodel.graphics.form.PDTransparencyGroup;
8585 import org.apache.pdfbox.pdmodel.graphics.image.PDImage;
86 import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
8687 import org.apache.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentGroup;
8788 import org.apache.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentGroup.RenderState;
8889 import org.apache.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentMembershipDictionary;
10051006 @Override
10061007 public void drawImage(PDImage pdImage) throws IOException
10071008 {
1009 if (pdImage instanceof PDImageXObject &&
1010 isHiddenOCG(((PDImageXObject) pdImage).getOptionalContent()))
1011 {
1012 return;
1013 }
10081014 Matrix ctm = getGraphicsState().getCurrentTransformationMatrix();
10091015 AffineTransform at = ctm.createAffineTransform();
10101016
12181224
12191225 // prepare transfer functions (either one per color or one for all)
12201226 // and maps (actually arrays[256] to be faster) to avoid calculating values several times
1221 Integer rMap[];
1222 Integer gMap[];
1223 Integer bMap[];
1227 Integer[] rMap;
1228 Integer[] gMap;
1229 Integer[] bMap;
12241230 PDFunction rf;
12251231 PDFunction gf;
12261232 PDFunction bf;
13941400 @Override
13951401 public void showForm(PDFormXObject form) throws IOException
13961402 {
1403 if (isHiddenOCG(form.getOptionalContent()))
1404 {
1405 return;
1406 }
13971407 if (isContentRendered())
13981408 {
13991409 super.showForm(form);
14031413 @Override
14041414 public void showTransparencyGroup(PDTransparencyGroup form) throws IOException
14051415 {
1416 if (isHiddenOCG(form.getOptionalContent()))
1417 {
1418 return;
1419 }
14061420 if (!isContentRendered())
14071421 {
14081422 return;
670670 }
671671 // test if our TextPosition starts after a new word would be expected to start
672672 if (expectedStartOfNextWordX != EXPECTED_START_OF_NEXT_WORD_X_RESET_VALUE
673 && expectedStartOfNextWordX < positionX &&
674 // only bother adding a space if the last character was not a space
675 lastPosition.getTextPosition().getUnicode() != null
676 && !lastPosition.getTextPosition().getUnicode().endsWith(" "))
673 && expectedStartOfNextWordX < positionX
674 // only bother adding a word separator if the last character was not a word separator
675 && (wordSeparator.isEmpty() || //
676 (lastPosition.getTextPosition().getUnicode() != null
677 && !lastPosition.getTextPosition().getUnicode()
678 .endsWith(wordSeparator))))
677679 {
678680 line.add(LineItem.getWordSeparator());
679681 }
721723
722724 private boolean overlap(float y1, float height1, float y2, float height2)
723725 {
724 return within(y1, y2, .1f) || y2 <= y1 && y2 >= y1 - height1
725 || y1 <= y2 && y1 >= y2 - height2;
726 return within(y1, y2, .1f) || (y2 <= y1 && y1 - height1 - y2 < -(height1 * 0.1f))
727 || (y1 <= y2 && y2 - height2 - y1 < -(height2 * 0.1f));
726728 }
727729
728730 /**
395395 + thisOperand[7] * otherOperand[5]
396396 + thisOperand[8] * otherOperand[8];
397397 }
398
398 if (Float.isInfinite(result.single[0]) || Float.isNaN(result.single[0]) //
399 || Float.isInfinite(result.single[1]) || Float.isNaN(result.single[1]) //
400 || Float.isInfinite(result.single[2]) || Float.isNaN(result.single[2]) //
401 || Float.isInfinite(result.single[3]) || Float.isNaN(result.single[3]) //
402 || Float.isInfinite(result.single[4]) || Float.isNaN(result.single[4]) //
403 || Float.isInfinite(result.single[5]) || Float.isNaN(result.single[5]) //
404 || Float.isInfinite(result.single[6]) || Float.isNaN(result.single[6]) //
405 || Float.isInfinite(result.single[7]) || Float.isNaN(result.single[7]) //
406 || Float.isInfinite(result.single[8]) || Float.isNaN(result.single[8]))
407 throw new IllegalArgumentException(
408 "Multiplying two matrices produces illegal values");
399409 return result;
400410 }
401411
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.pdfbox.util;
17
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.LinkedHashSet;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25
26 /**
27 * Map implementation with a smallest possible memory usage.
28 * It should only be used for maps with small number of items
29 * (e.g. &lt;30) since most operations have an O(n) complexity.
30 * Thus it should be used in cases with large number of map
31 * objects, each having only few items.
32 *
33 * <p><code>null</code> is not supported for keys or values.</p>
34 */
35 public class SmallMap<K, V> implements Map<K, V>
36 {
37 /**
38 * stores key-value pair as 2 objects; key first; in case of empty map this might be <code>null</code>
39 */
40 private Object[] mapArr;
41
42 /** Creates empty map. */
43 public SmallMap()
44 {
45 }
46
47 /** Creates map filled with entries from provided map. */
48 public SmallMap(Map<? extends K, ? extends V> initMap)
49 {
50 putAll(initMap);
51 }
52
53 /**
54 * Returns index of key within map-array or <code>-1</code>
55 * if key is not found (or key is <code>null</code>).
56 */
57 private int findKey(Object key)
58 {
59 if (isEmpty() || (key==null))
60 {
61 return -1;
62 }
63
64 for ( int aIdx = 0; aIdx < mapArr.length; aIdx+=2 )
65 {
66 if (key.equals(mapArr[aIdx]))
67 {
68 return aIdx;
69 }
70 }
71
72 return -1;
73 }
74
75 /**
76 * Returns index of value within map-array or <code>-1</code>
77 * if value is not found (or value is <code>null</code>).
78 */
79 private int findValue(Object value)
80 {
81 if (isEmpty() || (value==null))
82 {
83 return -1;
84 }
85
86 for ( int aIdx = 1; aIdx < mapArr.length; aIdx+=2 )
87 {
88 if (value.equals(mapArr[aIdx]))
89 {
90 return aIdx;
91 }
92 }
93
94 return -1;
95 }
96
97 @Override
98 public int size()
99 {
100 return mapArr == null ? 0 : mapArr.length >> 1;
101 }
102
103 @Override
104 public boolean isEmpty()
105 {
106 return (mapArr == null) || (mapArr.length == 0);
107 }
108
109 @Override
110 public boolean containsKey(Object key)
111 {
112 return findKey(key) >= 0;
113 }
114
115 @Override
116 public boolean containsValue(Object value)
117 {
118 return findValue(value) >= 0;
119 }
120
121 @SuppressWarnings("unchecked")
122 @Override
123 public V get(Object key)
124 {
125 int kIdx = findKey(key);
126
127 return kIdx < 0 ? null : (V) mapArr[kIdx+1];
128 }
129
130 @Override
131 public V put(K key, V value)
132 {
133 if ((key == null) || (value == null))
134 {
135 throw new NullPointerException( "Key or value must not be null.");
136 }
137
138 if (mapArr == null)
139 {
140 mapArr = new Object[] { key, value };
141 return null;
142 }
143 else
144 {
145 int kIdx = findKey(key);
146
147 if (kIdx < 0)
148 {
149 // key unknown
150 int oldLen = mapArr.length;
151 Object[] newMapArr = new Object[oldLen+2];
152 System.arraycopy(mapArr, 0, newMapArr, 0, oldLen);
153 newMapArr[oldLen] = key;
154 newMapArr[oldLen+1] = value;
155 mapArr = newMapArr;
156 return null;
157 }
158 else
159 {
160 // key exists; replace value
161 @SuppressWarnings("unchecked")
162 V oldValue = (V) mapArr[kIdx+1];
163 mapArr[kIdx+1] = value;
164 return oldValue;
165 }
166 }
167 }
168
169 @Override
170 public V remove(Object key)
171 {
172 int kIdx = findKey(key);
173
174 if (kIdx < 0)
175 {
176 // not found
177 return null;
178 }
179
180 @SuppressWarnings("unchecked")
181 V oldValue = (V) mapArr[kIdx+1];
182 int oldLen = mapArr.length;
183
184 if (oldLen == 2)
185 {
186 // was last entry
187 mapArr = null;
188 }
189 else
190 {
191 Object[] newMapArr = new Object[oldLen-2];
192 System.arraycopy(mapArr, 0, newMapArr, 0, kIdx);
193 System.arraycopy(mapArr, kIdx+2, newMapArr, kIdx, oldLen - kIdx - 2);
194 mapArr = newMapArr;
195 }
196
197 return oldValue;
198 }
199
200 @Override
201 public final void putAll(Map<? extends K, ? extends V> otherMap)
202 {
203 if ((mapArr == null) || (mapArr.length == 0))
204 {
205 // existing map is empty
206 mapArr = new Object[otherMap.size() << 1];
207 int aIdx = 0;
208 for (Entry<? extends K, ? extends V> entry : otherMap.entrySet())
209 {
210 if ((entry.getKey() == null) || (entry.getValue() == null))
211 {
212 throw new NullPointerException( "Key or value must not be null.");
213 }
214
215 mapArr[aIdx++] = entry.getKey();
216 mapArr[aIdx++] = entry.getValue();
217 }
218 }
219 else
220 {
221 int oldLen = mapArr.length;
222 // first increase array size to hold all to put entries as if they have unknown keys
223 // reduce after adding all to the required size
224 Object[] newMapArr = new Object[oldLen+(otherMap.size() << 1)];
225 System.arraycopy(mapArr, 0, newMapArr, 0, oldLen);
226
227 int newIdx = oldLen;
228 for (Entry<? extends K, ? extends V> entry : otherMap.entrySet())
229 {
230 if ((entry.getKey() == null) || (entry.getValue() == null))
231 {
232 throw new NullPointerException( "Key or value must not be null.");
233 }
234
235 int existKeyIdx = findKey(entry.getKey());
236
237 if (existKeyIdx >= 0)
238 {
239 // existing key
240 newMapArr[existKeyIdx+1] = entry.getValue();
241 }
242 else
243 {
244 // new key
245 newMapArr[newIdx++] = entry.getKey();
246 newMapArr[newIdx++] = entry.getValue();
247 }
248 }
249
250 if (newIdx < newMapArr.length)
251 {
252 Object[] reducedMapArr = new Object[newIdx];
253 System.arraycopy(newMapArr, 0, reducedMapArr, 0, newIdx);
254 newMapArr = reducedMapArr;
255 }
256
257 mapArr = newMapArr;
258 }
259 }
260
261 @Override
262 public void clear()
263 {
264 mapArr = null;
265 }
266
267 /**
268 * Returns a set view of the keys contained in this map.
269 *
270 * <p>The current implementation does not allow changes to the
271 * returned key set (which would have to be reflected in the
272 * underlying map.</p>
273 */
274 @SuppressWarnings("unchecked")
275 @Override
276 public Set<K> keySet()
277 {
278 if (isEmpty())
279 {
280 return Collections.emptySet();
281 }
282
283 Set<K> keys = new LinkedHashSet<K>();
284 for (int kIdx = 0; kIdx < mapArr.length; kIdx+=2)
285 {
286 keys.add((K)mapArr[kIdx]);
287 }
288 return Collections.unmodifiableSet( keys );
289 }
290
291 /**
292 * Returns a collection of the values contained in this map.
293 *
294 * <p>The current implementation does not allow changes to the
295 * returned collection (which would have to be reflected in the
296 * underlying map.</p>
297 */
298 @SuppressWarnings("unchecked")
299 @Override
300 public Collection<V> values()
301 {
302 if (isEmpty())
303 {
304 return Collections.emptySet();
305 }
306
307 List<V> values = new ArrayList<V>(mapArr.length >> 1);
308 for (int vIdx = 1; vIdx < mapArr.length; vIdx+=2)
309 {
310 values.add((V)mapArr[vIdx]);
311 }
312 return Collections.unmodifiableList( values );
313 }
314
315 private class SmallMapEntry implements Entry<K, V>
316 {
317 private final int keyIdx;
318
319 SmallMapEntry(int keyInMapIdx)
320 {
321 keyIdx = keyInMapIdx;
322 }
323
324 @SuppressWarnings("unchecked")
325 @Override
326 public K getKey()
327 {
328 return (K)mapArr[keyIdx];
329 }
330
331 @SuppressWarnings("unchecked")
332 @Override
333 public V getValue()
334 {
335 return (V)mapArr[keyIdx+1];
336 }
337
338 @Override
339 public V setValue(V value)
340 {
341 if (value == null)
342 {
343 throw new NullPointerException( "Key or value must not be null.");
344 }
345
346 V oldValue = getValue();
347 mapArr[keyIdx+1] = value;
348 return oldValue;
349 }
350
351 @Override
352 public int hashCode()
353 {
354 return getKey().hashCode();
355 }
356
357 @Override
358 public boolean equals(Object obj)
359 {
360 if (!(obj instanceof SmallMap.SmallMapEntry))
361 {
362 return false;
363 }
364 @SuppressWarnings("unchecked")
365 SmallMapEntry other = (SmallMapEntry) obj;
366
367 return getKey().equals(other.getKey()) && getValue().equals(other.getValue());
368 }
369 }
370
371 @Override
372 public Set<java.util.Map.Entry<K, V>> entrySet()
373 {
374 if (isEmpty())
375 {
376 return Collections.emptySet();
377 }
378
379 Set<java.util.Map.Entry<K, V>> entries = new LinkedHashSet<Entry<K, V>>();
380 for (int kIdx = 0; kIdx < mapArr.length; kIdx+=2)
381 {
382 entries.add(new SmallMapEntry(kIdx));
383 }
384 return Collections.unmodifiableSet( entries );
385 }
386
387 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.pdfbox.cos;
17
18 import static org.junit.Assert.assertFalse;
19 import org.junit.Test;
20
21 public class COSDictionaryTest
22 {
23 @Test
24 public void testCOSDictionaryNotEqualsCOSStream()
25 {
26 COSDictionary cosDictionary = new COSDictionary();
27 COSStream cosStream = new COSStream();
28 cosDictionary.setItem(COSName.BE, COSName.BE);
29 cosDictionary.setInt(COSName.LENGTH, 0);
30 cosStream.setItem(COSName.BE, COSName.BE);
31 assertFalse("a COSDictionary shall not be equal to a COSStream with the same dictionary entries", cosDictionary.equals(cosStream));
32 assertFalse("a COSStream shall not be equal to a COSDictionary with the same dictionary entries", cosStream.equals(cosDictionary));
33 }
34 }
5252 // Assert result
5353 Assert.assertEquals(1, retval);
5454 }
55
56 @Test
57 public void checkHashCode()
58 {
59 // same object number 100 0
60 Assert.assertEquals(new COSObjectKey(100, 0).hashCode(),
61 new COSObjectKey(100, 0).hashCode());
62
63 // different object numbers/same generation numbers 100 0 vs. 200 0
64 Assert.assertNotEquals(new COSObjectKey(100, 0).hashCode(),
65 new COSObjectKey(200, 0).hashCode());
66
67 // different object numbers/different generation numbers/ sum of both numbers are equal 100 0 vs. 99 1
68 Assert.assertNotEquals(new COSObjectKey(100, 0).hashCode(),
69 new COSObjectKey(99, 1).hashCode());
70 }
5571 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.pdfbox.io;
17
18 import java.io.IOException;
19 import org.junit.Assert;
20
21 import org.junit.Test;
22
23 /**
24 * Regression test to check the known bugs in {@link ScratchFileBuffer}.
25 *
26 * @author Kühn &amp; Weyh Software GmbH
27 */
28 public class ScratchFileBufferTest
29 {
30
31 private static final int PAGE_SIZE = 4096;
32 private static final int NUM_ITERATIONS = 3;
33
34 /**
35 * PDFBOX-4756: test positions are correct when seeking and that no EOFException is thrown in
36 * ScratchFileBuffer.seek() beyond last page.
37 *
38 * @throws IOException
39 */
40 @Test
41 public void testEOFBugInSeek() throws IOException
42 {
43 ScratchFile scratchFile = new ScratchFile(MemoryUsageSetting.setupTempFileOnly());
44 ScratchFileBuffer scratchFileBuffer = new ScratchFileBuffer(scratchFile);
45 byte[] bytes = new byte[PAGE_SIZE];
46 for (int i = 0; i < NUM_ITERATIONS; i++)
47 {
48 long p0 = scratchFileBuffer.getPosition();
49 scratchFileBuffer.write(bytes);
50 long p1 = scratchFileBuffer.getPosition();
51 Assert.assertEquals(PAGE_SIZE, p1 - p0);
52 scratchFileBuffer.write(bytes);
53 long p2 = scratchFileBuffer.getPosition();
54 Assert.assertEquals(PAGE_SIZE, p2 - p1);
55 scratchFileBuffer.seek(0);
56 scratchFileBuffer.seek(i * 2 * PAGE_SIZE);
57 }
58 scratchFile.close();
59 }
60 }
0 /*
1 * Copyright 2014 The Apache Software Foundation.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package org.apache.pdfbox.pdfparser;
17
18 import java.io.ByteArrayInputStream;
19 import java.io.IOException;
20 import org.junit.Assert;
21 import org.junit.Test;
22
23 /**
24 * Unittest for org.apache.pdfbox.pdfparser.InputStreamSource
25 */
26 public class InputStreamSourceTest
27 {
28 @Test
29 public void testPositionReadFully() throws IOException
30 {
31 byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
32 ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
33
34 InputStreamSource inputStreamSource = new InputStreamSource(bais);
35
36 Assert.assertEquals(0, inputStreamSource.getPosition());
37 inputStreamSource.readFully(5);
38 Assert.assertEquals(5, inputStreamSource.getPosition());
39
40 inputStreamSource.close();
41 }
42
43 @Test
44 public void testPositionRead() throws IOException
45 {
46 byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
47 ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
48
49 InputStreamSource inputStreamSource = new InputStreamSource(bais);
50
51 Assert.assertEquals(0, inputStreamSource.getPosition());
52 inputStreamSource.read();
53 inputStreamSource.read();
54 inputStreamSource.read();
55 Assert.assertEquals(3, inputStreamSource.getPosition());
56
57 inputStreamSource.close();
58 }
59
60 @Test
61 public void testPositionReadBytes() throws IOException
62 {
63 byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
64 ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
65
66 InputStreamSource inputStreamSource = new InputStreamSource(bais);
67
68 Assert.assertEquals(0, inputStreamSource.getPosition());
69 byte[] buffer = new byte[4];
70 inputStreamSource.read(buffer);
71 Assert.assertEquals(4, inputStreamSource.getPosition());
72
73 inputStreamSource.read(buffer, 1, 2);
74 Assert.assertEquals(6, inputStreamSource.getPosition());
75
76 inputStreamSource.close();
77 }
78
79 @Test
80 public void testPositionPeek() throws IOException
81 {
82 byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
83 ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
84
85 InputStreamSource inputStreamSource = new InputStreamSource(bais);
86
87 Assert.assertEquals(0, inputStreamSource.getPosition());
88 inputStreamSource.readFully(6);
89 Assert.assertEquals(6, inputStreamSource.getPosition());
90
91 inputStreamSource.peek();
92 Assert.assertEquals(6, inputStreamSource.getPosition());
93
94 inputStreamSource.close();
95 }
96
97 @Test
98 public void testPositionUnreadBytes() throws IOException
99 {
100 byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
101 ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
102
103 InputStreamSource inputStreamSource = new InputStreamSource(bais);
104
105 Assert.assertEquals(0, inputStreamSource.getPosition());
106 inputStreamSource.read();
107 inputStreamSource.read();
108 byte[] readBytes = inputStreamSource.readFully(6);
109 Assert.assertEquals(8, inputStreamSource.getPosition());
110 inputStreamSource.unread(readBytes);
111 Assert.assertEquals(2, inputStreamSource.getPosition());
112 inputStreamSource.read();
113 Assert.assertEquals(3, inputStreamSource.getPosition());
114 inputStreamSource.read(readBytes, 2, 4);
115 Assert.assertEquals(7, inputStreamSource.getPosition());
116 inputStreamSource.unread(readBytes, 2, 4);
117 Assert.assertEquals(3, inputStreamSource.getPosition());
118
119 inputStreamSource.close();
120 }
121 }
0 /*
1 * Copyright 2014 The Apache Software Foundation.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package org.apache.pdfbox.pdfparser;
17
18 import java.io.ByteArrayInputStream;
19 import java.io.IOException;
20
21 import org.apache.pdfbox.io.RandomAccessBuffer;
22 import org.junit.Assert;
23 import org.junit.Test;
24
25 /**
26 * Unittest for org.apache.pdfbox.pdfparser.RandomAccessSource
27 */
28 public class RandomAccessSourceTest
29 {
30 @Test
31 public void testPositionReadFully() throws IOException
32 {
33 byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
34 ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
35
36 RandomAccessSource randomAccessSource = new RandomAccessSource(
37 new RandomAccessBuffer(bais));
38
39 Assert.assertEquals(0, randomAccessSource.getPosition());
40 randomAccessSource.readFully(5);
41 Assert.assertEquals(5, randomAccessSource.getPosition());
42
43 randomAccessSource.close();
44 }
45
46 @Test
47 public void testPositionRead() throws IOException
48 {
49 byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
50 ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
51
52 RandomAccessSource randomAccessSource = new RandomAccessSource(
53 new RandomAccessBuffer(bais));
54
55 Assert.assertEquals(0, randomAccessSource.getPosition());
56 randomAccessSource.read();
57 randomAccessSource.read();
58 randomAccessSource.read();
59 Assert.assertEquals(3, randomAccessSource.getPosition());
60
61 randomAccessSource.close();
62 }
63
64 @Test
65 public void testPositionReadBytes() throws IOException
66 {
67 byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
68 ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
69
70 RandomAccessSource randomAccessSource = new RandomAccessSource(
71 new RandomAccessBuffer(bais));
72
73 Assert.assertEquals(0, randomAccessSource.getPosition());
74 byte[] buffer = new byte[4];
75 randomAccessSource.read(buffer);
76 Assert.assertEquals(4, randomAccessSource.getPosition());
77
78 randomAccessSource.read(buffer, 1, 2);
79 Assert.assertEquals(6, randomAccessSource.getPosition());
80
81 randomAccessSource.close();
82 }
83
84 @Test
85 public void testPositionPeek() throws IOException
86 {
87 byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
88 ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
89
90 RandomAccessSource randomAccessSource = new RandomAccessSource(
91 new RandomAccessBuffer(bais));
92
93 Assert.assertEquals(0, randomAccessSource.getPosition());
94 randomAccessSource.readFully(6);
95 Assert.assertEquals(6, randomAccessSource.getPosition());
96
97 randomAccessSource.peek();
98 Assert.assertEquals(6, randomAccessSource.getPosition());
99
100 randomAccessSource.close();
101 }
102
103 @Test
104 public void testPositionUnreadBytes() throws IOException
105 {
106 byte[] inputValues = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
107 ByteArrayInputStream bais = new ByteArrayInputStream(inputValues);
108
109 RandomAccessSource randomAccessSource = new RandomAccessSource(
110 new RandomAccessBuffer(bais));
111
112 Assert.assertEquals(0, randomAccessSource.getPosition());
113 randomAccessSource.read();
114 randomAccessSource.read();
115 byte[] readBytes = randomAccessSource.readFully(6);
116 Assert.assertEquals(8, randomAccessSource.getPosition());
117 randomAccessSource.unread(readBytes);
118 Assert.assertEquals(2, randomAccessSource.getPosition());
119 randomAccessSource.read();
120 Assert.assertEquals(3, randomAccessSource.getPosition());
121 randomAccessSource.read(readBytes, 2, 4);
122 Assert.assertEquals(7, randomAccessSource.getPosition());
123 randomAccessSource.unread(readBytes, 2, 4);
124 Assert.assertEquals(3, randomAccessSource.getPosition());
125
126 randomAccessSource.close();
127 }
128 }
3636 import org.apache.pdfbox.io.ScratchFile;
3737 import org.apache.pdfbox.pdmodel.PDDocument;
3838 import org.apache.pdfbox.pdmodel.PDDocumentInformation;
39 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline;
40 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem;
3941 import org.apache.pdfbox.rendering.PDFRenderer;
4042 import org.apache.pdfbox.util.DateConverter;
4143 import org.junit.Before;
331333 PDDocument.load(new File(TARGETPDFDIR, "PDFBOX-4339.pdf")).close();
332334 }
333335
336 /**
337 * Test parsing the "WXMDXCYRWFDCMOSFQJ5OAJIAFXYRZ5OA.pdf" file, which is susceptible to
338 * regression.
339 *
340 * @throws IOException
341 */
342 @Test
343 public void testPDFBox4153() throws IOException
344 {
345 PDDocument doc = PDDocument.load(new File(TARGETPDFDIR, "PDFBOX-4153-WXMDXCYRWFDCMOSFQJ5OAJIAFXYRZ5OA.pdf"));
346 PDDocumentOutline documentOutline = doc.getDocumentCatalog().getDocumentOutline();
347 PDOutlineItem firstChild = documentOutline.getFirstChild();
348 assertEquals("Main Menu", firstChild.getTitle());
349 doc.close();
350 }
351
352 /**
353 * Test that PDFBOX-4490 has 3 pages.
354 *
355 * @throws IOException
356 */
357 @Test
358 public void testPDFBox4490() throws IOException
359 {
360 PDDocument doc = PDDocument.load(new File(TARGETPDFDIR, "PDFBOX-4490.pdf"));
361 assertEquals(3, doc.getNumberOfPages());
362 doc.close();
363 }
364
334365 private void executeParserTest(RandomAccessRead source, MemoryUsageSetting memUsageSetting) throws IOException
335366 {
336367 ScratchFile scratchFile = new ScratchFile(memUsageSetting);
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.pdfbox.pdfwriter;
17
18 import java.awt.image.BufferedImage;
19 import java.io.File;
20 import java.io.IOException;
21 import java.io.OutputStream;
22 import javax.imageio.ImageIO;
23 import org.apache.pdfbox.cos.COSName;
24 import org.apache.pdfbox.pdfparser.PDFStreamParser;
25 import org.apache.pdfbox.pdmodel.PDDocument;
26 import org.apache.pdfbox.pdmodel.PDPage;
27 import org.apache.pdfbox.pdmodel.common.PDStream;
28 import org.apache.pdfbox.rendering.PDFRenderer;
29 import org.apache.pdfbox.rendering.TestPDFToImage;
30 import org.junit.After;
31 import org.junit.AfterClass;
32 import static org.junit.Assert.fail;
33 import org.junit.Before;
34 import org.junit.BeforeClass;
35 import org.junit.Test;
36
37 /**
38 *
39 * @author Tilman Hausherr
40 */
41 public class ContentStreamWriterTest
42 {
43
44 private final File testDirIn = new File("target/test-output/contentstream/in");
45 private final File testDirOut = new File("target/test-output/contentstream/out");
46
47 public ContentStreamWriterTest()
48 {
49 testDirIn.mkdirs();
50 testDirOut.mkdirs();
51 }
52
53 @BeforeClass
54 public static void setUpClass()
55 {
56 }
57
58 @AfterClass
59 public static void tearDownClass()
60 {
61 }
62
63 @Before
64 public void setUp()
65 {
66 }
67
68 @After
69 public void tearDown()
70 {
71 }
72
73 /**
74 * Test parse content stream, write back tokens and compare rendering.
75 *
76 * @throws java.io.IOException
77 */
78 @Test
79 public void testPDFBox4750() throws IOException
80 {
81 String filename = "PDFBOX-4750.pdf";
82 File file = new File("target/pdfs", filename);
83 PDDocument doc = PDDocument.load(file);
84
85 PDFRenderer r = new PDFRenderer(doc);
86 for (int i = 0; i < doc.getNumberOfPages(); ++i)
87 {
88 BufferedImage bim1 = r.renderImageWithDPI(i, 96);
89 ImageIO.write(bim1, "png", new File(testDirIn, filename + "-" + (i + 1) + ".png"));
90 PDPage page = doc.getPage(i);
91 PDStream newContent = new PDStream(doc);
92
93 PDFStreamParser parser = new PDFStreamParser(page);
94 parser.parse();
95 OutputStream os = newContent.createOutputStream(COSName.FLATE_DECODE);
96 ContentStreamWriter tokenWriter = new ContentStreamWriter(os);
97 tokenWriter.writeTokens(parser.getTokens());
98 os.close();
99
100 page.setContents(newContent);
101 }
102 doc.save(new File(testDirIn, filename));
103 doc.close();
104 TestPDFToImage testPDFToImage = new TestPDFToImage(TestPDFToImage.class.getName());
105 if (!testPDFToImage.doTestFile(new File(testDirIn, filename), testDirIn.getAbsolutePath(), testDirOut.getAbsolutePath()))
106 {
107 fail("Rendering failed or is not identical, see in " + testDirOut);
108 }
109 }
110 }
1515 package org.apache.pdfbox.pdmodel.common;
1616
1717 import static org.junit.Assert.assertEquals;
18 import static org.junit.Assert.assertFalse;
1819 import static org.junit.Assert.assertTrue;
1920
21 import java.io.File;
22 import java.io.IOException;
2023 import java.util.ArrayList;
24 import java.util.Collections;
2125 import java.util.List;
2226
2327 import org.apache.pdfbox.cos.COSArray;
2428 import org.apache.pdfbox.cos.COSBase;
25 import org.apache.pdfbox.cos.COSName;
29 import org.apache.pdfbox.pdmodel.PDDocument;
2630 import org.apache.pdfbox.pdmodel.PDPage;
2731 import org.apache.pdfbox.pdmodel.interactive.annotation.AnnotationFilter;
2832 import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
3034 import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationSquareCircle;
3135 import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationTextMarkup;
3236 import org.junit.Before;
37 import org.junit.Rule;
3338 import org.junit.Test;
39 import org.junit.rules.ExpectedException;
3440
3541 public class COSArrayListTest {
42
43 @Rule
44 public ExpectedException thrown = ExpectedException.none();
45
3646 // next two entries are to be used for comparison with
3747 // COSArrayList behaviour in order to ensure that the
3848 // intented object is now at the correct position.
4959 // {@link PDPage.getAnnotations(AnnotationFilter annotationFilter)}
5060 static PDPage pdPage;
5161
62 private static final File OUT_DIR = new File("target/test-output/pdmodel/common");
63
5264 /*
5365 * Create thre new different annotations an add them to the Java List/Array as
5466 * well as PDFBox List/Array implementations.
6375 annotationsList.add(txtMark);
6476 annotationsList.add(txtLink);
6577 annotationsList.add(aCircle);
66 assertTrue(annotationsList.size() == 3);
78 annotationsList.add(txtLink);
79 assertTrue(annotationsList.size() == 4);
6780
6881 tbcAnnotationsList = new ArrayList<PDAnnotation>();
6982 tbcAnnotationsList.add(txtMark);
7083 tbcAnnotationsList.add(txtLink);
7184 tbcAnnotationsList.add(aCircle);
72 assertTrue(tbcAnnotationsList.size() == 3);
85 tbcAnnotationsList.add(txtLink);
86 assertTrue(tbcAnnotationsList.size() == 4);
7387
7488 annotationsArray = new COSArray();
7589 annotationsArray.add(txtMark);
7690 annotationsArray.add(txtLink);
7791 annotationsArray.add(aCircle);
78 assertTrue(annotationsArray.size() == 3);
79
80 tbcAnnotationsArray = new COSBase[3];
92 annotationsArray.add(txtLink);
93 assertTrue(annotationsArray.size() == 4);
94
95 tbcAnnotationsArray = new COSBase[4];
8196 tbcAnnotationsArray[0] = txtMark.getCOSObject();
8297 tbcAnnotationsArray[1] = txtLink.getCOSObject();
8398 tbcAnnotationsArray[2] = aCircle.getCOSObject();
84 assertTrue(tbcAnnotationsArray.length == 3);
99 tbcAnnotationsArray[3] = txtLink.getCOSObject();
100 assertTrue(tbcAnnotationsArray.length == 4);
85101
86102 // add the annotations to the page
87103 pdPage = new PDPage();
88104 pdPage.setAnnotations(annotationsList);
105
106 // create test output directory
107 OUT_DIR.mkdirs();
89108 }
90109
91110 /**
95114 public void getFromList() throws Exception {
96115 COSArrayList<PDAnnotation> cosArrayList = new COSArrayList<PDAnnotation>(annotationsList, annotationsArray);
97116
98 for (int i = 0; i < 3; i++) {
117 for (int i = 0; i < cosArrayList.size(); i++) {
99118 PDAnnotation annot = (PDAnnotation) cosArrayList.get(i);
100 // compare position using COSArrayList
101 assertTrue("PDAnnotations cosObject at " + i + " shall be at index " + i + " of COSArray",
102 annotationsArray.indexOf(annot.getCOSObject()) == i);
119 assertTrue("PDAnnotations cosObject at " + i + " shall be equal to index " + i + " of COSArray",
120 annotationsArray.get(i).equals(annot.getCOSObject()));
103121
104122 // compare with Java List/Array
105123 assertTrue("PDAnnotations at " + i + " shall be at index " + i + " of List",
106 tbcAnnotationsList.indexOf(annot) == i);
124 tbcAnnotationsList.get(i).equals((annot)));
107125 assertEquals("PDAnnotations cosObject at " + i + " shall be at position " + i + " of Array",
108 tbcAnnotationsArray[i], annot.getCOSObject());
126 tbcAnnotationsArray[i], annot.getCOSObject());
109127 }
110128 }
111129
120138 PDAnnotationSquareCircle aSquare = new PDAnnotationSquareCircle(PDAnnotationSquareCircle.SUB_TYPE_SQUARE);
121139 cosArrayList.add(aSquare);
122140
123 assertTrue("List size shall be 4", annotationsList.size() == 4);
124 assertTrue("COSArray size shall be 4", annotationsArray.size() == 4);
125
126 PDAnnotation annot = (PDAnnotation) annotationsList.get(3);
127 assertTrue("Added annotation shall be 4th entry in COSArray", annotationsArray.indexOf(annot.getCOSObject()) == 3);
128 assertEquals("Provided COSArray and underlying COSArray shall be equal", annotationsArray, cosArrayList.toList());
141 assertTrue("List size shall be 5", annotationsList.size() == 5);
142 assertTrue("COSArray size shall be 5", annotationsArray.size() == 5);
143
144 PDAnnotation annot = (PDAnnotation) annotationsList.get(4);
145 assertTrue("Added annotation shall be 4th entry in COSArray", annotationsArray.indexOf(annot.getCOSObject()) == 4);
146 assertEquals("Provided COSArray and underlying COSArray shall be equal", annotationsArray, cosArrayList.getCOSArray());
129147 }
130148
131149 /**
135153 public void removeFromListByIndex() throws Exception {
136154 COSArrayList<PDAnnotation> cosArrayList = new COSArrayList<PDAnnotation>(annotationsList, annotationsArray);
137155
156 int positionToRemove = 2;
157 PDAnnotation toBeRemoved = cosArrayList.get(positionToRemove);
158
159 assertEquals("Remove operation shall return the removed object",toBeRemoved, cosArrayList.remove(positionToRemove));
160 assertTrue("List size shall be 3", cosArrayList.size() == 3);
161 assertTrue("COSArray size shall be 3", annotationsArray.size() == 3);
162
163 assertTrue("PDAnnotation shall no longer exist in List",
164 cosArrayList.indexOf(tbcAnnotationsList.get(positionToRemove)) == -1);
165 assertTrue("COSObject shall no longer exist in COSArray",
166 annotationsArray.indexOf(tbcAnnotationsArray[positionToRemove]) == -1);
167 }
168
169 /**
170 * Test removing a unique PDModel element by index is in sync with underlying COSArray
171 */
172 @Test
173 public void removeUniqueFromListByObject() throws Exception {
174 COSArrayList<PDAnnotation> cosArrayList = new COSArrayList<PDAnnotation>(annotationsList, annotationsArray);
175
176 int positionToRemove = 2;
177 PDAnnotation toBeRemoved = annotationsList.get(positionToRemove);
178
179 assertTrue("Remove operation shall return true",cosArrayList.remove(toBeRemoved));
180 assertTrue("List size shall be 3", cosArrayList.size() == 3);
181 assertTrue("COSArray size shall be 3", annotationsArray.size() == 3);
182
183 // compare with Java List/Array to ensure correct object at position
184 assertTrue("List object at 3 is at position 2 in COSArrayList now",
185 cosArrayList.get(2).equals(tbcAnnotationsList.get(3)));
186 assertTrue("COSObject of List object at 3 is at position 2 in COSArray now",
187 annotationsArray.get(2).equals(tbcAnnotationsList.get(3).getCOSObject()));
188 assertTrue("Array object at 3 is at position 2 in underlying COSArray now",
189 annotationsArray.get(2).equals(tbcAnnotationsArray[3]));
190
191 assertTrue("PDAnnotation shall no longer exist in List",
192 cosArrayList.indexOf(tbcAnnotationsList.get(positionToRemove)) == -1);
193 assertTrue("COSObject shall no longer exist in COSArray",
194 annotationsArray.indexOf(tbcAnnotationsArray[positionToRemove]) == -1);
195
196 assertFalse("Remove shall not remove any object",cosArrayList.remove(toBeRemoved));
197
198 }
199
200 /**
201 * Test removing a unique PDModel element by index is in sync with underlying COSArray
202 */
203 @Test
204 public void removeAllUniqueFromListByObject() throws Exception {
205 COSArrayList<PDAnnotation> cosArrayList = new COSArrayList<PDAnnotation>(annotationsList, annotationsArray);
206
207 int positionToRemove = 2;
208 PDAnnotation toBeRemoved = annotationsList.get(positionToRemove);
209
210 List<PDAnnotation> toBeRemovedInstances = Collections.singletonList(toBeRemoved);
211
212 assertTrue("Remove operation shall return true",cosArrayList.removeAll(toBeRemovedInstances));
213 assertTrue("List size shall be 3", cosArrayList.size() == 3);
214 assertTrue("COSArray size shall be 3", annotationsArray.size() == 3);
215
216 assertFalse("Remove shall not remove any object",cosArrayList.removeAll(toBeRemovedInstances));
217 }
218
219
220 /**
221 * Test removing a multiple appearing PDModel element by index is in sync with underlying COSArray
222 */
223 @Test
224 public void removeMultipleFromListByObject() throws Exception {
225 COSArrayList<PDAnnotation> cosArrayList = new COSArrayList<PDAnnotation>(annotationsList, annotationsArray);
226
138227 int positionToRemove = 1;
139 cosArrayList.remove(positionToRemove);
140
228 PDAnnotation toBeRemoved = tbcAnnotationsList.get(positionToRemove);
229
230 assertTrue("Remove operation shall return true",cosArrayList.remove(toBeRemoved));
231 assertTrue("List size shall be 3", cosArrayList.size() == 3);
232 assertTrue("COSArray size shall be 3", annotationsArray.size() == 3);
233
234 assertTrue("Remove operation shall return true",cosArrayList.remove(toBeRemoved));
141235 assertTrue("List size shall be 2", cosArrayList.size() == 2);
142236 assertTrue("COSArray size shall be 2", annotationsArray.size() == 2);
143237
144 PDAnnotation annot = (PDAnnotation) cosArrayList.get(1);
145 assertTrue("Object at original position 2 shall now be at position 1 in underlying COSArray",
146 annotationsArray.indexOf(annot.getCOSObject()) == 1);
147
148 // compare with Java List/Array to ensure correct object at position
149 assertTrue("List object at 2 is at position 1 in COSArrayList now",
150 cosArrayList.indexOf(tbcAnnotationsList.get(2)) == 1);
151 assertTrue("COSObject of List object at 2 is at position 1 in COSArray now",
152 annotationsArray.indexOf(tbcAnnotationsList.get(2).getCOSObject()) == 1);
153 assertTrue("Array object at 2 is at position 1 in underlying COSArray now",
154 annotationsArray.indexOf(tbcAnnotationsArray[2]) == 1);
155
156 assertTrue("PDAnnotation shall no longer exist in List",
157 cosArrayList.indexOf(tbcAnnotationsList.get(positionToRemove)) == -1);
158 assertTrue("COSObject shall no longer exist in COSArray",
159 annotationsArray.indexOf(tbcAnnotationsArray[positionToRemove]) == -1);
160 }
161
162 /**
163 * Test removing a PDModel element by index is in sync with underlying COSArray
164 */
165 @Test
166 public void removeFromListByObject() throws Exception {
238 }
239
240 /**
241 * Test removing a unique PDModel element by index is in sync with underlying COSArray
242 */
243 @Test
244 public void removeAllMultipleFromListByObject() throws Exception {
167245 COSArrayList<PDAnnotation> cosArrayList = new COSArrayList<PDAnnotation>(annotationsList, annotationsArray);
168246
169247 int positionToRemove = 1;
170 PDAnnotation toBeRemoved = tbcAnnotationsList.get(positionToRemove);
171
172 cosArrayList.remove(toBeRemoved);
173
248 PDAnnotation toBeRemoved = annotationsList.get(positionToRemove);
249
250 List<PDAnnotation> toBeRemovedInstances = Collections.singletonList(toBeRemoved);
251
252 assertTrue("Remove operation shall return true",cosArrayList.removeAll(toBeRemovedInstances));
174253 assertTrue("List size shall be 2", cosArrayList.size() == 2);
175254 assertTrue("COSArray size shall be 2", annotationsArray.size() == 2);
176255
177 PDAnnotation annot = (PDAnnotation) cosArrayList.get(1);
178 assertTrue("Object at original position 2 shall now be at position 1 in underlying COSArray",
179 annotationsArray.indexOf(annot.getCOSObject()) == 1);
180
181 // compare with Java List/Array to ensure correct object at position
182 assertTrue("List object at 2 is at position 1 in COSArrayList now",
183 cosArrayList.indexOf(tbcAnnotationsList.get(2)) == 1);
184 assertTrue("COSObject of List object at 2 is at position 1 in COSArray now",
185 annotationsArray.indexOf(tbcAnnotationsList.get(2).getCOSObject()) == 1);
186 assertTrue("Array object at 2 is at position 1 in underlying COSArray now",
187 annotationsArray.indexOf(tbcAnnotationsArray[2]) == 1);
188
189 assertTrue("PDAnnotation shall no longer exist in List",
190 cosArrayList.indexOf(tbcAnnotationsList.get(positionToRemove)) == -1);
191 assertTrue("COSObject shall no longer exist in COSArray",
192 annotationsArray.indexOf(tbcAnnotationsArray[positionToRemove]) == -1);
256 assertFalse("Remove shall not remove any object",cosArrayList.removeAll(toBeRemovedInstances));
193257 }
194258
195259 @Test
196260 public void removeFromFilteredListByIndex() throws Exception
197261 {
262 // removing from a filtered list is not permitted
263 thrown.expect(UnsupportedOperationException.class);
264
198265 // retrieve all annotations from page but the link annotation
199266 // which is 2nd in list - see above setup
200267 AnnotationFilter annotsFilter = new AnnotationFilter()
207274 };
208275
209276 COSArrayList<PDAnnotation> cosArrayList = (COSArrayList<PDAnnotation>) pdPage.getAnnotations(annotsFilter);
210 COSArray underlyingCOSArray = pdPage.getCOSObject().getCOSArray(COSName.ANNOTS);
211
212 assertTrue("Filtered COSArrayList size shall be 2", cosArrayList.size() == 2);
213 assertTrue("Underlying COSArray shall have 3 entries", underlyingCOSArray.size() == 3);
214 assertTrue("Backed COSArray shall have 3 entries", cosArrayList.toList().size() == 3);
215
216 // remove aCircle annotation
217 int positionToRemove = 1;
218 PDAnnotation toBeRemoved = cosArrayList.get(positionToRemove);
219 assertTrue("We should remove the circle annotation", toBeRemoved.getSubtype().equals(PDAnnotationSquareCircle.SUB_TYPE_CIRCLE));
220 cosArrayList.remove(positionToRemove);
221
222 assertTrue("List size shall be 2", cosArrayList.size() == 1);
223 assertTrue("COSArray size shall be 2", underlyingCOSArray.size() == 2);
224 assertTrue("Backed COSArray size shall be 2", cosArrayList.toList().size() == 2);
225
226 assertTrue("Removed annotation shall no longer appear in COSArrayList", cosArrayList.indexOf(toBeRemoved) == -1);
227 assertTrue("Removed annotation shall no longer appear in underlying COSArray", underlyingCOSArray.indexOf(toBeRemoved.getCOSObject()) == -1);
228 assertTrue("Removed annotation shall no longer appear in backed COSArray", cosArrayList.toList().indexOf(toBeRemoved.getCOSObject()) == -1);
277
278 // this call should fail
279 cosArrayList.remove(1);
229280 }
230281
231282
232283 @Test
233284 public void removeFromFilteredListByObject() throws Exception
234285 {
286 // removing from a filtered list is not permitted
287 thrown.expect(UnsupportedOperationException.class);
288
235289 // retrieve all annotations from page but the link annotation
236290 // which is 2nd in list - see above setup
237291 AnnotationFilter annotsFilter = new AnnotationFilter()
244298 };
245299
246300 COSArrayList<PDAnnotation> cosArrayList = (COSArrayList<PDAnnotation>) pdPage.getAnnotations(annotsFilter);
247 COSArray underlyingCOSArray = pdPage.getCOSObject().getCOSArray(COSName.ANNOTS);
248
249 assertTrue("Filtered COSArrayList size shall be 2", cosArrayList.size() == 2);
250 assertTrue("Underlying COSArray shall have 3 entries", underlyingCOSArray.size() == 3);
251 assertTrue("Backed COSArray shall have 3 entries", cosArrayList.toList().size() == 3);
252
253 // remove aCircle annotation
301
302 // remove object
254303 int positionToRemove = 1;
255304 PDAnnotation toBeRemoved = cosArrayList.get(positionToRemove);
256 assertTrue("We should remove the circle annotation", toBeRemoved.getSubtype().equals(PDAnnotationSquareCircle.SUB_TYPE_CIRCLE));
305
306 // this call should fail
257307 cosArrayList.remove(toBeRemoved);
258308
259 assertTrue("List size shall be 2", cosArrayList.size() == 1);
260 assertTrue("COSArray size shall be 2", underlyingCOSArray.size() == 2);
261 assertTrue("Backed COSArray size shall be 2", cosArrayList.toList().size() == 2);
262
263 assertTrue("Removed annotation shall no longer appear in COSArrayList", cosArrayList.indexOf(toBeRemoved) == -1);
264 assertTrue("Removed annotation shall no longer appear in underlying COSArray", underlyingCOSArray.indexOf(toBeRemoved.getCOSObject()) == -1);
265 assertTrue("Removed annotation shall no longer appear in backed COSArray", cosArrayList.toList().indexOf(toBeRemoved.getCOSObject()) == -1);
309 }
310
311 @Test
312 public void removeSingleDirectObject() throws IOException {
313
314 // generate test file
315 PDDocument pdf = new PDDocument();
316
317 PDPage page = new PDPage();
318 pdf.addPage(page);
319
320 ArrayList<PDAnnotation> pageAnnots = new ArrayList<PDAnnotation>();
321 PDAnnotationTextMarkup txtMark = new PDAnnotationTextMarkup(PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
322 PDAnnotationLink txtLink = new PDAnnotationLink();
323
324 // enforce the COSDictionaries to be written directly into the COSArray
325 txtMark.getCOSObject().getCOSObject().setDirect(true);
326 txtLink.getCOSObject().getCOSObject().setDirect(true);
327
328 pageAnnots.add(txtMark);
329 pageAnnots.add(txtMark);
330 pageAnnots.add(txtMark);
331 pageAnnots.add(txtLink);
332 assertTrue("There shall be 4 annotations generated", pageAnnots.size() == 4);
333
334 page.setAnnotations(pageAnnots);
335
336 pdf.save(OUT_DIR + "/removeSingleDirectObjectTest.pdf");
337 pdf.close();
338
339 pdf = PDDocument.load(new File(OUT_DIR + "/removeSingleDirectObjectTest.pdf"));
340 page = pdf.getPage(0);
341
342 COSArrayList<PDAnnotation> annotations = (COSArrayList) page.getAnnotations();
343
344 assertTrue("There shall be 4 annotations retrieved", annotations.size() == 4);
345 assertTrue("The size of the internal COSArray shall be 4", annotations.getCOSArray().size() == 4);
346
347 PDAnnotation toBeRemoved = annotations.get(0);
348 annotations.remove(toBeRemoved);
349
350 assertTrue("There shall be 3 annotations left", annotations.size() == 3);
351 assertTrue("The size of the internal COSArray shall be 3", annotations.getCOSArray().size() == 3);
352 pdf.close();
353 }
354
355 @Test
356 public void removeSingleIndirectObject() throws IOException {
357
358 // generate test file
359 PDDocument pdf = new PDDocument();
360 PDPage page = new PDPage();
361 pdf.addPage(page);
362
363 ArrayList<PDAnnotation> pageAnnots = new ArrayList<PDAnnotation>();
364 PDAnnotationTextMarkup txtMark = new PDAnnotationTextMarkup(PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
365 PDAnnotationLink txtLink = new PDAnnotationLink();
366
367 pageAnnots.add(txtMark);
368 pageAnnots.add(txtMark);
369 pageAnnots.add(txtMark);
370 pageAnnots.add(txtLink);
371 assertTrue("There shall be 4 annotations generated", pageAnnots.size() == 4);
372
373 page.setAnnotations(pageAnnots);
374
375 pdf.save(OUT_DIR + "/removeSingleIndirectObjectTest.pdf");
376 pdf.close();
377
378 pdf = PDDocument.load(new File(OUT_DIR + "/removeSingleIndirectObjectTest.pdf"));
379 page = pdf.getPage(0);
380
381 COSArrayList<PDAnnotation> annotations = (COSArrayList) page.getAnnotations();
382
383 assertTrue("There shall be 4 annotations retrieved", annotations.size() == 4);
384 assertTrue("The size of the internal COSArray shall be 4", annotations.getCOSArray().size() == 4);
385
386 PDAnnotation toBeRemoved = annotations.get(0);
387
388 annotations.remove(toBeRemoved);
389
390 assertTrue("There shall be 3 annotations left", annotations.size() == 3);
391 assertTrue("The size of the internal COSArray shall be 2", annotations.getCOSArray().size() == 3);
392 pdf.close();
393 }
394
395 // @Test
396 // PDFBOX-4669, PDFBOX-4723
397 // This test is currently disabled with the removeAll function not properly
398 // working. See the discussion in above mentioned tickets about currently not implementing equals which the
399 // functionality would need to rely on.
400 public void removeDirectObject() throws IOException {
401
402 // generate test file
403 PDDocument pdf = new PDDocument();
404 PDPage page = new PDPage();
405 pdf.addPage(page);
406
407 ArrayList<PDAnnotation> pageAnnots = new ArrayList<PDAnnotation>();
408 PDAnnotationTextMarkup txtMark = new PDAnnotationTextMarkup(PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
409 PDAnnotationLink txtLink = new PDAnnotationLink();
410
411 // enforce the COSDictionaries to be written directly into the COSArray
412 txtMark.getCOSObject().getCOSObject().setDirect(true);
413 txtLink.getCOSObject().getCOSObject().setDirect(true);
414
415 pageAnnots.add(txtMark);
416 pageAnnots.add(txtMark);
417 pageAnnots.add(txtMark);
418 pageAnnots.add(txtLink);
419 assertTrue("There shall be 4 annotations generated", pageAnnots.size() == 4);
420
421 page.setAnnotations(pageAnnots);
422
423 pdf.save(OUT_DIR + "/removeDirectObjectTest.pdf");
424 pdf.close();
425
426 pdf = PDDocument.load(new File(OUT_DIR + "/removeDirectObjectTest.pdf"));
427 page = pdf.getPage(0);
428
429 COSArrayList<PDAnnotation> annotations = (COSArrayList) page.getAnnotations();
430
431 assertTrue("There shall be 4 annotations retrieved", annotations.size() == 4);
432 assertTrue("The size of the internal COSArray shall be 4", annotations.getCOSArray().size() == 4);
433
434 ArrayList<PDAnnotation> toBeRemoved = new ArrayList<PDAnnotation>();
435
436 toBeRemoved.add(annotations.get(0));
437 annotations.removeAll(toBeRemoved);
438
439 assertTrue("There shall be 1 annotations left", annotations.size() == 1);
440 assertTrue("The size of the internal COSArray shall be 1", annotations.getCOSArray().size() == 1);
441 }
442
443 @Test
444 public void removeIndirectObject() throws IOException {
445
446 // generate test file
447 PDDocument pdf = new PDDocument();
448 PDPage page = new PDPage();
449 pdf.addPage(page);
450
451 ArrayList<PDAnnotation> pageAnnots = new ArrayList<PDAnnotation>();
452 PDAnnotationTextMarkup txtMark = new PDAnnotationTextMarkup(PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
453 PDAnnotationLink txtLink = new PDAnnotationLink();
454
455 pageAnnots.add(txtMark);
456 pageAnnots.add(txtMark);
457 pageAnnots.add(txtMark);
458 pageAnnots.add(txtLink);
459 assertTrue("There shall be 4 annotations generated", pageAnnots.size() == 4);
460
461 page.setAnnotations(pageAnnots);
462
463 pdf.save(OUT_DIR + "/removeIndirectObjectTest.pdf");
464 pdf.close();
465
466 pdf = PDDocument.load(new File(OUT_DIR + "/removeIndirectObjectTest.pdf"));
467 page = pdf.getPage(0);
468
469 COSArrayList<PDAnnotation> annotations = (COSArrayList) page.getAnnotations();
470
471 assertTrue("There shall be 4 annotations retrieved", annotations.size() == 4);
472 assertTrue("The size of the internal COSArray shall be 4", annotations.getCOSArray().size() == 4);
473
474 ArrayList<PDAnnotation> toBeRemoved = new ArrayList<PDAnnotation>();
475 toBeRemoved.add(annotations.get(0));
476
477 annotations.removeAll(toBeRemoved);
478
479 assertTrue("There shall be 1 annotations left", annotations.size() == 1);
480 assertTrue("The size of the internal COSArray shall be 1", annotations.getCOSArray().size() == 1);
481 }
482
483 // @Test
484 // PDFBOX-4669, PDFBOX-4723
485 // This test is currently disabled with the retainAll function not properly
486 // working. See the discussion in above mentioned tickets about currently not implementing equals which the
487 // functionality would need to rely on.
488 public void retainDirectObject() throws IOException {
489
490 // generate test file
491 PDDocument pdf = new PDDocument();
492 PDPage page = new PDPage();
493 pdf.addPage(page);
494
495 ArrayList<PDAnnotation> pageAnnots = new ArrayList<PDAnnotation>();
496 PDAnnotationTextMarkup txtMark = new PDAnnotationTextMarkup(PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
497 PDAnnotationLink txtLink = new PDAnnotationLink();
498
499 // enforce the COSDictionaries to be written directly into the COSArray
500 txtMark.getCOSObject().getCOSObject().setDirect(true);
501 txtLink.getCOSObject().getCOSObject().setDirect(true);
502
503 pageAnnots.add(txtMark);
504 pageAnnots.add(txtMark);
505 pageAnnots.add(txtMark);
506 pageAnnots.add(txtLink);
507 assertTrue("There shall be 4 annotations generated", pageAnnots.size() == 4);
508
509 page.setAnnotations(pageAnnots);
510
511 pdf.save(OUT_DIR + "/retainDirectObjectTest.pdf");
512 pdf.close();
513
514 pdf = PDDocument.load(new File(OUT_DIR + "/retainDirectObjectTest.pdf"));
515 page = pdf.getPage(0);
516
517 COSArrayList<PDAnnotation> annotations = (COSArrayList) page.getAnnotations();
518
519 assertTrue("There shall be 4 annotations retrieved", annotations.size() == 4);
520 assertTrue("The size of the internal COSArray shall be 4", annotations.getCOSArray().size() == 4);
521
522 ArrayList<PDAnnotation> toBeRetained = new ArrayList<PDAnnotation>();
523
524 toBeRetained.add(annotations.get(0));
525 annotations.retainAll(toBeRetained);
526
527 assertTrue("There shall be 3 annotations left", annotations.size() == 3);
528 assertTrue("The size of the internal COSArray shall be 3", annotations.getCOSArray().size() == 3);
529 }
530
531 // @Test
532 // PDFBOX-4669, PDFBOX-4723
533 // This test is currently disabled with the retainAll function not properly
534 // working. See the discussion in above mentioned tickets about currently not implementing equals which the
535 // functionality would need to rely on.
536 public void retainIndirectObject() throws IOException {
537
538 // generate test file
539 PDDocument pdf = new PDDocument();
540 PDPage page = new PDPage();
541 pdf.addPage(page);
542
543 ArrayList<PDAnnotation> pageAnnots = new ArrayList<PDAnnotation>();
544 PDAnnotationTextMarkup txtMark = new PDAnnotationTextMarkup(PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT);
545 PDAnnotationLink txtLink = new PDAnnotationLink();
546
547 // enforce the COSDictionaries to be written directly into the COSArray
548 txtMark.getCOSObject().getCOSObject().setDirect(true);
549 txtLink.getCOSObject().getCOSObject().setDirect(true);
550
551 pageAnnots.add(txtMark);
552 pageAnnots.add(txtMark);
553 pageAnnots.add(txtMark);
554 pageAnnots.add(txtLink);
555 assertTrue("There shall be 4 annotations generated", pageAnnots.size() == 4);
556
557 page.setAnnotations(pageAnnots);
558
559 pdf.save(OUT_DIR + "/retainIndirectObjectTest.pdf");
560 pdf.close();
561
562 pdf = PDDocument.load(new File(OUT_DIR + "/retainIndirectObjectTest.pdf"));
563 page = pdf.getPage(0);
564
565 COSArrayList<PDAnnotation> annotations = (COSArrayList) page.getAnnotations();
566
567 assertTrue("There shall be 4 annotations retrieved", annotations.size() == 4);
568 assertTrue("The size of the internal COSArray shall be 4", annotations.getCOSArray().size() == 4);
569
570 ArrayList<PDAnnotation> toBeRetained = new ArrayList<PDAnnotation>();
571
572 toBeRetained.add(annotations.get(0));
573 annotations.retainAll(toBeRetained);
574
575 assertTrue("There shall be 3 annotations left", annotations.size() == 3);
576 assertTrue("The size of the internal COSArray shall be 3", annotations.getCOSArray().size() == 3);
266577 }
267578 }
3131 import org.apache.pdfbox.pdmodel.PDDocument;
3232 import org.apache.pdfbox.rendering.PDFRenderer;
3333 import org.apache.pdfbox.rendering.TestPDFToImage;
34 import static org.junit.Assert.fail;
3435 import org.junit.Before;
3536 import org.junit.Test;
3637
3738 /**
3839 * Test flatten different forms and compare with rendering.
3940 *
40 * The tests are currently disabled to not run within the CI environment
41 * Some of the tests are currently disabled to not run within the CI environment
4142 * as the test results need manual inspection. Enable as needed.
4243 *
4344 */
5758 /*
5859 * PDFBOX-142 Filled template.
5960 */
60 //@Test
61 // @Test
6162 public void testFlattenPDFBOX142() throws IOException
6263 {
6364 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12742551/Testformular1.pdf";
6970 /*
7071 * PDFBOX-563 Filled template.
7172 */
72 //@Test
73 @Test
7374 public void testFlattenPDFBOX563() throws IOException
7475 {
7576 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12425859/TestFax_56972.pdf";
8182 /*
8283 * PDFBOX-2469 Empty template.
8384 */
84 //@Test
85 @Test
8586 public void testFlattenPDFBOX2469Empty() throws IOException
8687 {
8788 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12682897/FormI-9-English.pdf";
9394 /*
9495 * PDFBOX-2469 Filled template.
9596 */
96 //@Test
97 @Test
9798 public void testFlattenPDFBOX2469Filled() throws IOException
9899 {
99100 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12678455/testPDF_acroForm.pdf";
105106 /*
106107 * PDFBOX-2586 Empty template.
107108 */
108 //@Test
109 @Test
109110 public void testFlattenPDFBOX2586() throws IOException
110111 {
111112 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12689788/test.pdf";
117118 /*
118119 * PDFBOX-3083 Filled template rotated.
119120 */
120 //@Test
121 // @Test
121122 public void testFlattenPDFBOX3083() throws IOException
122123 {
123124 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12770263/mypdf.pdf";
129130 /*
130131 * PDFBOX-3262 Hidden fields
131132 */
132 //@Test
133 @Test
133134 public void testFlattenPDFBOX3262() throws IOException
134135 {
135136 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12792007/hidden_fields.pdf";
141142 /*
142143 * PDFBOX-3396 Signed Document 1.
143144 */
144 //@Test
145 @Test
145146 public void testFlattenPDFBOX3396_1() throws IOException
146147 {
147148 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12816014/Signed-Document-1.pdf";
153154 /*
154155 * PDFBOX-3396 Signed Document 2.
155156 */
156 //@Test
157 @Test
157158 public void testFlattenPDFBOX3396_2() throws IOException
158159 {
159160 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12816016/Signed-Document-2.pdf";
165166 /*
166167 * PDFBOX-3396 Signed Document 3.
167168 */
168 //@Test
169 @Test
169170 public void testFlattenPDFBOX3396_3() throws IOException
170171 {
171172 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12821307/Signed-Document-3.pdf";
177178 /*
178179 * PDFBOX-3396 Signed Document 4.
179180 */
180 //@Test
181 @Test
181182 public void testFlattenPDFBOX3396_4() throws IOException
182183 {
183184 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12821308/Signed-Document-4.pdf";
189190 /*
190191 * PDFBOX-3587 Empty template.
191192 */
192 //@Test
193 // @Test
193194 public void testFlattenOpenOfficeForm() throws IOException
194195 {
195196 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12839977/OpenOfficeForm.pdf";
201202 /*
202203 * PDFBOX-3587 Filled template.
203204 */
204 //@Test
205 // @Test
205206 public void testFlattenOpenOfficeFormFilled() throws IOException
206207 {
207208 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12840280/OpenOfficeForm_filled.pdf";
213214 /**
214215 * PDFBOX-4157 Filled template.
215216 */
216 //@Test
217 // @Test
217218 public void testFlattenPDFBox4157() throws IOException
218219 {
219220 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12976553/PDFBOX-4157-filled.pdf";
225226 /**
226227 * PDFBOX-4172 Filled template.
227228 */
228 //@Test
229 // @Test
229230 public void testFlattenPDFBox4172() throws IOException
230231 {
231232 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12976552/PDFBOX-4172-filled.pdf";
237238 /**
238239 * PDFBOX-4615 Filled template.
239240 */
240 //@Test
241 // @Test
241242 public void testFlattenPDFBox4615() throws IOException
242243 {
243244 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12976452/resetboundingbox-filled.pdf";
249250 /**
250251 * PDFBOX-4693: page is not rotated, but the appearance stream is.
251252 */
252 //@Test
253 @Test
253254 public void testFlattenPDFBox4693() throws IOException
254255 {
255256 String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12986337/stenotypeTest-3_rotate_no_flatten.pdf";
280281 TestPDFToImage testPDFToImage = new TestPDFToImage(TestPDFToImage.class.getName());
281282 if (!testPDFToImage.doTestFile(outputFile, IN_DIR.getAbsolutePath(), OUT_DIR.getAbsolutePath()))
282283 {
283 // don't fail, rendering is different on different systems, result must be viewed manually
284 System.out.println("Rendering of " + outputFile + " failed or is not identical to expected rendering in " + IN_DIR + " directory");
284 fail("Rendering of " + outputFile + " failed or is not identical to expected rendering in " + IN_DIR + " directory");
285285 removeMatchingRenditions(inputFile);
286286 return false;
287287 }
359359
360360 for (File testFile : testFiles)
361361 {
362 if (! new File(OUT_DIR, testFile.getName()).exists())
362 if (!new File(OUT_DIR, testFile.getName()).exists())
363363 {
364364 testFile.delete();
365365 }
184184 {
185185 equals = false;
186186 log.warn("Actual line is longer at:" + actualIndex );
187 }
188 if (expectedArray.length != actualArray.length)
189 {
190 equals = false;
191 log.warn("Expected lines: " + expectedArray.length + ", actual lines: " + actualArray.length);
187192 }
188193 }
189194 }
2121
2222 /**
2323 *
24 * @author Neil McErlean
2425 * @author Tilman Hausherr
2526 */
2627 public class MatrixTest
2728 {
2829
30 @Test
31 public void testConstructionAndCopy() throws Exception
32 {
33 Matrix m1 = new Matrix();
34 assertMatrixIsPristine(m1);
35
36 Matrix m2 = m1.clone();
37 assertNotSame(m1, m2);
38 assertMatrixIsPristine(m2);
39 }
40
41 @Test
42 public void testMultiplication() throws Exception
43 {
44 // This matrix will not change - we use it to drive the various multiplications.
45 final Matrix testMatrix = new Matrix();
46
47 // Create matrix with values
48 // [ 0, 1, 2
49 // 1, 2, 3
50 // 2, 3, 4]
51 for (int x = 0; x < 3; x++)
52 {
53 for (int y = 0; y < 3; y++)
54 {
55 testMatrix.setValue(x, y, x + y);
56 }
57 }
58
59 Matrix m1 = testMatrix.clone();
60 Matrix m2 = testMatrix.clone();
61
62 // Multiply two matrices together producing a new result matrix.
63 Matrix product = m1.multiply(m2);
64
65 assertNotSame(m1, product);
66 assertNotSame(m2, product);
67
68 // Operand 1 should not have changed
69 assertMatrixValuesEqualTo(new float[] { 0, 1, 2, 1, 2, 3, 2, 3, 4 }, m1);
70 // Operand 2 should not have changed
71 assertMatrixValuesEqualTo(new float[] { 0, 1, 2, 1, 2, 3, 2, 3, 4 }, m2);
72 assertMatrixValuesEqualTo(new float[] { 5, 8, 11, 8, 14, 20, 11, 20, 29 }, product);
73
74 // Multiply two matrices together with the result being written to a third matrix
75 // (Any existing values there will be overwritten).
76 Matrix resultMatrix = new Matrix();
77
78 Matrix retVal = m1.multiply(m2, resultMatrix);
79 assertSame(retVal, resultMatrix);
80 // Operand 1 should not have changed
81 assertMatrixValuesEqualTo(new float[] { 0, 1, 2, 1, 2, 3, 2, 3, 4 }, m1);
82 // Operand 2 should not have changed
83 assertMatrixValuesEqualTo(new float[] { 0, 1, 2, 1, 2, 3, 2, 3, 4 }, m2);
84 assertMatrixValuesEqualTo(new float[] { 5, 8, 11, 8, 14, 20, 11, 20, 29 }, resultMatrix);
85
86 // Multiply two matrices together with the result being written into the other matrix
87 retVal = m1.multiply(m2, m2);
88 assertSame(retVal, m2);
89 // Operand 1 should not have changed
90 assertMatrixValuesEqualTo(new float[] { 0, 1, 2, 1, 2, 3, 2, 3, 4 }, m1);
91 assertMatrixValuesEqualTo(new float[] { 5, 8, 11, 8, 14, 20, 11, 20, 29 }, retVal);
92
93 // Multiply two matrices together with the result being written into 'this' matrix
94 m1 = testMatrix.clone();
95 m2 = testMatrix.clone();
96
97 retVal = m1.multiply(m2, m1);
98 assertSame(retVal, m1);
99 // Operand 2 should not have changed
100 assertMatrixValuesEqualTo(new float[] { 0, 1, 2, 1, 2, 3, 2, 3, 4 }, m2);
101 assertMatrixValuesEqualTo(new float[] { 5, 8, 11, 8, 14, 20, 11, 20, 29 }, retVal);
102
103 // Multiply the same matrix with itself with the result being written into 'this' matrix
104 m1 = testMatrix.clone();
105
106 retVal = m1.multiply(m1, m1);
107 assertSame(retVal, m1);
108 assertMatrixValuesEqualTo(new float[] { 5, 8, 11, 8, 14, 20, 11, 20, 29 }, retVal);
109 }
110
111 @Test(expected = IllegalArgumentException.class)
112 public void testIllegalValueNaN1()
113 {
114 Matrix m = new Matrix();
115 m.setValue(0, 0, Float.MAX_VALUE);
116 m.multiply(m, m);
117 }
118
119 @Test(expected = IllegalArgumentException.class)
120 public void testIllegalValueNaN2()
121 {
122 Matrix m = new Matrix();
123 m.setValue(0, 0, Float.NaN);
124 m.multiply(m, m);
125 }
126
127 @Test(expected = IllegalArgumentException.class)
128 public void testIllegalValuePositiveInfinity()
129 {
130 Matrix m = new Matrix();
131 m.setValue(0, 0, Float.POSITIVE_INFINITY);
132 m.multiply(m, m);
133 }
134
135 @Test(expected = IllegalArgumentException.class)
136 public void testIllegalValueNegativeInfinity()
137 {
138 Matrix m = new Matrix();
139 m.setValue(0, 0, Float.NEGATIVE_INFINITY);
140 m.multiply(m, m);
141 }
142
29143 /**
30144 * Test of PDFBOX-2872 bug
31145 */
43157
44158 }
45159
160 /**
161 * This method asserts that the matrix values for the given {@link Matrix} object are equal to the pristine, or
162 * original, values.
163 *
164 * @param m the Matrix to test.
165 */
166 private void assertMatrixIsPristine(Matrix m)
167 {
168 assertMatrixValuesEqualTo(new float[] { 1, 0, 0, 0, 1, 0, 0, 0, 1 }, m);
169 }
170
171 /**
172 * This method asserts that the matrix values for the given {@link Matrix} object have the specified values.
173 *
174 * @param values the expected values
175 * @param m the matrix to test
176 */
177 private void assertMatrixValuesEqualTo(float[] values, Matrix m)
178 {
179 float delta = 0.00001f;
180 for (int i = 0; i < values.length; i++)
181 {
182 // Need to convert a (row, column) coordinate into a straight index.
183 int row = (int) Math.floor(i / 3);
184 int column = i % 3;
185 StringBuilder failureMsg = new StringBuilder();
186 failureMsg.append("Incorrect value for matrix[").append(row).append(",").append(column)
187 .append("]");
188 assertEquals(failureMsg.toString(), values[i], m.getValue(row, column), delta);
189 }
190 }
46191
47192 }
+0
-204
pdfbox/src/test/java/org/apache/pdfbox/util/TestMatrix.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.pdfbox.util;
17
18 import java.io.IOException;
19
20 import junit.framework.Test;
21 import junit.framework.TestCase;
22 import junit.framework.TestSuite;
23
24 /**
25 * Test the {@link Matrix} class.
26 * @author Neil McErlean
27 * @since 1.4.0
28 */
29 public class TestMatrix extends TestCase
30 {
31 /**
32 * Test class constructor.
33 *
34 * @param name The name of the test class.
35 *
36 * @throws IOException If there is an error creating the test.
37 */
38 public TestMatrix( String name ) throws IOException
39 {
40 super( name );
41 }
42
43 public void testConstructionAndCopy() throws Exception
44 {
45 Matrix m1 = new Matrix();
46 assertMatrixIsPristine(m1);
47
48 Matrix m2 = m1.clone();
49 assertNotSame(m1, m2);
50 assertMatrixIsPristine(m2);
51 }
52
53 public void testMultiplication() throws Exception
54 {
55 // This matrix will not change - we use it to drive the various multiplications.
56 final Matrix testMatrix = new Matrix();
57
58 // Create matrix with values
59 // [ 0, 1, 2
60 // 1, 2, 3
61 // 2, 3, 4]
62 for (int x = 0; x < 3; x++)
63 {
64 for (int y = 0; y < 3; y++)
65 {
66 testMatrix.setValue(x, y, x + y);
67 }
68 }
69
70 Matrix m1 = testMatrix.clone();
71 Matrix m2 = testMatrix.clone();
72
73 // Multiply two matrices together producing a new result matrix.
74 Matrix product = m1.multiply(m2);
75
76 assertNotSame(m1, product);
77 assertNotSame(m2, product);
78
79 // Operand 1 should not have changed
80 assertMatrixValuesEqualTo(new float[] {0, 1, 2,
81 1, 2, 3,
82 2, 3, 4}, m1);
83 // Operand 2 should not have changed
84 assertMatrixValuesEqualTo(new float[] {0, 1, 2,
85 1, 2, 3,
86 2, 3, 4}, m2);
87 assertMatrixValuesEqualTo(new float[] {5, 8, 11,
88 8, 14, 20,
89 11, 20, 29}, product);
90
91 // Multiply two matrices together with the result being written to a third matrix
92 // (Any existing values there will be overwritten).
93 Matrix resultMatrix = new Matrix();
94
95 Matrix retVal = m1.multiply(m2, resultMatrix);
96 assertSame(retVal, resultMatrix);
97 // Operand 1 should not have changed
98 assertMatrixValuesEqualTo(new float[] {0, 1, 2,
99 1, 2, 3,
100 2, 3, 4}, m1);
101 // Operand 2 should not have changed
102 assertMatrixValuesEqualTo(new float[] {0, 1, 2,
103 1, 2, 3,
104 2, 3, 4}, m2);
105 assertMatrixValuesEqualTo(new float[] {5, 8, 11,
106 8, 14, 20,
107 11, 20, 29}, resultMatrix);
108
109
110
111 // Multiply two matrices together with the result being written into the other matrix
112 retVal = m1.multiply(m2, m2);
113 assertSame(retVal, m2);
114 // Operand 1 should not have changed
115 assertMatrixValuesEqualTo(new float[] {0, 1, 2,
116 1, 2, 3,
117 2, 3, 4}, m1);
118 assertMatrixValuesEqualTo(new float[] {5, 8, 11,
119 8, 14, 20,
120 11, 20, 29}, retVal);
121
122
123
124 // Multiply two matrices together with the result being written into 'this' matrix
125 m1 = testMatrix.clone();
126 m2 = testMatrix.clone();
127
128 retVal = m1.multiply(m2, m1);
129 assertSame(retVal, m1);
130 // Operand 2 should not have changed
131 assertMatrixValuesEqualTo(new float[] {0, 1, 2,
132 1, 2, 3,
133 2, 3, 4}, m2);
134 assertMatrixValuesEqualTo(new float[] {5, 8, 11,
135 8, 14, 20,
136 11, 20, 29}, retVal);
137
138
139
140 // Multiply the same matrix with itself with the result being written into 'this' matrix
141 m1 = testMatrix.clone();
142
143 retVal = m1.multiply(m1, m1);
144 assertSame(retVal, m1);
145 assertMatrixValuesEqualTo(new float[] {5, 8, 11,
146 8, 14, 20,
147 11, 20, 29}, retVal);
148 }
149
150 /**
151 * This method asserts that the matrix values for the given {@link Matrix} object are equal
152 * to the pristine, or original, values.
153 * @param m the Matrix to test.
154 */
155 private void assertMatrixIsPristine(Matrix m)
156 {
157 assertMatrixValuesEqualTo(new float[] {1 ,0 ,0,
158 0, 1, 0,
159 0, 0, 1}, m);
160 }
161
162 /**
163 * This method asserts that the matrix values for the given {@link Matrix} object have
164 * the specified values.
165 * @param values the expected values
166 * @param m the matrix to test
167 */
168 private void assertMatrixValuesEqualTo(float[] values, Matrix m)
169 {
170 float delta = 0.00001f;
171 for (int i = 0; i < values.length; i++)
172 {
173 // Need to convert a (row, column) coordinate into a straight index.
174 int row = (int)Math.floor(i / 3);
175 int column = i % 3;
176 StringBuilder failureMsg = new StringBuilder();
177 failureMsg.append("Incorrect value for matrix[")
178 .append(row).append(",").append(column).append("]");
179 assertEquals(failureMsg.toString(), values[i], m.getValue(row, column), delta);
180 }
181 }
182
183 /**
184 * Set the tests in the suite for this test class.
185 *
186 * @return the Suite.
187 */
188 public static Test suite()
189 {
190 return new TestSuite( TestMatrix.class );
191 }
192
193 /**
194 * Command line execution.
195 *
196 * @param args Command line arguments.
197 */
198 public static void main( String[] args )
199 {
200 String[] arg = {TestMatrix.class.getName() };
201 junit.textui.TestRunner.main( arg );
202 }
203 }
2222 <parent>
2323 <groupId>org.apache.pdfbox</groupId>
2424 <artifactId>pdfbox-parent</artifactId>
25 <version>2.0.18</version>
25 <version>2.0.19</version>
2626 <relativePath>parent/pom.xml</relativePath>
2727 </parent>
2828
3333
3434 <scm>
3535 <connection>
36 scm:svn:http://svn.apache.org/repos/asf/pdfbox/tags/2.0.18
36 scm:svn:http://svn.apache.org/repos/asf/pdfbox/tags/2.0.19
3737 </connection>
3838 <developerConnection>
39 scm:svn:https://svn.apache.org/repos/asf/pdfbox/tags/2.0.18
39 scm:svn:https://svn.apache.org/repos/asf/pdfbox/tags/2.0.19
4040 </developerConnection>
41 <url>http://svn.apache.org/viewvc/pdfbox/tags/2.0.18</url>
41 <url>http://svn.apache.org/viewvc/pdfbox/tags/2.0.19</url>
4242 </scm>
4343
4444 <modules>
2525 <parent>
2626 <groupId>org.apache.pdfbox</groupId>
2727 <artifactId>pdfbox-parent</artifactId>
28 <version>2.0.18</version>
28 <version>2.0.19</version>
2929 <relativePath>../parent/pom.xml</relativePath>
3030 </parent>
3131
2727 import org.apache.xmpbox.schema.XMPSchema;
2828
2929 /**
30 * Class which all elements within an rdf:RDF have the same value for their rdf:about attributes
31 *
30 * Class which checks that all elements within an rdf:RDF have the same value for their rdf:about
31 * attributes.
32 *
3233 * @author Germain Costenobel
33 *
34 *
3435 */
3536 public class RDFAboutAttributeConcordanceValidation
3637 {
3738
3839 /**
39 *
40 *
4041 * @param metadata the XMP metadata.
4142 * @throws DifferentRDFAboutException
4243 * @throws ValidationException
4748 List<XMPSchema> schemas = metadata.getAllSchemas();
4849 if (schemas.isEmpty())
4950 {
50 throw new ValidationException("Schemas not found in the given metadata representation");
51 throw new ValidationException("No schema found in the given metadata representation");
5152 }
52
53
5354 String about = schemas.get(0).getAboutValue();
54
55
5556 // rdf:description must have an rdf:about attribute
5657 for (XMPSchema xmpSchema : schemas)
5758 {
6162 {
6263 throw new DifferentRDFAboutException();
6364 }
64
65
6566 if ("".equals(about))
6667 {
6768 about = schemaAboutValue;
2222 <parent>
2323 <groupId>org.apache.pdfbox</groupId>
2424 <artifactId>pdfbox-parent</artifactId>
25 <version>2.0.18</version>
25 <version>2.0.19</version>
2626 <relativePath>../parent/pom.xml</relativePath>
2727 </parent>
2828
2222 <parent>
2323 <groupId>org.apache.pdfbox</groupId>
2424 <artifactId>pdfbox-parent</artifactId>
25 <version>2.0.18</version>
25 <version>2.0.19</version>
2626 <relativePath>../parent/pom.xml</relativePath>
2727 </parent>
2828
1515 package org.apache.pdfbox.tools;
1616
1717 import java.io.File;
18 import java.io.IOException;
1819
1920 import org.apache.pdfbox.cos.COSName;
2021 import org.apache.pdfbox.cos.COSObject;
9495 }
9596 doc.save(outputFilename);
9697 }
97 catch(Exception e)
98 catch (IOException e)
9899 {
99100 System.err.println("Error processing file: " + e.getMessage());
100101 }
6666 COSName.DCT_DECODE.getName(),
6767 COSName.DCT_DECODE_ABBREVIATION.getName());
6868
69 private boolean directJPEG;
70 private String prefix;
69 private boolean useDirectJPEG;
70 private String filePrefix;
7171
7272 private final Set<COSStream> seen = new HashSet<COSStream>();
7373 private int imageCounter = 1;
120120 {
121121 usage();
122122 }
123 prefix = args[i];
123 filePrefix = args[i];
124124 }
125125 else if (args[i].equals(DIRECTJPEG))
126126 {
127 directJPEG = true;
127 useDirectJPEG = true;
128128 }
129129 else
130130 {
140140 }
141141 else
142142 {
143 if (prefix == null && pdfFile.length() >4)
144 {
145 prefix = pdfFile.substring(0, pdfFile.length() -4);
143 if (filePrefix == null && pdfFile.length() > 4)
144 {
145 filePrefix = pdfFile.substring(0, pdfFile.length() - 4);
146146 }
147147
148148 extract(pdfFile, password);
206206 PDPage page = getPage();
207207 processPage(page);
208208 PDResources res = page.getResources();
209 if (res == null)
210 {
211 return;
212 }
209213 for (COSName name : res.getExtGStateNames())
210214 {
211215 PDSoftMask softMask = res.getExtGState(name).getSoftMask();
242246 }
243247
244248 // save image
245 String name = prefix + "-" + imageCounter;
249 String name = filePrefix + "-" + imageCounter;
246250 imageCounter++;
247251
248252 System.out.println("Writing image: " + name);
249 write2file(pdImage, name, directJPEG);
253 write2file(pdImage, name, useDirectJPEG);
250254 }
251255
252256 @Override
354358 }
355359 }
356360 }
357 }
358
359 private boolean hasMasks(PDImage pdImage) throws IOException
360 {
361 if (pdImage instanceof PDImageXObject)
362 {
363 PDImageXObject ximg = (PDImageXObject) pdImage;
364 return ximg.getMask() != null || ximg.getSoftMask() != null;
365 }
366 return false;
367361 }
368362
369363 /**
387381 suffix = "jp2";
388382 }
389383
384 if (hasMasks(pdImage))
385 {
386 // TIKA-3040, PDFBOX-4771: can't save ARGB as JPEG
387 suffix = "png";
388 }
389
390390 FileOutputStream out = null;
391391 try
392392 {
393393 out = new FileOutputStream(prefix + "." + suffix);
394 BufferedImage image = pdImage.getImage();
395 if (image != null)
396 {
397 if ("jpg".equals(suffix))
398 {
399 String colorSpaceName = pdImage.getColorSpace().getName();
400 if (directJPEG ||
401 !hasMasks(pdImage) &&
402 (PDDeviceGray.INSTANCE.getName().equals(colorSpaceName) ||
403 PDDeviceRGB.INSTANCE.getName().equals(colorSpaceName)))
404 {
405 // RGB or Gray colorspace: get and write the unmodified JPEG stream
406 InputStream data = pdImage.createInputStream(JPEG);
407 IOUtils.copy(data, out);
408 IOUtils.closeQuietly(data);
409 }
410 else
411 {
412 // for CMYK and other "unusual" colorspaces, the JPEG will be converted
394 if ("jpg".equals(suffix))
395 {
396 String colorSpaceName = pdImage.getColorSpace().getName();
397 if (directJPEG ||
398 (PDDeviceGray.INSTANCE.getName().equals(colorSpaceName) ||
399 PDDeviceRGB.INSTANCE.getName().equals(colorSpaceName)))
400 {
401 // RGB or Gray colorspace: get and write the unmodified JPEG stream
402 InputStream data = pdImage.createInputStream(JPEG);
403 IOUtils.copy(data, out);
404 IOUtils.closeQuietly(data);
405 }
406 else
407 {
408 // for CMYK and other "unusual" colorspaces, the JPEG will be converted
409 BufferedImage image = pdImage.getImage();
410 if (image != null)
411 {
413412 ImageIOUtil.writeImage(image, suffix, out);
414413 }
415414 }
416 else if ("jp2".equals(suffix))
417 {
418 String colorSpaceName = pdImage.getColorSpace().getName();
419 if (directJPEG ||
420 !hasMasks(pdImage) &&
421 (PDDeviceGray.INSTANCE.getName().equals(colorSpaceName) ||
422 PDDeviceRGB.INSTANCE.getName().equals(colorSpaceName)))
423 {
424 // RGB or Gray colorspace: get and write the unmodified JPEG2000 stream
425 InputStream data = pdImage.createInputStream(
426 Arrays.asList(COSName.JPX_DECODE.getName()));
427 IOUtils.copy(data, out);
428 IOUtils.closeQuietly(data);
429 }
430 else
431 {
432 // for CMYK and other "unusual" colorspaces, the image will be converted
415 }
416 else if ("jp2".equals(suffix))
417 {
418 String colorSpaceName = pdImage.getColorSpace().getName();
419 if (directJPEG ||
420 (PDDeviceGray.INSTANCE.getName().equals(colorSpaceName) ||
421 PDDeviceRGB.INSTANCE.getName().equals(colorSpaceName)))
422 {
423 // RGB or Gray colorspace: get and write the unmodified JPEG2000 stream
424 InputStream data = pdImage.createInputStream(
425 Arrays.asList(COSName.JPX_DECODE.getName()));
426 IOUtils.copy(data, out);
427 IOUtils.closeQuietly(data);
428 }
429 else
430 {
431 // for CMYK and other "unusual" colorspaces, the image will be converted
432 BufferedImage image = pdImage.getImage();
433 if (image != null)
434 {
433435 ImageIOUtil.writeImage(image, "jpeg2000", out);
434436 }
435437 }
436 else
438 }
439 else if ("tiff".equals(suffix) && pdImage.getColorSpace().equals(PDDeviceGray.INSTANCE))
440 {
441 BufferedImage image = pdImage.getImage();
442 if (image == null)
443 {
444 return;
445 }
446 // CCITT compressed images can have a different colorspace, but this one is B/W
447 // This is a bitonal image, so copy to TYPE_BYTE_BINARY
448 // so that a G4 compressed TIFF image is created by ImageIOUtil.writeImage()
449 int w = image.getWidth();
450 int h = image.getHeight();
451 BufferedImage bitonalImage = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_BINARY);
452 // copy image the old fashioned way - ColorConvertOp is slower!
453 for (int y = 0; y < h; y++)
454 {
455 for (int x = 0; x < w; x++)
456 {
457 bitonalImage.setRGB(x, y, image.getRGB(x, y));
458 }
459 }
460 ImageIOUtil.writeImage(bitonalImage, suffix, out);
461 }
462 else
463 {
464 BufferedImage image = pdImage.getImage();
465 if (image != null)
437466 {
438467 ImageIOUtil.writeImage(image, suffix, out);
439468 }
448477 }
449478 }
450479 }
480
481 private boolean hasMasks(PDImage pdImage) throws IOException
482 {
483 if (pdImage instanceof PDImageXObject)
484 {
485 PDImageXObject ximg = (PDImageXObject) pdImage;
486 return ximg.getMask() != null || ximg.getSoftMask() != null;
487 }
488 return false;
489 }
451490 }
7070 /*
7171 * debug flag
7272 */
73 private boolean debug = false;
73 private boolean debugOutput = false;
7474
7575 /**
7676 * private constructor.
170170 }
171171 else if( args[i].equals( DEBUG ) )
172172 {
173 debug = true;
173 debugOutput = true;
174174 }
175175 else if( args[i].equals( END_PAGE ) )
176176 {
238238 output = new OutputStreamWriter( new FileOutputStream( outputFile ), encoding );
239239 }
240240 startTime = startProcessing("Starting text extraction");
241 if (debug)
241 if (debugOutput)
242242 {
243243 System.err.println("Writing to " + outputFile);
244244 }
287287 {
288288 for (Map.Entry<String, PDComplexFileSpecification> ent : embeddedFileNames.entrySet())
289289 {
290 if (debug)
290 if (debugOutput)
291291 {
292292 System.err.println("Processing embedded file " + ent.getKey() + ":");
293293 }
295295 PDEmbeddedFile file = spec.getEmbeddedFile();
296296 if (file != null && "application/pdf".equals(file.getSubtype()))
297297 {
298 if (debug)
298 if (debugOutput)
299299 {
300300 System.err.println(" is PDF (size=" + file.getSize() + ")");
301301 }
389389
390390 private long startProcessing(String message)
391391 {
392 if (debug)
392 if (debugOutput)
393393 {
394394 System.err.println(message);
395395 }
398398
399399 private void stopProcessing(String message, long startTime)
400400 {
401 if (debug)
401 if (debugOutput)
402402 {
403403 long stopTime = System.currentTimeMillis();
404404 float elapsedTime = ((float)(stopTime - startTime))/1000;
269269 int count = 1 + endPage - startPage;
270270 if (showTime)
271271 {
272 System.err.printf("Rendered %d page%s in %dms\n", count, count == 1 ? "" : "s",
272 System.err.printf("Rendered %d page%s in %dms%n", count, count == 1 ? "" : "s",
273273 duration / 1000000);
274274 }
275275
9595 }
9696 }
9797 doc.getDocumentCatalog();
98 doc.getDocument().setIsXRefStream(false);
9899 doc.save( out );
99100 }
100101 finally
2626 <parent>
2727 <groupId>org.apache.pdfbox</groupId>
2828 <artifactId>pdfbox-parent</artifactId>
29 <version>2.0.18</version>
29 <version>2.0.19</version>
3030 <relativePath>../parent/pom.xml</relativePath>
3131 </parent>
3232