cleanup io-pdfbox

This commit is contained in:
Jörg Prante 2020-11-15 20:39:27 +01:00
parent b5dc5f1b98
commit 5f4adca5c0
24 changed files with 312 additions and 360 deletions

View file

@ -1,5 +1,10 @@
module org.xbib.graphics.graphics2d.pdfbox { module org.xbib.graphics.graphics2d.pdfbox {
exports org.xbib.graphics.io.pdfbox; exports org.xbib.graphics.io.pdfbox;
exports org.xbib.graphics.io.pdfbox.color;
exports org.xbib.graphics.io.pdfbox.draw;
exports org.xbib.graphics.io.pdfbox.font;
exports org.xbib.graphics.io.pdfbox.image;
exports org.xbib.graphics.io.pdfbox.paint;
requires transitive org.apache.pdfbox; requires transitive org.apache.pdfbox;
requires org.apache.fontbox; requires org.apache.fontbox;
requires transitive java.desktop; requires transitive java.desktop;

View file

@ -1,8 +1,18 @@
package org.xbib.graphics.io.pdfbox; package org.xbib.graphics.io.pdfbox;
import org.xbib.graphics.io.pdfbox.DrawControl.DrawControlEnv; import org.xbib.graphics.io.pdfbox.draw.DefaultDrawControl;
import org.xbib.graphics.io.pdfbox.FontTextDrawer.FontTextDrawerEnv; import org.xbib.graphics.io.pdfbox.draw.DrawControl;
import org.xbib.graphics.io.pdfbox.PaintApplier.PaintApplierEnv; import org.xbib.graphics.io.pdfbox.draw.DrawControl.DrawControlEnvironment;
import org.xbib.graphics.io.pdfbox.color.ColorMapper;
import org.xbib.graphics.io.pdfbox.color.DefaultColorMapper;
import org.xbib.graphics.io.pdfbox.font.DefaultFontDrawer;
import org.xbib.graphics.io.pdfbox.font.FontDrawer;
import org.xbib.graphics.io.pdfbox.font.FontDrawer.FontDrawerEnvironment;
import org.xbib.graphics.io.pdfbox.image.ImageEncoder;
import org.xbib.graphics.io.pdfbox.image.LosslessImageEncoder;
import org.xbib.graphics.io.pdfbox.paint.DefaultPaintApplier;
import org.xbib.graphics.io.pdfbox.paint.PaintApplier;
import org.xbib.graphics.io.pdfbox.paint.PaintApplier.PaintApplierEnvironment;
import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.cos.COSStream;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
@ -74,23 +84,29 @@ public class PdfBoxGraphics2D extends Graphics2D {
private final PDPageContentStream contentStream; private final PDPageContentStream contentStream;
private BufferedImage calcImage; private final BufferedImage calcImage;
private PDDocument document; private final PDDocument document;
private final AffineTransform baseTransform; private final AffineTransform baseTransform;
private AffineTransform transform = new AffineTransform(); private final CopyInfo copyInfo;
private ImageEncoder imageEncoder = new LosslessImageEncoder(); private final List<CopyInfo> copyList;
private ColorMapper colorMapper = new DefaultColorMapper(); private final DefaultPaintApplierEnvironment paintEnv;
private PaintApplier paintApplier = new DefaultPaintApplier(); private AffineTransform transform;
private FontTextDrawer fontTextDrawer = new DefaultFontTextDrawer(); private ImageEncoder imageEncoder;
private DrawControl drawControl = DefaultDrawControl.INSTANCE; private ColorMapper colorMapper;
private PaintApplier paintApplier;
private FontDrawer fontDrawer;
private DrawControl drawControl;
private Paint paint; private Paint paint;
@ -106,13 +122,9 @@ public class PdfBoxGraphics2D extends Graphics2D {
private Color backgroundColor; private Color backgroundColor;
private int saveCounter = 0; private int saveCounter;
private final CopyInfo copyInfo; private boolean disposed;
private final List<CopyInfo> copyList = new ArrayList<>();
private final PaintApplierEnvImpl paintEnv = new PaintApplierEnvImpl();
/** /**
* Do we currently have an active path on the content stream, which has not been * Do we currently have an active path on the content stream, which has not been
@ -121,11 +133,11 @@ public class PdfBoxGraphics2D extends Graphics2D {
* clip and we have some clipping. If at the end we try to clip with an empty * clip and we have some clipping. If at the end we try to clip with an empty
* path, then Acrobat Reader does not like that and draws nothing. * path, then Acrobat Reader does not like that and draws nothing.
*/ */
private boolean hasPathOnStream = false; private boolean hasPathOnStream;
private Map<Key, Object> renderingHints = new HashMap<>(); private Map<Key, Object> renderingHints;
private final DrawControlEnv drawControlEnv = new DrawControlEnv() { private final DrawControlEnvironment drawControlEnvironment = new DrawControlEnvironment() {
@Override @Override
public Paint getPaint() { public Paint getPaint() {
return paint; return paint;
@ -137,7 +149,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
} }
}; };
private final FontTextDrawerEnv fontDrawerEnv = new FontTextDrawerEnv() { private final FontDrawerEnvironment fontDrawerEnv = new FontDrawerEnvironment() {
@Override @Override
public PDDocument getDocument() { public PDDocument getDocument() {
return document; return document;
@ -246,24 +258,8 @@ public class PdfBoxGraphics2D extends Graphics2D {
PDFormXObject xFormObject, PDFormXObject xFormObject,
PdfBoxGraphics2D parentGfx) PdfBoxGraphics2D parentGfx)
throws IOException { throws IOException {
this.document = document; this(document, xFormObject, new PDPageContentStream(document, xFormObject,
this.xFormObject = xFormObject; xFormObject.getStream().createOutputStream(COSName.FLATE_DECODE)), parentGfx);
this.contentStream = new PDPageContentStream(document, xFormObject,
xFormObject.getStream().createOutputStream(COSName.FLATE_DECODE));
contentStreamSaveState();
if (parentGfx != null) {
this.colorMapper = parentGfx.colorMapper;
this.fontTextDrawer = parentGfx.fontTextDrawer;
this.imageEncoder = parentGfx.imageEncoder;
this.paintApplier = parentGfx.paintApplier;
}
baseTransform = new AffineTransform();
baseTransform.translate(0, xFormObject.getBBox().getHeight());
baseTransform.scale(1, -1);
calcImage = new BufferedImage(100, 100, BufferedImage.TYPE_4BYTE_ABGR);
calcGfx = calcImage.createGraphics();
font = calcGfx.getFont();
copyInfo = null;
} }
public PdfBoxGraphics2D(PDDocument document, public PdfBoxGraphics2D(PDDocument document,
@ -277,7 +273,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
contentStreamSaveState(); contentStreamSaveState();
if (parentGfx != null) { if (parentGfx != null) {
this.colorMapper = parentGfx.colorMapper; this.colorMapper = parentGfx.colorMapper;
this.fontTextDrawer = parentGfx.fontTextDrawer; this.fontDrawer = parentGfx.fontDrawer;
this.imageEncoder = parentGfx.imageEncoder; this.imageEncoder = parentGfx.imageEncoder;
this.paintApplier = parentGfx.paintApplier; this.paintApplier = parentGfx.paintApplier;
} }
@ -288,6 +284,15 @@ public class PdfBoxGraphics2D extends Graphics2D {
calcGfx = calcImage.createGraphics(); calcGfx = calcImage.createGraphics();
font = calcGfx.getFont(); font = calcGfx.getFont();
copyInfo = null; copyInfo = null;
transform = new AffineTransform();
imageEncoder = new LosslessImageEncoder();
colorMapper = new DefaultColorMapper();
paintApplier = new DefaultPaintApplier();
fontDrawer = new DefaultFontDrawer();
drawControl = DefaultDrawControl.INSTANCE;
copyList = new ArrayList<>();
paintEnv = new DefaultPaintApplierEnvironment();
renderingHints = new HashMap<>();
} }
private PdfBoxGraphics2D(PdfBoxGraphics2D pdfBoxGraphics2D) throws IOException { private PdfBoxGraphics2D(PdfBoxGraphics2D pdfBoxGraphics2D) throws IOException {
@ -311,7 +316,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
this.clipShape = pdfBoxGraphics2D.clipShape; this.clipShape = pdfBoxGraphics2D.clipShape;
this.backgroundColor = pdfBoxGraphics2D.backgroundColor; this.backgroundColor = pdfBoxGraphics2D.backgroundColor;
this.colorMapper = pdfBoxGraphics2D.colorMapper; this.colorMapper = pdfBoxGraphics2D.colorMapper;
this.fontTextDrawer = pdfBoxGraphics2D.fontTextDrawer; this.fontDrawer = pdfBoxGraphics2D.fontDrawer;
this.imageEncoder = pdfBoxGraphics2D.imageEncoder; this.imageEncoder = pdfBoxGraphics2D.imageEncoder;
this.paintApplier = pdfBoxGraphics2D.paintApplier; this.paintApplier = pdfBoxGraphics2D.paintApplier;
this.drawControl = pdfBoxGraphics2D.drawControl; this.drawControl = pdfBoxGraphics2D.drawControl;
@ -319,6 +324,11 @@ public class PdfBoxGraphics2D extends Graphics2D {
this.renderingHints = new HashMap<>(pdfBoxGraphics2D.renderingHints); this.renderingHints = new HashMap<>(pdfBoxGraphics2D.renderingHints);
this.xorColor = pdfBoxGraphics2D.xorColor; this.xorColor = pdfBoxGraphics2D.xorColor;
this.saveCounter = 0; this.saveCounter = 0;
this.copyList = new ArrayList<>();
this.disposed = false;
this.paintEnv = pdfBoxGraphics2D.paintEnv;
this.hasPathOnStream = pdfBoxGraphics2D.hasPathOnStream;
this.renderingHints = pdfBoxGraphics2D.renderingHints;
contentStreamSaveState(); contentStreamSaveState();
} }
@ -346,10 +356,9 @@ public class PdfBoxGraphics2D extends Graphics2D {
if (this.saveCounter != 0) { if (this.saveCounter != 0) {
throw new IllegalStateException("SaveCounter should be 0, but is " + this.saveCounter); throw new IllegalStateException("SaveCounter should be 0, but is " + this.saveCounter);
} }
document = null;
calcGfx.dispose(); calcGfx.dispose();
calcImage.flush(); calcImage.flush();
calcImage = null; disposed = true;
} }
@Override @Override
@ -360,7 +369,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
} }
try { try {
contentStreamSaveState(); contentStreamSaveState();
Shape shapeToDraw = drawControl.transformShapeBeforeDraw(s, drawControlEnv); Shape shapeToDraw = drawControl.transformShapeBeforeDraw(s, drawControlEnvironment);
if (shapeToDraw != null) { if (shapeToDraw != null) {
walkShape(shapeToDraw); walkShape(shapeToDraw);
PDShading pdShading = applyPaint(shapeToDraw); PDShading pdShading = applyPaint(shapeToDraw);
@ -391,7 +400,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
contentStream.stroke(); contentStream.stroke();
hasPathOnStream = false; hasPathOnStream = false;
} }
drawControl.afterShapeDraw(s, drawControlEnv); drawControl.afterShapeDraw(s, drawControlEnvironment);
contentStreamRestoreState(); contentStreamRestoreState();
} catch (IOException e) { } catch (IOException e) {
throw new PdfBoxGraphics2dException(e); throw new PdfBoxGraphics2dException(e);
@ -538,7 +547,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
} }
try { try {
contentStreamSaveState(); contentStreamSaveState();
if (fontTextDrawer.canDrawText((AttributedCharacterIterator) iterator.clone(), fontDrawerEnv)) { if (fontDrawer.canDrawText((AttributedCharacterIterator) iterator.clone(), fontDrawerEnv)) {
drawStringUsingText(iterator, x, y); drawStringUsingText(iterator, x, y);
} else { } else {
drawStringUsingShapes(iterator, x, y); drawStringUsingShapes(iterator, x, y);
@ -566,7 +575,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
} }
try { try {
contentStreamSaveState(); contentStreamSaveState();
Shape shapeToFill = drawControl.transformShapeBeforeFill(s, drawControlEnv); Shape shapeToFill = drawControl.transformShapeBeforeFill(s, drawControlEnvironment);
if (shapeToFill != null) { if (shapeToFill != null) {
boolean useEvenOdd = walkShape(shapeToFill); boolean useEvenOdd = walkShape(shapeToFill);
PDShading shading = applyPaint(shapeToFill); PDShading shading = applyPaint(shapeToFill);
@ -584,7 +593,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
} }
hasPathOnStream = false; hasPathOnStream = false;
} }
drawControl.afterShapeFill(s, drawControlEnv); drawControl.afterShapeFill(s, drawControlEnvironment);
contentStreamRestoreState(); contentStreamRestoreState();
} catch (IOException e) { } catch (IOException e) {
throw new PdfBoxGraphics2dException(e); throw new PdfBoxGraphics2dException(e);
@ -717,7 +726,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
@Override @Override
public FontMetrics getFontMetrics(Font f) { public FontMetrics getFontMetrics(Font f) {
try { try {
return fontTextDrawer.getFontMetrics(f, fontDrawerEnv); return fontDrawer.getFontMetrics(f, fontDrawerEnv);
} catch (IOException | FontFormatException e) { } catch (IOException | FontFormatException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -934,32 +943,12 @@ public class PdfBoxGraphics2D extends Graphics2D {
* @return the PDAppearanceStream which resulted in this graphics * @return the PDAppearanceStream which resulted in this graphics
*/ */
public PDFormXObject getXFormObject() { public PDFormXObject getXFormObject() {
if (document != null) { if (!disposed) {
throw new IllegalStateException("You can only get the XformObject after you disposed the Graphics2D!"); throw new IllegalStateException("You can only get the XFormObject after you disposed the Graphics2D object");
}
if (copyInfo != null) {
throw new IllegalStateException("You can not get the Xform stream from the copy");
} }
return xFormObject; return xFormObject;
} }
/**
* Sometimes the users of {@link #create()} don't correctly {@link #dispose()}
* the child graphics they create. And you may not always be able to fix this
* uses, as it may be in some 3rdparty library. In this case this method can
* help you. It will cleanup all dangling child graphics. The child graphics can
* not be used after that. This method is a workaround for a buggy old code. You
* should only use it if you have to.
* Note: You can only call this method on the "main" graphics, not on a child
* created with {@link #create()}
*/
public void disposeDanglingChildGraphics() {
if (copyInfo != null)
throw new IllegalStateException(
"Don't call disposeDanglingChildGraphics() on a child!");
disposeCopies(copyList);
}
/** /**
* Set a new color mapper. * Set a new color mapper.
* *
@ -1011,10 +1000,10 @@ public class PdfBoxGraphics2D extends Graphics2D {
* also must perform the text layout. If it can not map the text or font * also must perform the text layout. If it can not map the text or font
* correctly, the font drawing falls back to vectoring the text. * correctly, the font drawing falls back to vectoring the text.
* *
* @param fontTextDrawer The text drawer, which can draw text using fonts * @param fontDrawer The text drawer, which can draw text using fonts
*/ */
public void setFontTextDrawer(FontTextDrawer fontTextDrawer) { public void setFontTextDrawer(FontDrawer fontDrawer) {
this.fontTextDrawer = fontTextDrawer; this.fontDrawer = fontDrawer;
} }
/** /**
@ -1022,7 +1011,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
* applyer to the content stream or by walkShape() - is on the content stream. * applyer to the content stream or by walkShape() - is on the content stream.
* We can then safely clip() if there is a path on the content stream. * We can then safely clip() if there is a path on the content stream.
*/ */
void markPathIsOnStream() { public void markPathIsOnStream() {
hasPathOnStream = true; hasPathOnStream = true;
} }
@ -1050,7 +1039,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
tf.concatenate(transform); tf.concatenate(transform);
tf.translate(x, y); tf.translate(x, y);
contentStream.transform(new Matrix(tf)); contentStream.transform(new Matrix(tf));
fontTextDrawer.drawText(iterator, fontDrawerEnv); fontDrawer.drawText(iterator, fontDrawerEnv);
contentStreamRestoreState(); contentStreamRestoreState();
} }
@ -1151,7 +1140,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
* *
* @param useEvenOdd true when we should use the evenOdd rule. * @param useEvenOdd true when we should use the evenOdd rule.
*/ */
void internalClip(boolean useEvenOdd) throws IOException { public void internalClip(boolean useEvenOdd) throws IOException {
if (hasPathOnStream) { if (hasPathOnStream) {
if (useEvenOdd) { if (useEvenOdd) {
contentStream.clipEvenOdd(); contentStream.clipEvenOdd();
@ -1226,7 +1215,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
} }
} }
private class PaintApplierEnvImpl implements PaintApplierEnv { private class DefaultPaintApplierEnvironment implements PaintApplierEnvironment {
private Shape shapeToDraw; private Shape shapeToDraw;

View file

@ -1,4 +1,4 @@
package org.xbib.graphics.io.pdfbox; package org.xbib.graphics.io.pdfbox.color;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor; import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;

View file

@ -1,4 +1,4 @@
package org.xbib.graphics.io.pdfbox; package org.xbib.graphics.io.pdfbox.color;
import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor; import org.apache.pdfbox.pdmodel.graphics.color.PDColor;

View file

@ -1,9 +1,10 @@
package org.xbib.graphics.io.pdfbox; package org.xbib.graphics.io.pdfbox.color;
import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor; import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceCMYK; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceCMYK;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
import org.xbib.graphics.io.pdfbox.paint.DefaultPaintApplier;
import java.awt.Color; import java.awt.Color;

View file

@ -1,10 +1,11 @@
package org.xbib.graphics.io.pdfbox; package org.xbib.graphics.io.pdfbox.color;
import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor; import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.color.PDICCBased; import org.apache.pdfbox.pdmodel.graphics.color.PDICCBased;
import org.xbib.graphics.io.pdfbox.color.DefaultColorMapper;
import java.awt.Color; import java.awt.Color;
import java.awt.color.ICC_ColorSpace; import java.awt.color.ICC_ColorSpace;

View file

@ -1,4 +1,4 @@
package org.xbib.graphics.io.pdfbox; package org.xbib.graphics.io.pdfbox.draw;
import java.awt.Shape; import java.awt.Shape;
@ -14,20 +14,20 @@ public class DefaultDrawControl implements DrawControl {
} }
@Override @Override
public Shape transformShapeBeforeFill(Shape shape, DrawControlEnv env) { public Shape transformShapeBeforeFill(Shape shape, DrawControlEnvironment env) {
return shape; return shape;
} }
@Override @Override
public Shape transformShapeBeforeDraw(Shape shape, DrawControlEnv env) { public Shape transformShapeBeforeDraw(Shape shape, DrawControlEnvironment env) {
return shape; return shape;
} }
@Override @Override
public void afterShapeFill(Shape shape, DrawControlEnv env) { public void afterShapeFill(Shape shape, DrawControlEnvironment env) {
} }
@Override @Override
public void afterShapeDraw(Shape shape, DrawControlEnv env) { public void afterShapeDraw(Shape shape, DrawControlEnvironment env) {
} }
} }

View file

@ -1,5 +1,6 @@
package org.xbib.graphics.io.pdfbox; package org.xbib.graphics.io.pdfbox.draw;
import org.xbib.graphics.io.pdfbox.PdfBoxGraphics2D;
import java.awt.Paint; import java.awt.Paint;
import java.awt.Shape; import java.awt.Shape;
@ -18,7 +19,7 @@ public interface DrawControl {
* @param env Environment * @param env Environment
* @return the shape to be filled. If you return null, nothing will be filled * @return the shape to be filled. If you return null, nothing will be filled
*/ */
Shape transformShapeBeforeFill(Shape shape, DrawControlEnv env); Shape transformShapeBeforeFill(Shape shape, DrawControlEnvironment env);
/** /**
* You may optional change the shape that is going to be drawn. You can also do * You may optional change the shape that is going to be drawn. You can also do
@ -28,36 +29,36 @@ public interface DrawControl {
* @param env Environment * @param env Environment
* @return the shape to be filled. If you return null, nothing will be drawn * @return the shape to be filled. If you return null, nothing will be drawn
*/ */
Shape transformShapeBeforeDraw(Shape shape, DrawControlEnv env); Shape transformShapeBeforeDraw(Shape shape, DrawControlEnvironment env);
/** /**
* Called after shape was filled. This method is always called, even if * Called after shape was filled. This method is always called, even if
* {@link #transformShapeBeforeFill(Shape, DrawControlEnv)} returns * {@link #transformShapeBeforeFill(Shape, DrawControlEnvironment)} returns
* null. * null.
* *
* @param shape the shape that was filled. This is the original shape, not the one * @param shape the shape that was filled. This is the original shape, not the one
* transformed by * transformed by
* {@link #transformShapeBeforeFill(Shape, DrawControlEnv)}. * {@link #transformShapeBeforeFill(Shape, DrawControlEnvironment)}.
* @param env Environment * @param env Environment
*/ */
void afterShapeFill(Shape shape, DrawControlEnv env); void afterShapeFill(Shape shape, DrawControlEnvironment env);
/** /**
* Called after shape was drawn. This method is always called, even if * Called after shape was drawn. This method is always called, even if
* {@link #transformShapeBeforeDraw(Shape, DrawControlEnv)} returns * {@link #transformShapeBeforeDraw(Shape, DrawControlEnvironment)} returns
* null. * null.
* *
* @param shape the shape that was drawn. This is the original shape, not the one * @param shape the shape that was drawn. This is the original shape, not the one
* transformed by * transformed by
* {@link #transformShapeBeforeDraw(Shape, DrawControlEnv)}. * {@link #transformShapeBeforeDraw(Shape, DrawControlEnvironment)}.
* @param env Environment * @param env Environment
*/ */
void afterShapeDraw(Shape shape, DrawControlEnv env); void afterShapeDraw(Shape shape, DrawControlEnvironment env);
/** /**
* The environment of the draw operation * The environment of the draw operation
*/ */
interface DrawControlEnv { interface DrawControlEnvironment {
/** /**
* @return the current paint set on the graphics. * @return the current paint set on the graphics.
*/ */

View file

@ -1,4 +1,4 @@
package org.xbib.graphics.io.pdfbox; package org.xbib.graphics.io.pdfbox.font;
import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDFont;
@ -7,17 +7,17 @@ import java.awt.FontFormatException;
import java.io.IOException; import java.io.IOException;
/** /**
* Like {@link DefaultFontTextDrawer}, but tries to use default fonts * Like {@link DefaultFontDrawer}, but tries to use core fonts
* whenever possible. Default fonts are not embedded. You can register * whenever possible. Default fonts are not embedded. You can register
* additional font files. If no font mapping is found, Helvetica is used. * additional font files. If no font mapping is found, Helvetica is used.
* This will fallback to vectorized text if any kind of RTL text is rendered * This will fallback to vectorized text if any kind of RTL text is rendered
* and/or any other not supported feature is used. * and/or any other not supported feature is used.
*/ */
public class DefaultFontTextDrawerFonts extends DefaultFontTextDrawer { public class CoreFontDrawer extends DefaultFontDrawer {
@Override @Override
protected PDFont mapFont(Font font, FontTextDrawerEnv env) throws IOException, FontFormatException { protected PDFont mapFont(Font font, FontDrawerEnvironment env) throws IOException, FontFormatException {
PDFont pdFont = mapDefaultFonts(font); PDFont pdFont = mapToCoreFonts(font);
if (pdFont != null) { if (pdFont != null) {
return pdFont; return pdFont;
} }

View file

@ -1,4 +1,4 @@
package org.xbib.graphics.io.pdfbox; package org.xbib.graphics.io.pdfbox.font;
import org.apache.fontbox.ttf.TrueTypeCollection; import org.apache.fontbox.ttf.TrueTypeCollection;
import org.apache.pdfbox.io.IOUtils; import org.apache.pdfbox.io.IOUtils;
@ -7,6 +7,7 @@ import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font; import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.Matrix;
import org.xbib.graphics.io.pdfbox.PdfBoxGraphics2D;
import java.awt.Font; import java.awt.Font;
import java.awt.FontFormatException; import java.awt.FontFormatException;
@ -33,9 +34,9 @@ import java.util.logging.Logger;
* Just ensure that you call close after you closed the PDDocument to free any * Just ensure that you call close after you closed the PDDocument to free any
* temporary files. * temporary files.
*/ */
public class DefaultFontTextDrawer implements FontTextDrawer, Closeable { public class DefaultFontDrawer implements FontDrawer, Closeable {
private static final Logger logger = Logger.getLogger(DefaultFontTextDrawer.class.getName()); private static final Logger logger = Logger.getLogger(DefaultFontDrawer.class.getName());
@Override @Override
public void close() { public void close() {
@ -141,54 +142,44 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable {
* the case if this class has been derived. The default implementation * the case if this class has been derived. The default implementation
* just checks for this. * just checks for this.
*/ */
@SuppressWarnings("WeakerAccess")
protected boolean hasDynamicFontMapping() { protected boolean hasDynamicFontMapping() {
return getClass() != DefaultFontTextDrawer.class; return getClass() != DefaultFontDrawer.class;
} }
@Override @Override
public boolean canDrawText(AttributedCharacterIterator iterator, FontTextDrawerEnv env) public boolean canDrawText(AttributedCharacterIterator iterator, FontDrawerEnvironment env)
throws IOException, FontFormatException { throws IOException, FontFormatException {
/* if (fontMap.size() == 0 && fontFiles.size() == 0 && !hasDynamicFontMapping()) {
* When no font is registered we can not display the text using a font...
*/
if (fontMap.size() == 0 && fontFiles.size() == 0 && !hasDynamicFontMapping())
return false; return false;
}
boolean run = true; boolean run = true;
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
while (run) { while (run) {
Font attributeFont = (Font) iterator.getAttribute(TextAttribute.FONT); Font attributeFont = (Font) iterator.getAttribute(TextAttribute.FONT);
if (attributeFont == null) if (attributeFont == null) {
attributeFont = env.getFont(); attributeFont = env.getFont();
if (mapFont(attributeFont, env) == null) }
if (mapFont(attributeFont, env) == null) {
return false; return false;
}
/* if (iterator.getAttribute(TextAttribute.BACKGROUND) != null) {
* We can not do a Background on the text currently.
*/
if (iterator.getAttribute(TextAttribute.BACKGROUND) != null)
return false; return false;
}
boolean isStrikeThrough = TextAttribute.STRIKETHROUGH_ON boolean isStrikeThrough =
.equals(iterator.getAttribute(TextAttribute.STRIKETHROUGH)); TextAttribute.STRIKETHROUGH_ON.equals(iterator.getAttribute(TextAttribute.STRIKETHROUGH));
boolean isUnderline = TextAttribute.UNDERLINE_ON boolean isUnderline =
.equals(iterator.getAttribute(TextAttribute.UNDERLINE)); TextAttribute.UNDERLINE_ON.equals(iterator.getAttribute(TextAttribute.UNDERLINE));
boolean isLigatures = TextAttribute.LIGATURES_ON boolean isLigatures =
.equals(iterator.getAttribute(TextAttribute.LIGATURES)); TextAttribute.LIGATURES_ON.equals(iterator.getAttribute(TextAttribute.LIGATURES));
if (isStrikeThrough || isUnderline || isLigatures) if (isStrikeThrough || isUnderline || isLigatures) {
return false; return false;
}
run = iterateRun(iterator, sb); run = iterateRun(iterator, sb);
String s = sb.toString(); String s = sb.toString();
int l = s.length(); int l = s.length();
for (int i = 0; i < l; ) { for (int i = 0; i < l; ) {
int codePoint = s.codePointAt(i); int codePoint = s.codePointAt(i);
switch (Character.getDirectionality(codePoint)) { switch (Character.getDirectionality(codePoint)) {
/*
* We can handle normal LTR.
*/
case Character.DIRECTIONALITY_LEFT_TO_RIGHT: case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
case Character.DIRECTIONALITY_EUROPEAN_NUMBER: case Character.DIRECTIONALITY_EUROPEAN_NUMBER:
case Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR: case Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR:
@ -207,20 +198,13 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable {
case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING: case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE: case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
case Character.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT: case Character.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT:
/*
* We can not handle this
*/
return false; return false;
default: default:
/*
* Default: We can not handle this
*/
return false; return false;
} }
if (!attributeFont.canDisplay(codePoint)) {
if (!attributeFont.canDisplay(codePoint))
return false; return false;
}
i += Character.charCount(codePoint); i += Character.charCount(codePoint);
} }
} }
@ -228,7 +212,7 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable {
} }
@Override @Override
public void drawText(AttributedCharacterIterator iterator, FontTextDrawerEnv env) public void drawText(AttributedCharacterIterator iterator, FontDrawerEnvironment env)
throws IOException, FontFormatException { throws IOException, FontFormatException {
PDPageContentStream contentStream = env.getContentStream(); PDPageContentStream contentStream = env.getContentStream();
@ -241,52 +225,37 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
boolean run = true; boolean run = true;
while (run) { while (run) {
Font attributeFont = (Font) iterator.getAttribute(TextAttribute.FONT); Font attributeFont = (Font) iterator.getAttribute(TextAttribute.FONT);
if (attributeFont == null) if (attributeFont == null) {
attributeFont = env.getFont(); attributeFont = env.getFont();
}
Number fontSize = ((Number) iterator.getAttribute(TextAttribute.SIZE)); Number fontSize = ((Number) iterator.getAttribute(TextAttribute.SIZE));
if (fontSize != null) if (fontSize != null) {
attributeFont = attributeFont.deriveFont(fontSize.floatValue()); attributeFont = attributeFont.deriveFont(fontSize.floatValue());
}
PDFont font = applyFont(attributeFont, env); PDFont font = applyFont(attributeFont, env);
Paint paint = (Paint) iterator.getAttribute(TextAttribute.FOREGROUND); Paint paint = (Paint) iterator.getAttribute(TextAttribute.FOREGROUND);
if (paint == null) if (paint == null) {
paint = env.getPaint(); paint = env.getPaint();
}
boolean isStrikeThrough = TextAttribute.STRIKETHROUGH_ON boolean isStrikeThrough =
.equals(iterator.getAttribute(TextAttribute.STRIKETHROUGH)); TextAttribute.STRIKETHROUGH_ON.equals(iterator.getAttribute(TextAttribute.STRIKETHROUGH));
boolean isUnderline = TextAttribute.UNDERLINE_ON boolean isUnderline =
.equals(iterator.getAttribute(TextAttribute.UNDERLINE)); TextAttribute.UNDERLINE_ON.equals(iterator.getAttribute(TextAttribute.UNDERLINE));
boolean isLigatures = TextAttribute.LIGATURES_ON boolean isLigatures =
.equals(iterator.getAttribute(TextAttribute.LIGATURES)); TextAttribute.LIGATURES_ON.equals(iterator.getAttribute(TextAttribute.LIGATURES));
run = iterateRun(iterator, sb); run = iterateRun(iterator, sb);
String text = sb.toString(); String text = sb.toString();
/*
* Apply the paint
*/
env.applyPaint(paint, null); env.applyPaint(paint, null);
/*
* If we force the text write we may encounter situations where the font can not
* display the characters. PDFBox will throw an exception in this case. We will
* just silently ignore the text and not display it instead.
*/
try { try {
showTextOnStream(env, contentStream, attributeFont, font, isStrikeThrough, showTextOnStream(env, contentStream, attributeFont, font, isStrikeThrough,
isUnderline, isLigatures, text); isUnderline, isLigatures, text);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
if (font instanceof PDType1Font && !font.isEmbedded()) { if (font instanceof PDType1Font && !font.isEmbedded()) {
/*
* We tried to use a builtin default font, but it does not have the needed
* characters. So we use a embedded font as fallback.
*/
try { try {
if (fallbackFontUnknownEncodings == null) if (fallbackFontUnknownEncodings == null) {
fallbackFontUnknownEncodings = findFallbackFont(env); fallbackFontUnknownEncodings = findFallbackFont(env);
}
if (fallbackFontUnknownEncodings != null) { if (fallbackFontUnknownEncodings != null) {
env.getContentStream().setFont(fallbackFontUnknownEncodings, env.getContentStream().setFont(fallbackFontUnknownEncodings,
attributeFont.getSize2D()); attributeFont.getSize2D());
@ -299,48 +268,35 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable {
e = e1; e = e1;
} }
} }
if (e != null) {
if (e != null)
logger.log(Level.WARNING, "PDFBoxGraphics: Can not map text " + text + " with font " logger.log(Level.WARNING, "PDFBoxGraphics: Can not map text " + text + " with font "
+ attributeFont.getFontName() + ": " + e.getMessage()); + attributeFont.getFontName() + ": " + e.getMessage());
} }
} }
}
contentStream.endText(); contentStream.endText();
} }
@Override @Override
public FontMetrics getFontMetrics(final Font f, FontTextDrawerEnv env) public FontMetrics getFontMetrics(Font f, FontDrawerEnvironment env)
throws IOException, FontFormatException { throws IOException, FontFormatException {
final FontMetrics defaultMetrics = env.getCalculationGraphics().getFontMetrics(f); final FontMetrics fontMetrics = env.getCalculationGraphics().getFontMetrics(f);
final PDFont pdFont = mapFont(f, env); final PDFont pdFont = mapFont(f, env);
/*
* By default we delegate to the buffered image based calculation. This is wrong
* as soon as we use the native PDF Box font, as those have sometimes different widths.
*
* But it is correct and fine as long as we use vector shapes.
*/
if (pdFont == null) { if (pdFont == null) {
return defaultMetrics; return fontMetrics;
} }
return new DefaultFontMetrics(f, defaultMetrics, pdFont); return new DefaultFontMetrics(f, fontMetrics, pdFont);
} }
private PDFont fallbackFontUnknownEncodings; private PDFont fallbackFontUnknownEncodings;
private PDFont findFallbackFont(FontTextDrawerEnv env) throws IOException { private PDFont findFallbackFont(FontDrawerEnvironment env) {
/*
* We search for the right font in the folders... We try to use
* LucidaSansRegular and if not found Arial, because this fonts often exists. We
* use the Java default font as fallback.
*
* Normally this method is only used and called if a default font misses some
* special characters, e.g. Hebrew or Arabic characters.
*/
String javaHome = System.getProperty("java.home", "."); String javaHome = System.getProperty("java.home", ".");
String javaFontDir = javaHome + "/lib/fonts"; String javaFontDir = javaHome + "/lib/fonts";
String windir = System.getenv("WINDIR"); String windir = System.getenv("WINDIR");
if (windir == null) if (windir == null) {
windir = javaFontDir; windir = javaFontDir;
}
File[] paths = new File[]{new File(new File(windir), "fonts"), File[] paths = new File[]{new File(new File(windir), "fonts"),
new File(System.getProperty("user.dir", ".")), new File(System.getProperty("user.dir", ".")),
// Mac Fonts // Mac Fonts
@ -357,24 +313,26 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable {
if (arialFile.exists()) { if (arialFile.exists()) {
// We try to use the first font we can find and use. // We try to use the first font we can find and use.
PDType0Font pdType0Font = tryToLoadFont(env, arialFile); PDType0Font pdType0Font = tryToLoadFont(env, arialFile);
if (pdType0Font != null) if (pdType0Font != null) {
return pdType0Font; return pdType0Font;
} }
} }
} }
}
return null; return null;
} }
private PDType0Font tryToLoadFont(FontTextDrawerEnv env, File foundFontFile) { private PDType0Font tryToLoadFont(FontDrawerEnvironment env, File foundFontFile) {
try { try {
return PDType0Font.load(env.getDocument(), foundFontFile); return PDType0Font.load(env.getDocument(), foundFontFile);
} catch (IOException e) { } catch (IOException e) {
logger.log(Level.WARNING, e.getMessage(), e);
// The font may be have a embed restriction. // The font may be have a embed restriction.
return null; return null;
} }
} }
private void showTextOnStream(FontTextDrawerEnv env, private void showTextOnStream(FontDrawerEnvironment env,
PDPageContentStream contentStream, PDPageContentStream contentStream,
Font attributeFont, Font attributeFont,
PDFont font, PDFont font,
@ -385,11 +343,11 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable {
contentStream.showText(text); contentStream.showText(text);
} }
private PDFont applyFont(Font font, FontTextDrawerEnv env) private PDFont applyFont(Font font, FontDrawerEnvironment env)
throws IOException, FontFormatException { throws IOException, FontFormatException {
PDFont fontToUse = mapFont(font, env); PDFont fontToUse = mapFont(font, env);
if (fontToUse == null) { if (fontToUse == null) {
fontToUse = DefaultFontTextDrawerFonts.chooseMatchingHelvetica(font); fontToUse = CoreFontDrawer.chooseMatchingHelvetica(font);
} }
env.getContentStream().setFont(fontToUse, font.getSize2D()); env.getContentStream().setFont(fontToUse, font.getSize2D());
return fontToUse; return fontToUse;
@ -404,13 +362,9 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable {
* @throws IOException when the font can not be loaded * @throws IOException when the font can not be loaded
* @throws FontFormatException when the font file can not be loaded * @throws FontFormatException when the font file can not be loaded
*/ */
@SuppressWarnings("WeakerAccess") protected PDFont mapFont(Font font, FontDrawerEnvironment env)
protected PDFont mapFont(final Font font, final FontTextDrawerEnv env)
throws IOException, FontFormatException { throws IOException, FontFormatException {
/* for (FontEntry fontEntry : fontFiles) {
* If we have any font registering's, we must perform them now
*/
for (final FontEntry fontEntry : fontFiles) {
if (fontEntry.overrideName == null) { if (fontEntry.overrideName == null) {
Font javaFont = Font.createFont(Font.TRUETYPE_FONT, fontEntry.file); Font javaFont = Font.createFont(Font.TRUETYPE_FONT, fontEntry.file);
fontEntry.overrideName = javaFont.getFontName(); fontEntry.overrideName = javaFont.getFontName();
@ -447,13 +401,12 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable {
} }
/** /**
* Find a PDFont for the given font object, which does not need to be embedded. * Find a PDFont for the given font object.
* * @param font font for which to find a suitable core font
* @param font font for which to find a suitable default font * @return null if no core font is found or a core font which does not
* @return null if no default font is found or a default font which does not
* need to be embedded. * need to be embedded.
*/ */
protected static PDFont mapDefaultFonts(Font font) { protected static PDFont mapToCoreFonts(Font font) {
if (fontNameEqualsAnyOf(font, Font.SANS_SERIF, Font.DIALOG, Font.DIALOG_INPUT, "Arial", "Helvetica")) { if (fontNameEqualsAnyOf(font, Font.SANS_SERIF, Font.DIALOG, Font.DIALOG_INPUT, "Arial", "Helvetica")) {
return chooseMatchingHelvetica(font); return chooseMatchingHelvetica(font);
} }

View file

@ -1,4 +1,4 @@
package org.xbib.graphics.io.pdfbox; package org.xbib.graphics.io.pdfbox.font;
import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDFont;
import java.awt.Font; import java.awt.Font;
@ -151,9 +151,6 @@ public class DefaultFontMetrics extends FontMetrics {
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
/*
* We let unknown chars be handled with
*/
return defaultMetrics.stringWidth(str); return defaultMetrics.stringWidth(str);
} }
} }

View file

@ -1,9 +1,10 @@
package org.xbib.graphics.io.pdfbox; package org.xbib.graphics.io.pdfbox.font;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.xbib.graphics.io.pdfbox.PdfBoxGraphics2D;
import java.awt.Font; import java.awt.Font;
import java.awt.FontFormatException; import java.awt.FontFormatException;
@ -16,9 +17,9 @@ import java.io.IOException;
import java.text.AttributedCharacterIterator; import java.text.AttributedCharacterIterator;
/** /**
* Draw text using Fonts * Draw text using fonts.
*/ */
public interface FontTextDrawer { public interface FontDrawer {
/** /**
* @param iterator Has the text and all its properties * @param iterator Has the text and all its properties
@ -28,7 +29,7 @@ public interface FontTextDrawer {
* @throws IOException when a font can not be loaded or a paint can't be applied. * @throws IOException when a font can not be loaded or a paint can't be applied.
* @throws FontFormatException when the font file can not be loaded * @throws FontFormatException when the font file can not be loaded
*/ */
boolean canDrawText(AttributedCharacterIterator iterator, FontTextDrawerEnv env) boolean canDrawText(AttributedCharacterIterator iterator, FontDrawerEnvironment env)
throws IOException, FontFormatException; throws IOException, FontFormatException;
/** /**
@ -37,16 +38,16 @@ public interface FontTextDrawer {
* @throws IOException when a font can not be loaded or a paint can't be applied. * @throws IOException when a font can not be loaded or a paint can't be applied.
* @throws FontFormatException when the font file can not be loaded * @throws FontFormatException when the font file can not be loaded
*/ */
void drawText(AttributedCharacterIterator iterator, FontTextDrawerEnv env) void drawText(AttributedCharacterIterator iterator, FontDrawerEnvironment env)
throws IOException, FontFormatException; throws IOException, FontFormatException;
FontMetrics getFontMetrics(Font f, FontTextDrawerEnv env) FontMetrics getFontMetrics(Font f, FontDrawerEnvironment env)
throws IOException, FontFormatException; throws IOException, FontFormatException;
/** /**
* Enviroment for font based drawing of text * Environment for font based drawing of text
*/ */
interface FontTextDrawerEnv { interface FontDrawerEnvironment {
/** /**
* @return the document we are writing to * @return the document we are writing to
*/ */

View file

@ -1,14 +1,14 @@
package org.xbib.graphics.io.pdfbox; package org.xbib.graphics.io.pdfbox.font;
import java.text.AttributedCharacterIterator; import java.text.AttributedCharacterIterator;
/** /**
* Always draw using text, even if we know that we can not map the text correctly. * Always draw using text, even if we know that we can not map the text correctly.
*/ */
public class DefaultFontTextDrawerForce extends DefaultFontTextDrawerFonts { public class ForcedFontDrawer extends CoreFontDrawer {
@Override @Override
public boolean canDrawText(AttributedCharacterIterator iterator, FontTextDrawerEnv env) { public boolean canDrawText(AttributedCharacterIterator iterator, FontDrawerEnvironment env) {
return true; return true;
} }
} }

View file

@ -1,4 +1,4 @@
package org.xbib.graphics.io.pdfbox; package org.xbib.graphics.io.pdfbox.image;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDPageContentStream;

View file

@ -1,4 +1,4 @@
package org.xbib.graphics.io.pdfbox; package org.xbib.graphics.io.pdfbox.image;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDPageContentStream;
@ -42,11 +42,11 @@ public class LosslessImageEncoder implements ImageEncoder {
int height = image.getHeight(null); int height = image.getHeight(null);
bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR); bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
Graphics graphics = bi.getGraphics(); Graphics graphics = bi.getGraphics();
if (!graphics.drawImage(image, 0, 0, null, null)) if (!graphics.drawImage(image, 0, 0, null, null)) {
throw new IllegalStateException("Not fully loaded images are not supported."); throw new IllegalStateException("Not fully loaded images are not supported");
}
graphics.dispose(); graphics.dispose();
} }
try { try {
if (doc == null || doc.get() != document) { if (doc == null || doc.get() != document) {
imageMap = new HashMap<>(); imageMap = new HashMap<>();
@ -76,7 +76,6 @@ public class LosslessImageEncoder implements ImageEncoder {
} }
imageMap.put(new ImageSoftReference(image), new SoftReference<>(imageXObject)); imageMap.put(new ImageSoftReference(image), new SoftReference<>(imageXObject));
} }
return imageXObject; return imageXObject;
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Could not encode Image", e); throw new RuntimeException("Could not encode Image", e);
@ -93,6 +92,9 @@ public class LosslessImageEncoder implements ImageEncoder {
if (obj == null) { if (obj == null) {
return false; return false;
} }
if (!(obj instanceof ImageSoftReference)) {
return false;
}
return ((ImageSoftReference) obj).get() == get(); return ((ImageSoftReference) obj).get() == get();
} }
@ -116,6 +118,9 @@ public class LosslessImageEncoder implements ImageEncoder {
if (obj == null) { if (obj == null) {
return false; return false;
} }
if (!(obj instanceof ProfileSoftReference)) {
return false;
}
return ((ProfileSoftReference) obj).get() == get(); return ((ProfileSoftReference) obj).get() == get();
} }

View file

@ -1,4 +1,4 @@
package org.xbib.graphics.io.pdfbox; package org.xbib.graphics.io.pdfbox.paint;
import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSBase;
@ -26,6 +26,9 @@ import org.apache.pdfbox.pdmodel.graphics.shading.ShadingPaint;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState; import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.Matrix;
import org.xbib.graphics.io.pdfbox.image.ImageEncoder;
import org.xbib.graphics.io.pdfbox.PdfBoxGraphics2D;
import org.xbib.graphics.io.pdfbox.color.ColorMapper;
import java.awt.AlphaComposite; import java.awt.AlphaComposite;
import java.awt.Color; import java.awt.Color;
@ -63,7 +66,7 @@ public class DefaultPaintApplier implements PaintApplier {
@Override @Override
public PDShading applyPaint(Paint paint, PDPageContentStream contentStream, AffineTransform tf, public PDShading applyPaint(Paint paint, PDPageContentStream contentStream, AffineTransform tf,
PaintApplierEnv env) throws IOException { PaintApplierEnvironment env) throws IOException {
PaintApplierState state = new PaintApplierState(); PaintApplierState state = new PaintApplierState();
state.document = env.getDocument(); state.document = env.getDocument();
state.resources = env.getResources(); state.resources = env.getResources();
@ -72,8 +75,8 @@ public class DefaultPaintApplier implements PaintApplier {
state.imageEncoder = env.getImageEncoder(); state.imageEncoder = env.getImageEncoder();
state.composite = env.getComposite(); state.composite = env.getComposite();
state.pdExtendedGraphicsState = null; state.pdExtendedGraphicsState = null;
state.env = env; state.paintApplierEnvironment = env;
state.tf = tf; state.affineTransform = tf;
state.nestedTransform = null; state.nestedTransform = null;
PDShading shading = applyPaint(paint, state); PDShading shading = applyPaint(paint, state);
if (state.pdExtendedGraphicsState != null) { if (state.pdExtendedGraphicsState != null) {
@ -155,10 +158,10 @@ public class DefaultPaintApplier implements PaintApplier {
AffineTransform patternTransform = new AffineTransform(); AffineTransform patternTransform = new AffineTransform();
if (paintPatternTransform != null) { if (paintPatternTransform != null) {
paintPatternTransform = new AffineTransform(paintPatternTransform); paintPatternTransform = new AffineTransform(paintPatternTransform);
paintPatternTransform.preConcatenate(state.tf); paintPatternTransform.preConcatenate(state.affineTransform);
patternTransform.concatenate(paintPatternTransform); patternTransform.concatenate(paintPatternTransform);
} else { } else {
patternTransform.concatenate(state.tf); patternTransform.concatenate(state.affineTransform);
} }
patternTransform.scale(1f, -1f); patternTransform.scale(1f, -1f);
pattern.setMatrix(patternTransform); pattern.setMatrix(patternTransform);
@ -167,7 +170,7 @@ public class DefaultPaintApplier implements PaintApplier {
appearance.setBBox(pattern.getBBox()); appearance.setBBox(pattern.getBBox());
Object graphicsNode = getPropertyValue(paint, "getGraphicsNode"); Object graphicsNode = getPropertyValue(paint, "getGraphicsNode");
PdfBoxGraphics2D pdfBoxGraphics2D = PdfBoxGraphics2D pdfBoxGraphics2D =
new PdfBoxGraphics2D(state.document, pattern.getBBox(), state.env.getGraphics2D()); new PdfBoxGraphics2D(state.document, pattern.getBBox(), state.paintApplierEnvironment.getGraphics2D());
try { try {
Method paintMethod = graphicsNode.getClass().getMethod("paint", Graphics2D.class); Method paintMethod = graphicsNode.getClass().getMethod("paint", Graphics2D.class);
paintMethod.invoke(graphicsNode, pdfBoxGraphics2D); paintMethod.invoke(graphicsNode, pdfBoxGraphics2D);
@ -294,7 +297,7 @@ public class DefaultPaintApplier implements PaintApplier {
Point2D startPoint = clonePoint(getPropertyValue(paint, "getStartPoint")); Point2D startPoint = clonePoint(getPropertyValue(paint, "getStartPoint"));
Point2D endPoint = clonePoint(getPropertyValue(paint, "getEndPoint")); Point2D endPoint = clonePoint(getPropertyValue(paint, "getEndPoint"));
AffineTransform gradientTransform = getPropertyValue(paint, "getTransform"); AffineTransform gradientTransform = getPropertyValue(paint, "getTransform");
state.tf.concatenate(gradientTransform); state.affineTransform.concatenate(gradientTransform);
// noinspection unused // noinspection unused
MultipleGradientPaint.CycleMethod cycleMethod = getCycleMethod(paint); MultipleGradientPaint.CycleMethod cycleMethod = getCycleMethod(paint);
@ -321,19 +324,13 @@ public class DefaultPaintApplier implements PaintApplier {
// will display it another. // will display it another.
float calculatedX = (float) Math.min(startPoint.getX(), endPoint.getX()); float calculatedX = (float) Math.min(startPoint.getX(), endPoint.getX());
float calculatedY = (float) Math.max(1.0f, Math.max(startPoint.getY(), endPoint.getY())); float calculatedY = (float) Math.max(1.0f, Math.max(startPoint.getY(), endPoint.getY()));
float calculatedWidth = Math float calculatedWidth = Math.max(1.0f, Math.abs((float) (endPoint.getX() - startPoint.getX())));
.max(1.0f, Math.abs((float) (endPoint.getX() - startPoint.getX()))); float negativeHeight = -1.0f * Math.max(1.0f, Math.abs((float) (endPoint.getY() - startPoint.getY())));
float negativeHeight =
-1.0f * Math.max(1.0f, Math.abs((float) (endPoint.getY() - startPoint.getY())));
state.contentStream.addRect(calculatedX, calculatedY, calculatedWidth, negativeHeight); state.contentStream.addRect(calculatedX, calculatedY, calculatedWidth, negativeHeight);
state.paintApplierEnvironment.getGraphics2D().markPathIsOnStream();
state.env.getGraphics2D().markPathIsOnStream(); state.paintApplierEnvironment.getGraphics2D().internalClip(false);
state.env.getGraphics2D().internalClip(false);
// Warp the 1x1 box containing the gradient to fill a larger rectangular space // Warp the 1x1 box containing the gradient to fill a larger rectangular space
state.contentStream.transform(new Matrix(state.tf)); state.contentStream.transform(new Matrix(state.affineTransform));
return shading; return shading;
} }
@ -357,15 +354,15 @@ public class DefaultPaintApplier implements PaintApplier {
Point2D startPoint = clonePoint(getPropertyValue(paint, "getStartPoint")); Point2D startPoint = clonePoint(getPropertyValue(paint, "getStartPoint"));
Point2D endPoint = clonePoint(getPropertyValue(paint, "getEndPoint")); Point2D endPoint = clonePoint(getPropertyValue(paint, "getEndPoint"));
AffineTransform gradientTransform = getPropertyValue(paint, "getTransform"); AffineTransform gradientTransform = getPropertyValue(paint, "getTransform");
state.tf.concatenate(gradientTransform); state.affineTransform.concatenate(gradientTransform);
// noinspection unused // noinspection unused
MultipleGradientPaint.CycleMethod cycleMethod = getCycleMethod(paint); MultipleGradientPaint.CycleMethod cycleMethod = getCycleMethod(paint);
// noinspection unused // noinspection unused
MultipleGradientPaint.ColorSpaceType colorSpaceType = getColorSpaceType(paint); MultipleGradientPaint.ColorSpaceType colorSpaceType = getColorSpaceType(paint);
state.tf.transform(startPoint, startPoint); state.affineTransform.transform(startPoint, startPoint);
state.tf.transform(endPoint, endPoint); state.affineTransform.transform(endPoint, endPoint);
setupShadingCoords(shading, startPoint, endPoint); setupShadingCoords(shading, startPoint, endPoint);
@ -483,12 +480,12 @@ public class DefaultPaintApplier implements PaintApplier {
Point2D centerPoint = clonePoint(getPropertyValue(paint, "getCenterPoint")); Point2D centerPoint = clonePoint(getPropertyValue(paint, "getCenterPoint"));
Point2D focusPoint = clonePoint(getPropertyValue(paint, "getFocusPoint")); Point2D focusPoint = clonePoint(getPropertyValue(paint, "getFocusPoint"));
AffineTransform gradientTransform = getPropertyValue(paint, "getTransform"); AffineTransform gradientTransform = getPropertyValue(paint, "getTransform");
state.tf.concatenate(gradientTransform); state.affineTransform.concatenate(gradientTransform);
state.tf.transform(centerPoint, centerPoint); state.affineTransform.transform(centerPoint, centerPoint);
state.tf.transform(focusPoint, focusPoint); state.affineTransform.transform(focusPoint, focusPoint);
float radius = getPropertyValue(paint, "getRadius"); float radius = getPropertyValue(paint, "getRadius");
radius = (float) Math.abs(radius * state.tf.getScaleX()); radius = (float) Math.abs(radius * state.affineTransform.getScaleX());
COSArray coords = new COSArray(); COSArray coords = new COSArray();
@ -523,8 +520,8 @@ public class DefaultPaintApplier implements PaintApplier {
Point2D startPoint = gradientPaint.getPoint1(); Point2D startPoint = gradientPaint.getPoint1();
Point2D endPoint = gradientPaint.getPoint2(); Point2D endPoint = gradientPaint.getPoint2();
state.tf.transform(startPoint, startPoint); state.affineTransform.transform(startPoint, startPoint);
state.tf.transform(endPoint, endPoint); state.affineTransform.transform(endPoint, endPoint);
setupShadingCoords(shading, startPoint, endPoint); setupShadingCoords(shading, startPoint, endPoint);
@ -670,7 +667,7 @@ public class DefaultPaintApplier implements PaintApplier {
* @return the value read from the object * @return the value read from the object
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected static <T> T getPropertyValue(Object obj, String propertyGetter) { public static <T> T getPropertyValue(Object obj, String propertyGetter) {
if (obj == null) { if (obj == null) {
return null; return null;
} }
@ -696,8 +693,8 @@ public class DefaultPaintApplier implements PaintApplier {
protected PDExtendedGraphicsState pdExtendedGraphicsState; protected PDExtendedGraphicsState pdExtendedGraphicsState;
protected Composite composite; protected Composite composite;
private COSDictionary dictExtendedState; private COSDictionary dictExtendedState;
private PaintApplierEnv env; private PaintApplierEnvironment paintApplierEnvironment;
public AffineTransform tf; private AffineTransform affineTransform;
protected AffineTransform nestedTransform; protected AffineTransform nestedTransform;
private void ensureExtendedState() { private void ensureExtendedState() {

View file

@ -1,9 +1,12 @@
package org.xbib.graphics.io.pdfbox; package org.xbib.graphics.io.pdfbox.paint;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.graphics.shading.PDShading; import org.apache.pdfbox.pdmodel.graphics.shading.PDShading;
import org.xbib.graphics.io.pdfbox.image.ImageEncoder;
import org.xbib.graphics.io.pdfbox.PdfBoxGraphics2D;
import org.xbib.graphics.io.pdfbox.color.ColorMapper;
import java.awt.Color; import java.awt.Color;
import java.awt.Composite; import java.awt.Composite;
@ -14,7 +17,7 @@ import java.awt.geom.AffineTransform;
import java.io.IOException; import java.io.IOException;
/** /**
* Apply the given paint on the Content Stream. * Apply the given paint on the content stream.
*/ */
public interface PaintApplier { public interface PaintApplier {
/** /**
@ -30,13 +33,13 @@ public interface PaintApplier {
* @throws IOException if its not possible to write the paint into the contentStream * @throws IOException if its not possible to write the paint into the contentStream
*/ */
PDShading applyPaint(Paint paint, PDPageContentStream contentStream, PDShading applyPaint(Paint paint, PDPageContentStream contentStream,
AffineTransform currentTransform, PaintApplierEnv env) throws IOException; AffineTransform currentTransform, PaintApplierEnvironment env) throws IOException;
/** /**
* The different mappers used by the paint applier. This interface is * The different mappers used by the paint applier. This interface is
* implemented internally by {@link PdfBoxGraphics2D} * implemented internally by {@link PdfBoxGraphics2D}
*/ */
interface PaintApplierEnv { interface PaintApplierEnvironment {
/** /**
* @return the color mapper * @return the color mapper
*/ */

View file

@ -29,7 +29,8 @@ public class DanglingCaseTest {
child2.setColor(Color.GREEN); child2.setColor(Color.GREEN);
child2.drawOval(0, 0, 5, 5); child2.drawOval(0, 0, 5, 5);
child.create(); child.create();
pdfBoxGraphics2D.disposeDanglingChildGraphics(); child.dispose();
child2.dispose();
pdfBoxGraphics2D.dispose(); pdfBoxGraphics2D.dispose();
PDFormXObject appearanceStream = pdfBoxGraphics2D.getXFormObject(); PDFormXObject appearanceStream = pdfBoxGraphics2D.getXFormObject();
Matrix matrix = new Matrix(); Matrix matrix = new Matrix();
@ -54,15 +55,4 @@ public class DanglingCaseTest {
pdfBoxGraphics2D.dispose(); pdfBoxGraphics2D.dispose();
}); });
} }
@Test
public void testDanglingDisposeException2() {
Assertions.assertThrows(IllegalStateException.class, () -> {
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
PdfBoxGraphics2D pdfBoxGraphics2D = new PdfBoxGraphics2D(document, 400, 400);
pdfBoxGraphics2D.create().disposeDanglingChildGraphics();
});
}
} }

View file

@ -1,65 +0,0 @@
package org.xbib.graphics.io.pdfbox;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.junit.jupiter.api.Test;
import java.awt.Font;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
public class DefaultFontTextDrawerFontsTest {
@Test
public void testFontStyleMatching() {
Font anyFont = Font.decode("Dialog");
Font anyFontBold = anyFont.deriveFont(Font.BOLD);
Font anyFontItalic = anyFont.deriveFont(Font.ITALIC);
Font anyFontBoldItalic = anyFont.deriveFont(Font.BOLD | Font.ITALIC);
assertEquals(PDType1Font.COURIER, DefaultFontTextDrawerFonts.chooseMatchingCourier(anyFont));
assertEquals(PDType1Font.COURIER_BOLD,
DefaultFontTextDrawerFonts.chooseMatchingCourier(anyFontBold));
assertEquals(PDType1Font.COURIER_OBLIQUE,
DefaultFontTextDrawerFonts.chooseMatchingCourier(anyFontItalic));
assertEquals(PDType1Font.COURIER_BOLD_OBLIQUE,
DefaultFontTextDrawerFonts.chooseMatchingCourier(anyFontBoldItalic));
assertEquals(PDType1Font.HELVETICA,
DefaultFontTextDrawerFonts.chooseMatchingHelvetica(anyFont));
assertEquals(PDType1Font.HELVETICA_BOLD,
DefaultFontTextDrawerFonts.chooseMatchingHelvetica(anyFontBold));
assertEquals(PDType1Font.HELVETICA_OBLIQUE,
DefaultFontTextDrawerFonts.chooseMatchingHelvetica(anyFontItalic));
assertEquals(PDType1Font.HELVETICA_BOLD_OBLIQUE,
DefaultFontTextDrawerFonts.chooseMatchingHelvetica(anyFontBoldItalic));
assertEquals(PDType1Font.TIMES_ROMAN, DefaultFontTextDrawerFonts.chooseMatchingTimes(anyFont));
assertEquals(PDType1Font.TIMES_BOLD,
DefaultFontTextDrawerFonts.chooseMatchingTimes(anyFontBold));
assertEquals(PDType1Font.TIMES_ITALIC,
DefaultFontTextDrawerFonts.chooseMatchingTimes(anyFontItalic));
assertEquals(PDType1Font.TIMES_BOLD_ITALIC,
DefaultFontTextDrawerFonts.chooseMatchingTimes(anyFontBoldItalic));
}
@Test
public void testDefaultFontMapping() {
assertEquals(PDType1Font.HELVETICA,
DefaultFontTextDrawerFonts.mapDefaultFonts(Font.decode(Font.DIALOG)));
assertEquals(PDType1Font.HELVETICA,
DefaultFontTextDrawerFonts.mapDefaultFonts(Font.decode(Font.DIALOG_INPUT)));
assertEquals(PDType1Font.HELVETICA,
DefaultFontTextDrawerFonts.mapDefaultFonts(Font.decode("Arial")));
assertEquals(PDType1Font.COURIER,
DefaultFontTextDrawerFonts.mapDefaultFonts(Font.decode(Font.MONOSPACED)));
assertEquals(PDType1Font.TIMES_ROMAN,
DefaultFontTextDrawerFonts.mapDefaultFonts(Font.decode(Font.SERIF)));
assertEquals(PDType1Font.ZAPF_DINGBATS,
DefaultFontTextDrawerFonts.mapDefaultFonts(Font.decode("Dingbats")));
assertEquals(PDType1Font.SYMBOL,
DefaultFontTextDrawerFonts.mapDefaultFonts(Font.decode("Symbol")));
assertNull(DefaultFontTextDrawerFonts.mapDefaultFonts(Font.decode("Georgia")));
}
}

View file

@ -9,6 +9,9 @@ import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.Matrix;
import org.xbib.graphics.io.pdfbox.font.CoreFontDrawer;
import org.xbib.graphics.io.pdfbox.font.DefaultFontDrawer;
import org.xbib.graphics.io.pdfbox.font.ForcedFontDrawer;
import java.awt.FontFormatException; import java.awt.FontFormatException;
import java.awt.Graphics2D; import java.awt.Graphics2D;
@ -25,7 +28,7 @@ class PdfBoxGraphics2DTestBase {
void exportGraphic(String dir, String name, GraphicsExporter exporter) { void exportGraphic(String dir, String name, GraphicsExporter exporter) {
try { try {
PDDocument document = new PDDocument(); PDDocument document = new PDDocument();
PDFont pdArial = PDType1Font.HELVETICA; PDFont helvetica = PDType1Font.HELVETICA;
File parentDir = new File("build/test/" + dir); File parentDir = new File("build/test/" + dir);
parentDir.mkdirs(); parentDir.mkdirs();
BufferedImage image = new BufferedImage(400, 400, BufferedImage.TYPE_4BYTE_ABGR); BufferedImage image = new BufferedImage(400, 400, BufferedImage.TYPE_4BYTE_ABGR);
@ -38,7 +41,6 @@ class PdfBoxGraphics2DTestBase {
document.addPage(page); document.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(document, page); PDPageContentStream contentStream = new PDPageContentStream(document, page);
PdfBoxGraphics2D pdfBoxGraphics2D = new PdfBoxGraphics2D(document, 400, 400); PdfBoxGraphics2D pdfBoxGraphics2D = new PdfBoxGraphics2D(document, 400, 400);
DefaultFontTextDrawer fontTextDrawer = null;
contentStream.beginText(); contentStream.beginText();
contentStream.setStrokingColor(0f, 0f, 0f); contentStream.setStrokingColor(0f, 0f, 0f);
contentStream.setNonStrokingColor(0f, 0f, 0f); contentStream.setNonStrokingColor(0f, 0f, 0f);
@ -46,20 +48,21 @@ class PdfBoxGraphics2DTestBase {
contentStream.setTextMatrix(Matrix.getTranslateInstance(10, 800)); contentStream.setTextMatrix(Matrix.getTranslateInstance(10, 800));
contentStream.showText("Mode " + m); contentStream.showText("Mode " + m);
contentStream.endText(); contentStream.endText();
DefaultFontDrawer fontTextDrawer = null;
switch (m) { switch (m) {
case FontTextIfPossible: case FontTextIfPossible:
fontTextDrawer = new DefaultFontTextDrawer(); fontTextDrawer = new DefaultFontDrawer();
registerFots(fontTextDrawer); registerFonts(fontTextDrawer);
break; break;
case DefaultFontText: { case DefaultFontText: {
fontTextDrawer = new DefaultFontTextDrawerFonts(); fontTextDrawer = new CoreFontDrawer();
registerFots(fontTextDrawer); registerFonts(fontTextDrawer);
break; break;
} }
case ForceFontText: case ForceFontText:
fontTextDrawer = new DefaultFontTextDrawerForce(); fontTextDrawer = new ForcedFontDrawer();
registerFots(fontTextDrawer); registerFonts(fontTextDrawer);
fontTextDrawer.registerFont("Arial", pdArial); fontTextDrawer.registerFont("Arial", helvetica);
break; break;
case DefaultVectorized: case DefaultVectorized:
default: default:
@ -88,7 +91,7 @@ class PdfBoxGraphics2DTestBase {
} }
} }
private void registerFots(DefaultFontTextDrawer fontTextDrawer) { private void registerFonts(DefaultFontDrawer fontTextDrawer) {
fontTextDrawer.registerFont(new File("src/test/resources/org/xbib/graphics/io/pdfbox/DejaVuSerifCondensed.ttf")); fontTextDrawer.registerFont(new File("src/test/resources/org/xbib/graphics/io/pdfbox/DejaVuSerifCondensed.ttf"));
fontTextDrawer.registerFont(new File("src/test/resources/org/xbib/graphics/io/pdfbox/antonio/Antonio-Regular.ttf")); fontTextDrawer.registerFont(new File("src/test/resources/org/xbib/graphics/io/pdfbox/antonio/Antonio-Regular.ttf"));
} }

View file

@ -3,6 +3,7 @@ package org.xbib.graphics.io.pdfbox;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.imageio.ImageReader; import javax.imageio.ImageReader;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.xbib.graphics.io.pdfbox.color.CMYKColor;
import java.awt.AlphaComposite; import java.awt.AlphaComposite;
import java.awt.BasicStroke; import java.awt.BasicStroke;

View file

@ -17,6 +17,8 @@ import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.rendering.PageDrawer; import org.apache.pdfbox.rendering.PageDrawer;
import org.apache.pdfbox.rendering.PageDrawerParameters; import org.apache.pdfbox.rendering.PageDrawerParameters;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.xbib.graphics.io.pdfbox.color.CMYKColor;
import org.xbib.graphics.io.pdfbox.draw.DefaultDrawControl;
import java.awt.BasicStroke; import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
@ -123,12 +125,12 @@ public class PdfRerenderTest {
boolean insideOwnDraw = false; boolean insideOwnDraw = false;
@Override @Override
public void afterShapeFill(Shape shape, DrawControlEnv env) { public void afterShapeFill(Shape shape, DrawControlEnvironment env) {
afterShapeDraw(shape, env); afterShapeDraw(shape, env);
} }
@Override @Override
public void afterShapeDraw(Shape shape, DrawControlEnv env) { public void afterShapeDraw(Shape shape, DrawControlEnvironment env) {
if (insideOwnDraw) if (insideOwnDraw)
return; return;
insideOwnDraw = true; insideOwnDraw = true;

View file

@ -17,8 +17,11 @@ import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.util.Matrix; import org.apache.pdfbox.util.Matrix;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.xbib.graphics.io.pdfbox.color.DefaultColorMapper;
import org.xbib.graphics.io.pdfbox.color.RGBtoCMYKColorMapper;
import org.xbib.graphics.io.pdfbox.font.DefaultFontDrawer;
import org.xbib.graphics.io.pdfbox.font.FontDrawer;
import java.awt.Graphics2D;
import java.awt.color.ICC_Profile; import java.awt.color.ICC_Profile;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -96,7 +99,7 @@ public class RenderSVGsTest extends PdfBoxGraphics2DTestBase {
"/org/apache/pdfbox/resources/icc/ISOcoated_v2_300_bas.icc")); "/org/apache/pdfbox/resources/icc/ISOcoated_v2_300_bas.icc"));
DefaultColorMapper colorMapper = new RGBtoCMYKColorMapper(icc_profile, pdfDocument); DefaultColorMapper colorMapper = new RGBtoCMYKColorMapper(icc_profile, pdfDocument);
pdfBoxGraphics2D.setColorMapper(colorMapper); pdfBoxGraphics2D.setColorMapper(colorMapper);
FontTextDrawer fontTextDrawer; FontDrawer fontDrawer;
contentStream.beginText(); contentStream.beginText();
contentStream.setStrokingColor(0.0f, 0.0f, 0.0f, 1.0f); contentStream.setStrokingColor(0.0f, 0.0f, 0.0f, 1.0f);
contentStream.setNonStrokingColor(0.0f, 0.0f, 0.0f, 1.0f); contentStream.setNonStrokingColor(0.0f, 0.0f, 0.0f, 1.0f);
@ -104,8 +107,8 @@ public class RenderSVGsTest extends PdfBoxGraphics2DTestBase {
contentStream.setTextMatrix(Matrix.getTranslateInstance(10, 800)); contentStream.setTextMatrix(Matrix.getTranslateInstance(10, 800));
contentStream.showText("Mode: CMYK colorspace"); contentStream.showText("Mode: CMYK colorspace");
contentStream.endText(); contentStream.endText();
fontTextDrawer = new DefaultFontTextDrawer(); fontDrawer = new DefaultFontDrawer();
pdfBoxGraphics2D.setFontTextDrawer(fontTextDrawer); pdfBoxGraphics2D.setFontTextDrawer(fontDrawer);
pdfBoxGraphics2D.scale(scale, scale); pdfBoxGraphics2D.scale(scale, scale);
gvtRoot.paint(pdfBoxGraphics2D); gvtRoot.paint(pdfBoxGraphics2D);
pdfBoxGraphics2D.dispose(); pdfBoxGraphics2D.dispose();

View file

@ -0,0 +1,65 @@
package org.xbib.graphics.io.pdfbox.font;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.junit.jupiter.api.Test;
import java.awt.Font;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
public class FontDrawerTest {
@Test
public void testFontStyleMatching() {
Font anyFont = Font.decode("Dialog");
Font anyFontBold = anyFont.deriveFont(Font.BOLD);
Font anyFontItalic = anyFont.deriveFont(Font.ITALIC);
Font anyFontBoldItalic = anyFont.deriveFont(Font.BOLD | Font.ITALIC);
assertEquals(PDType1Font.COURIER, CoreFontDrawer.chooseMatchingCourier(anyFont));
assertEquals(PDType1Font.COURIER_BOLD,
CoreFontDrawer.chooseMatchingCourier(anyFontBold));
assertEquals(PDType1Font.COURIER_OBLIQUE,
CoreFontDrawer.chooseMatchingCourier(anyFontItalic));
assertEquals(PDType1Font.COURIER_BOLD_OBLIQUE,
CoreFontDrawer.chooseMatchingCourier(anyFontBoldItalic));
assertEquals(PDType1Font.HELVETICA,
CoreFontDrawer.chooseMatchingHelvetica(anyFont));
assertEquals(PDType1Font.HELVETICA_BOLD,
CoreFontDrawer.chooseMatchingHelvetica(anyFontBold));
assertEquals(PDType1Font.HELVETICA_OBLIQUE,
CoreFontDrawer.chooseMatchingHelvetica(anyFontItalic));
assertEquals(PDType1Font.HELVETICA_BOLD_OBLIQUE,
CoreFontDrawer.chooseMatchingHelvetica(anyFontBoldItalic));
assertEquals(PDType1Font.TIMES_ROMAN, CoreFontDrawer.chooseMatchingTimes(anyFont));
assertEquals(PDType1Font.TIMES_BOLD,
CoreFontDrawer.chooseMatchingTimes(anyFontBold));
assertEquals(PDType1Font.TIMES_ITALIC,
CoreFontDrawer.chooseMatchingTimes(anyFontItalic));
assertEquals(PDType1Font.TIMES_BOLD_ITALIC,
CoreFontDrawer.chooseMatchingTimes(anyFontBoldItalic));
}
@Test
public void testDefaultFontMapping() {
assertEquals(PDType1Font.HELVETICA,
CoreFontDrawer.mapToCoreFonts(Font.decode(Font.DIALOG)));
assertEquals(PDType1Font.HELVETICA,
CoreFontDrawer.mapToCoreFonts(Font.decode(Font.DIALOG_INPUT)));
assertEquals(PDType1Font.HELVETICA,
CoreFontDrawer.mapToCoreFonts(Font.decode("Arial")));
assertEquals(PDType1Font.COURIER,
CoreFontDrawer.mapToCoreFonts(Font.decode(Font.MONOSPACED)));
assertEquals(PDType1Font.TIMES_ROMAN,
CoreFontDrawer.mapToCoreFonts(Font.decode(Font.SERIF)));
assertEquals(PDType1Font.ZAPF_DINGBATS,
CoreFontDrawer.mapToCoreFonts(Font.decode("Dingbats")));
assertEquals(PDType1Font.SYMBOL,
CoreFontDrawer.mapToCoreFonts(Font.decode("Symbol")));
assertNull(CoreFontDrawer.mapToCoreFonts(Font.decode("Georgia")));
}
}