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 {
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 org.apache.fontbox;
requires transitive java.desktop;

View file

@ -1,8 +1,18 @@
package org.xbib.graphics.io.pdfbox;
import org.xbib.graphics.io.pdfbox.DrawControl.DrawControlEnv;
import org.xbib.graphics.io.pdfbox.FontTextDrawer.FontTextDrawerEnv;
import org.xbib.graphics.io.pdfbox.PaintApplier.PaintApplierEnv;
import org.xbib.graphics.io.pdfbox.draw.DefaultDrawControl;
import org.xbib.graphics.io.pdfbox.draw.DrawControl;
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.COSStream;
import org.apache.pdfbox.pdmodel.PDDocument;
@ -74,23 +84,29 @@ public class PdfBoxGraphics2D extends Graphics2D {
private final PDPageContentStream contentStream;
private BufferedImage calcImage;
private final BufferedImage calcImage;
private PDDocument document;
private final PDDocument document;
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;
@ -106,13 +122,9 @@ public class PdfBoxGraphics2D extends Graphics2D {
private Color backgroundColor;
private int saveCounter = 0;
private int saveCounter;
private final CopyInfo copyInfo;
private final List<CopyInfo> copyList = new ArrayList<>();
private final PaintApplierEnvImpl paintEnv = new PaintApplierEnvImpl();
private boolean disposed;
/**
* 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
* 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
public Paint getPaint() {
return paint;
@ -137,7 +149,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
}
};
private final FontTextDrawerEnv fontDrawerEnv = new FontTextDrawerEnv() {
private final FontDrawerEnvironment fontDrawerEnv = new FontDrawerEnvironment() {
@Override
public PDDocument getDocument() {
return document;
@ -246,24 +258,8 @@ public class PdfBoxGraphics2D extends Graphics2D {
PDFormXObject xFormObject,
PdfBoxGraphics2D parentGfx)
throws IOException {
this.document = document;
this.xFormObject = xFormObject;
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;
this(document, xFormObject, new PDPageContentStream(document, xFormObject,
xFormObject.getStream().createOutputStream(COSName.FLATE_DECODE)), parentGfx);
}
public PdfBoxGraphics2D(PDDocument document,
@ -277,7 +273,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
contentStreamSaveState();
if (parentGfx != null) {
this.colorMapper = parentGfx.colorMapper;
this.fontTextDrawer = parentGfx.fontTextDrawer;
this.fontDrawer = parentGfx.fontDrawer;
this.imageEncoder = parentGfx.imageEncoder;
this.paintApplier = parentGfx.paintApplier;
}
@ -288,6 +284,15 @@ public class PdfBoxGraphics2D extends Graphics2D {
calcGfx = calcImage.createGraphics();
font = calcGfx.getFont();
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 {
@ -311,7 +316,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
this.clipShape = pdfBoxGraphics2D.clipShape;
this.backgroundColor = pdfBoxGraphics2D.backgroundColor;
this.colorMapper = pdfBoxGraphics2D.colorMapper;
this.fontTextDrawer = pdfBoxGraphics2D.fontTextDrawer;
this.fontDrawer = pdfBoxGraphics2D.fontDrawer;
this.imageEncoder = pdfBoxGraphics2D.imageEncoder;
this.paintApplier = pdfBoxGraphics2D.paintApplier;
this.drawControl = pdfBoxGraphics2D.drawControl;
@ -319,6 +324,11 @@ public class PdfBoxGraphics2D extends Graphics2D {
this.renderingHints = new HashMap<>(pdfBoxGraphics2D.renderingHints);
this.xorColor = pdfBoxGraphics2D.xorColor;
this.saveCounter = 0;
this.copyList = new ArrayList<>();
this.disposed = false;
this.paintEnv = pdfBoxGraphics2D.paintEnv;
this.hasPathOnStream = pdfBoxGraphics2D.hasPathOnStream;
this.renderingHints = pdfBoxGraphics2D.renderingHints;
contentStreamSaveState();
}
@ -346,10 +356,9 @@ public class PdfBoxGraphics2D extends Graphics2D {
if (this.saveCounter != 0) {
throw new IllegalStateException("SaveCounter should be 0, but is " + this.saveCounter);
}
document = null;
calcGfx.dispose();
calcImage.flush();
calcImage = null;
disposed = true;
}
@Override
@ -360,7 +369,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
}
try {
contentStreamSaveState();
Shape shapeToDraw = drawControl.transformShapeBeforeDraw(s, drawControlEnv);
Shape shapeToDraw = drawControl.transformShapeBeforeDraw(s, drawControlEnvironment);
if (shapeToDraw != null) {
walkShape(shapeToDraw);
PDShading pdShading = applyPaint(shapeToDraw);
@ -391,7 +400,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
contentStream.stroke();
hasPathOnStream = false;
}
drawControl.afterShapeDraw(s, drawControlEnv);
drawControl.afterShapeDraw(s, drawControlEnvironment);
contentStreamRestoreState();
} catch (IOException e) {
throw new PdfBoxGraphics2dException(e);
@ -538,7 +547,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
}
try {
contentStreamSaveState();
if (fontTextDrawer.canDrawText((AttributedCharacterIterator) iterator.clone(), fontDrawerEnv)) {
if (fontDrawer.canDrawText((AttributedCharacterIterator) iterator.clone(), fontDrawerEnv)) {
drawStringUsingText(iterator, x, y);
} else {
drawStringUsingShapes(iterator, x, y);
@ -566,7 +575,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
}
try {
contentStreamSaveState();
Shape shapeToFill = drawControl.transformShapeBeforeFill(s, drawControlEnv);
Shape shapeToFill = drawControl.transformShapeBeforeFill(s, drawControlEnvironment);
if (shapeToFill != null) {
boolean useEvenOdd = walkShape(shapeToFill);
PDShading shading = applyPaint(shapeToFill);
@ -584,7 +593,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
}
hasPathOnStream = false;
}
drawControl.afterShapeFill(s, drawControlEnv);
drawControl.afterShapeFill(s, drawControlEnvironment);
contentStreamRestoreState();
} catch (IOException e) {
throw new PdfBoxGraphics2dException(e);
@ -717,7 +726,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
@Override
public FontMetrics getFontMetrics(Font f) {
try {
return fontTextDrawer.getFontMetrics(f, fontDrawerEnv);
return fontDrawer.getFontMetrics(f, fontDrawerEnv);
} catch (IOException | FontFormatException e) {
throw new RuntimeException(e);
}
@ -934,32 +943,12 @@ public class PdfBoxGraphics2D extends Graphics2D {
* @return the PDAppearanceStream which resulted in this graphics
*/
public PDFormXObject getXFormObject() {
if (document != null) {
throw new IllegalStateException("You can only get the XformObject after you disposed the Graphics2D!");
}
if (copyInfo != null) {
throw new IllegalStateException("You can not get the Xform stream from the copy");
if (!disposed) {
throw new IllegalStateException("You can only get the XFormObject after you disposed the Graphics2D object");
}
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.
*
@ -1011,10 +1000,10 @@ public class PdfBoxGraphics2D extends Graphics2D {
* 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.
*
* @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) {
this.fontTextDrawer = fontTextDrawer;
public void setFontTextDrawer(FontDrawer fontDrawer) {
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.
* We can then safely clip() if there is a path on the content stream.
*/
void markPathIsOnStream() {
public void markPathIsOnStream() {
hasPathOnStream = true;
}
@ -1050,7 +1039,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
tf.concatenate(transform);
tf.translate(x, y);
contentStream.transform(new Matrix(tf));
fontTextDrawer.drawText(iterator, fontDrawerEnv);
fontDrawer.drawText(iterator, fontDrawerEnv);
contentStreamRestoreState();
}
@ -1151,7 +1140,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
*
* @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 (useEvenOdd) {
contentStream.clipEvenOdd();
@ -1226,7 +1215,7 @@ public class PdfBoxGraphics2D extends Graphics2D {
}
}
private class PaintApplierEnvImpl implements PaintApplierEnv {
private class DefaultPaintApplierEnvironment implements PaintApplierEnvironment {
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.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.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.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceCMYK;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
import org.xbib.graphics.io.pdfbox.paint.DefaultPaintApplier;
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.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.color.PDICCBased;
import org.xbib.graphics.io.pdfbox.color.DefaultColorMapper;
import java.awt.Color;
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;
@ -14,20 +14,20 @@ public class DefaultDrawControl implements DrawControl {
}
@Override
public Shape transformShapeBeforeFill(Shape shape, DrawControlEnv env) {
public Shape transformShapeBeforeFill(Shape shape, DrawControlEnvironment env) {
return shape;
}
@Override
public Shape transformShapeBeforeDraw(Shape shape, DrawControlEnv env) {
public Shape transformShapeBeforeDraw(Shape shape, DrawControlEnvironment env) {
return shape;
}
@Override
public void afterShapeFill(Shape shape, DrawControlEnv env) {
public void afterShapeFill(Shape shape, DrawControlEnvironment env) {
}
@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.Shape;
@ -18,7 +19,7 @@ public interface DrawControl {
* @param env Environment
* @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
@ -28,36 +29,36 @@ public interface DrawControl {
* @param env Environment
* @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
* {@link #transformShapeBeforeFill(Shape, DrawControlEnv)} returns
* {@link #transformShapeBeforeFill(Shape, DrawControlEnvironment)} returns
* null.
*
* @param shape the shape that was filled. This is the original shape, not the one
* transformed by
* {@link #transformShapeBeforeFill(Shape, DrawControlEnv)}.
* {@link #transformShapeBeforeFill(Shape, DrawControlEnvironment)}.
* @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
* {@link #transformShapeBeforeDraw(Shape, DrawControlEnv)} returns
* {@link #transformShapeBeforeDraw(Shape, DrawControlEnvironment)} returns
* null.
*
* @param shape the shape that was drawn. This is the original shape, not the one
* transformed by
* {@link #transformShapeBeforeDraw(Shape, DrawControlEnv)}.
* {@link #transformShapeBeforeDraw(Shape, DrawControlEnvironment)}.
* @param env Environment
*/
void afterShapeDraw(Shape shape, DrawControlEnv env);
void afterShapeDraw(Shape shape, DrawControlEnvironment env);
/**
* The environment of the draw operation
*/
interface DrawControlEnv {
interface DrawControlEnvironment {
/**
* @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;
@ -7,17 +7,17 @@ import java.awt.FontFormatException;
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
* 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
* and/or any other not supported feature is used.
*/
public class DefaultFontTextDrawerFonts extends DefaultFontTextDrawer {
public class CoreFontDrawer extends DefaultFontDrawer {
@Override
protected PDFont mapFont(Font font, FontTextDrawerEnv env) throws IOException, FontFormatException {
PDFont pdFont = mapDefaultFonts(font);
protected PDFont mapFont(Font font, FontDrawerEnvironment env) throws IOException, FontFormatException {
PDFont pdFont = mapToCoreFonts(font);
if (pdFont != null) {
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.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.PDType1Font;
import org.apache.pdfbox.util.Matrix;
import org.xbib.graphics.io.pdfbox.PdfBoxGraphics2D;
import java.awt.Font;
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
* 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
public void close() {
@ -141,54 +142,44 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable {
* the case if this class has been derived. The default implementation
* just checks for this.
*/
@SuppressWarnings("WeakerAccess")
protected boolean hasDynamicFontMapping() {
return getClass() != DefaultFontTextDrawer.class;
return getClass() != DefaultFontDrawer.class;
}
@Override
public boolean canDrawText(AttributedCharacterIterator iterator, FontTextDrawerEnv env)
public boolean canDrawText(AttributedCharacterIterator iterator, FontDrawerEnvironment env)
throws IOException, FontFormatException {
/*
* When no font is registered we can not display the text using a font...
*/
if (fontMap.size() == 0 && fontFiles.size() == 0 && !hasDynamicFontMapping())
if (fontMap.size() == 0 && fontFiles.size() == 0 && !hasDynamicFontMapping()) {
return false;
}
boolean run = true;
StringBuilder sb = new StringBuilder();
while (run) {
Font attributeFont = (Font) iterator.getAttribute(TextAttribute.FONT);
if (attributeFont == null)
if (attributeFont == null) {
attributeFont = env.getFont();
if (mapFont(attributeFont, env) == null)
}
if (mapFont(attributeFont, env) == null) {
return false;
/*
* We can not do a Background on the text currently.
*/
if (iterator.getAttribute(TextAttribute.BACKGROUND) != null)
}
if (iterator.getAttribute(TextAttribute.BACKGROUND) != null) {
return false;
boolean isStrikeThrough = TextAttribute.STRIKETHROUGH_ON
.equals(iterator.getAttribute(TextAttribute.STRIKETHROUGH));
boolean isUnderline = TextAttribute.UNDERLINE_ON
.equals(iterator.getAttribute(TextAttribute.UNDERLINE));
boolean isLigatures = TextAttribute.LIGATURES_ON
.equals(iterator.getAttribute(TextAttribute.LIGATURES));
if (isStrikeThrough || isUnderline || isLigatures)
}
boolean isStrikeThrough =
TextAttribute.STRIKETHROUGH_ON.equals(iterator.getAttribute(TextAttribute.STRIKETHROUGH));
boolean isUnderline =
TextAttribute.UNDERLINE_ON.equals(iterator.getAttribute(TextAttribute.UNDERLINE));
boolean isLigatures =
TextAttribute.LIGATURES_ON.equals(iterator.getAttribute(TextAttribute.LIGATURES));
if (isStrikeThrough || isUnderline || isLigatures) {
return false;
}
run = iterateRun(iterator, sb);
String s = sb.toString();
int l = s.length();
for (int i = 0; i < l; ) {
int codePoint = s.codePointAt(i);
switch (Character.getDirectionality(codePoint)) {
/*
* We can handle normal LTR.
*/
case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
case Character.DIRECTIONALITY_EUROPEAN_NUMBER:
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_OVERRIDE:
case Character.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT:
/*
* We can not handle this
*/
return false;
default:
/*
* Default: We can not handle this
*/
return false;
}
if (!attributeFont.canDisplay(codePoint))
if (!attributeFont.canDisplay(codePoint)) {
return false;
}
i += Character.charCount(codePoint);
}
}
@ -228,7 +212,7 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable {
}
@Override
public void drawText(AttributedCharacterIterator iterator, FontTextDrawerEnv env)
public void drawText(AttributedCharacterIterator iterator, FontDrawerEnvironment env)
throws IOException, FontFormatException {
PDPageContentStream contentStream = env.getContentStream();
@ -241,52 +225,37 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable {
StringBuilder sb = new StringBuilder();
boolean run = true;
while (run) {
Font attributeFont = (Font) iterator.getAttribute(TextAttribute.FONT);
if (attributeFont == null)
if (attributeFont == null) {
attributeFont = env.getFont();
}
Number fontSize = ((Number) iterator.getAttribute(TextAttribute.SIZE));
if (fontSize != null)
if (fontSize != null) {
attributeFont = attributeFont.deriveFont(fontSize.floatValue());
}
PDFont font = applyFont(attributeFont, env);
Paint paint = (Paint) iterator.getAttribute(TextAttribute.FOREGROUND);
if (paint == null)
if (paint == null) {
paint = env.getPaint();
boolean isStrikeThrough = TextAttribute.STRIKETHROUGH_ON
.equals(iterator.getAttribute(TextAttribute.STRIKETHROUGH));
boolean isUnderline = TextAttribute.UNDERLINE_ON
.equals(iterator.getAttribute(TextAttribute.UNDERLINE));
boolean isLigatures = TextAttribute.LIGATURES_ON
.equals(iterator.getAttribute(TextAttribute.LIGATURES));
}
boolean isStrikeThrough =
TextAttribute.STRIKETHROUGH_ON.equals(iterator.getAttribute(TextAttribute.STRIKETHROUGH));
boolean isUnderline =
TextAttribute.UNDERLINE_ON.equals(iterator.getAttribute(TextAttribute.UNDERLINE));
boolean isLigatures =
TextAttribute.LIGATURES_ON.equals(iterator.getAttribute(TextAttribute.LIGATURES));
run = iterateRun(iterator, sb);
String text = sb.toString();
/*
* Apply the paint
*/
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 {
showTextOnStream(env, contentStream, attributeFont, font, isStrikeThrough,
isUnderline, isLigatures, text);
} catch (IllegalArgumentException e) {
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 {
if (fallbackFontUnknownEncodings == null)
if (fallbackFontUnknownEncodings == null) {
fallbackFontUnknownEncodings = findFallbackFont(env);
}
if (fallbackFontUnknownEncodings != null) {
env.getContentStream().setFont(fallbackFontUnknownEncodings,
attributeFont.getSize2D());
@ -299,48 +268,35 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable {
e = e1;
}
}
if (e != null)
if (e != null) {
logger.log(Level.WARNING, "PDFBoxGraphics: Can not map text " + text + " with font "
+ attributeFont.getFontName() + ": " + e.getMessage());
}
}
}
contentStream.endText();
}
@Override
public FontMetrics getFontMetrics(final Font f, FontTextDrawerEnv env)
public FontMetrics getFontMetrics(Font f, FontDrawerEnvironment env)
throws IOException, FontFormatException {
final FontMetrics defaultMetrics = env.getCalculationGraphics().getFontMetrics(f);
final FontMetrics fontMetrics = env.getCalculationGraphics().getFontMetrics(f);
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) {
return defaultMetrics;
return fontMetrics;
}
return new DefaultFontMetrics(f, defaultMetrics, pdFont);
return new DefaultFontMetrics(f, fontMetrics, pdFont);
}
private PDFont fallbackFontUnknownEncodings;
private PDFont findFallbackFont(FontTextDrawerEnv env) throws IOException {
/*
* 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.
*/
private PDFont findFallbackFont(FontDrawerEnvironment env) {
String javaHome = System.getProperty("java.home", ".");
String javaFontDir = javaHome + "/lib/fonts";
String windir = System.getenv("WINDIR");
if (windir == null)
if (windir == null) {
windir = javaFontDir;
}
File[] paths = new File[]{new File(new File(windir), "fonts"),
new File(System.getProperty("user.dir", ".")),
// Mac Fonts
@ -357,24 +313,26 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable {
if (arialFile.exists()) {
// We try to use the first font we can find and use.
PDType0Font pdType0Font = tryToLoadFont(env, arialFile);
if (pdType0Font != null)
if (pdType0Font != null) {
return pdType0Font;
}
}
}
}
return null;
}
private PDType0Font tryToLoadFont(FontTextDrawerEnv env, File foundFontFile) {
private PDType0Font tryToLoadFont(FontDrawerEnvironment env, File foundFontFile) {
try {
return PDType0Font.load(env.getDocument(), foundFontFile);
} catch (IOException e) {
logger.log(Level.WARNING, e.getMessage(), e);
// The font may be have a embed restriction.
return null;
}
}
private void showTextOnStream(FontTextDrawerEnv env,
private void showTextOnStream(FontDrawerEnvironment env,
PDPageContentStream contentStream,
Font attributeFont,
PDFont font,
@ -385,11 +343,11 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable {
contentStream.showText(text);
}
private PDFont applyFont(Font font, FontTextDrawerEnv env)
private PDFont applyFont(Font font, FontDrawerEnvironment env)
throws IOException, FontFormatException {
PDFont fontToUse = mapFont(font, env);
if (fontToUse == null) {
fontToUse = DefaultFontTextDrawerFonts.chooseMatchingHelvetica(font);
fontToUse = CoreFontDrawer.chooseMatchingHelvetica(font);
}
env.getContentStream().setFont(fontToUse, font.getSize2D());
return fontToUse;
@ -404,13 +362,9 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable {
* @throws IOException when the font can not be loaded
* @throws FontFormatException when the font file can not be loaded
*/
@SuppressWarnings("WeakerAccess")
protected PDFont mapFont(final Font font, final FontTextDrawerEnv env)
protected PDFont mapFont(Font font, FontDrawerEnvironment env)
throws IOException, FontFormatException {
/*
* If we have any font registering's, we must perform them now
*/
for (final FontEntry fontEntry : fontFiles) {
for (FontEntry fontEntry : fontFiles) {
if (fontEntry.overrideName == null) {
Font javaFont = Font.createFont(Font.TRUETYPE_FONT, fontEntry.file);
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.
*
* @param font font for which to find a suitable default font
* @return null if no default font is found or a default font which does not
* Find a PDFont for the given font object.
* @param font font for which to find a suitable core font
* @return null if no core font is found or a core font which does not
* 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")) {
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 java.awt.Font;
@ -151,9 +151,6 @@ public class DefaultFontMetrics extends FontMetrics {
} catch (IOException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
/*
* We let unknown chars be handled with
*/
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.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.xbib.graphics.io.pdfbox.PdfBoxGraphics2D;
import java.awt.Font;
import java.awt.FontFormatException;
@ -16,9 +17,9 @@ import java.io.IOException;
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
@ -28,7 +29,7 @@ public interface FontTextDrawer {
* @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
*/
boolean canDrawText(AttributedCharacterIterator iterator, FontTextDrawerEnv env)
boolean canDrawText(AttributedCharacterIterator iterator, FontDrawerEnvironment env)
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 FontFormatException when the font file can not be loaded
*/
void drawText(AttributedCharacterIterator iterator, FontTextDrawerEnv env)
void drawText(AttributedCharacterIterator iterator, FontDrawerEnvironment env)
throws IOException, FontFormatException;
FontMetrics getFontMetrics(Font f, FontTextDrawerEnv env)
FontMetrics getFontMetrics(Font f, FontDrawerEnvironment env)
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
*/

View file

@ -1,14 +1,14 @@
package org.xbib.graphics.io.pdfbox;
package org.xbib.graphics.io.pdfbox.font;
import java.text.AttributedCharacterIterator;
/**
* 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
public boolean canDrawText(AttributedCharacterIterator iterator, FontTextDrawerEnv env) {
public boolean canDrawText(AttributedCharacterIterator iterator, FontDrawerEnvironment env) {
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.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.PDPageContentStream;
@ -42,11 +42,11 @@ public class LosslessImageEncoder implements ImageEncoder {
int height = image.getHeight(null);
bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
Graphics graphics = bi.getGraphics();
if (!graphics.drawImage(image, 0, 0, null, null))
throw new IllegalStateException("Not fully loaded images are not supported.");
if (!graphics.drawImage(image, 0, 0, null, null)) {
throw new IllegalStateException("Not fully loaded images are not supported");
}
graphics.dispose();
}
try {
if (doc == null || doc.get() != document) {
imageMap = new HashMap<>();
@ -76,7 +76,6 @@ public class LosslessImageEncoder implements ImageEncoder {
}
imageMap.put(new ImageSoftReference(image), new SoftReference<>(imageXObject));
}
return imageXObject;
} catch (IOException e) {
throw new RuntimeException("Could not encode Image", e);
@ -93,6 +92,9 @@ public class LosslessImageEncoder implements ImageEncoder {
if (obj == null) {
return false;
}
if (!(obj instanceof ImageSoftReference)) {
return false;
}
return ((ImageSoftReference) obj).get() == get();
}
@ -116,6 +118,9 @@ public class LosslessImageEncoder implements ImageEncoder {
if (obj == null) {
return false;
}
if (!(obj instanceof ProfileSoftReference)) {
return false;
}
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.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.interactive.annotation.PDAppearanceStream;
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.Color;
@ -63,7 +66,7 @@ public class DefaultPaintApplier implements PaintApplier {
@Override
public PDShading applyPaint(Paint paint, PDPageContentStream contentStream, AffineTransform tf,
PaintApplierEnv env) throws IOException {
PaintApplierEnvironment env) throws IOException {
PaintApplierState state = new PaintApplierState();
state.document = env.getDocument();
state.resources = env.getResources();
@ -72,8 +75,8 @@ public class DefaultPaintApplier implements PaintApplier {
state.imageEncoder = env.getImageEncoder();
state.composite = env.getComposite();
state.pdExtendedGraphicsState = null;
state.env = env;
state.tf = tf;
state.paintApplierEnvironment = env;
state.affineTransform = tf;
state.nestedTransform = null;
PDShading shading = applyPaint(paint, state);
if (state.pdExtendedGraphicsState != null) {
@ -155,10 +158,10 @@ public class DefaultPaintApplier implements PaintApplier {
AffineTransform patternTransform = new AffineTransform();
if (paintPatternTransform != null) {
paintPatternTransform = new AffineTransform(paintPatternTransform);
paintPatternTransform.preConcatenate(state.tf);
paintPatternTransform.preConcatenate(state.affineTransform);
patternTransform.concatenate(paintPatternTransform);
} else {
patternTransform.concatenate(state.tf);
patternTransform.concatenate(state.affineTransform);
}
patternTransform.scale(1f, -1f);
pattern.setMatrix(patternTransform);
@ -167,7 +170,7 @@ public class DefaultPaintApplier implements PaintApplier {
appearance.setBBox(pattern.getBBox());
Object graphicsNode = getPropertyValue(paint, "getGraphicsNode");
PdfBoxGraphics2D pdfBoxGraphics2D =
new PdfBoxGraphics2D(state.document, pattern.getBBox(), state.env.getGraphics2D());
new PdfBoxGraphics2D(state.document, pattern.getBBox(), state.paintApplierEnvironment.getGraphics2D());
try {
Method paintMethod = graphicsNode.getClass().getMethod("paint", Graphics2D.class);
paintMethod.invoke(graphicsNode, pdfBoxGraphics2D);
@ -294,7 +297,7 @@ public class DefaultPaintApplier implements PaintApplier {
Point2D startPoint = clonePoint(getPropertyValue(paint, "getStartPoint"));
Point2D endPoint = clonePoint(getPropertyValue(paint, "getEndPoint"));
AffineTransform gradientTransform = getPropertyValue(paint, "getTransform");
state.tf.concatenate(gradientTransform);
state.affineTransform.concatenate(gradientTransform);
// noinspection unused
MultipleGradientPaint.CycleMethod cycleMethod = getCycleMethod(paint);
@ -321,19 +324,13 @@ public class DefaultPaintApplier implements PaintApplier {
// will display it another.
float calculatedX = (float) Math.min(startPoint.getX(), endPoint.getX());
float calculatedY = (float) Math.max(1.0f, Math.max(startPoint.getY(), endPoint.getY()));
float calculatedWidth = Math
.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 calculatedWidth = Math.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())));
state.contentStream.addRect(calculatedX, calculatedY, calculatedWidth, negativeHeight);
state.env.getGraphics2D().markPathIsOnStream();
state.env.getGraphics2D().internalClip(false);
state.paintApplierEnvironment.getGraphics2D().markPathIsOnStream();
state.paintApplierEnvironment.getGraphics2D().internalClip(false);
// 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;
}
@ -357,15 +354,15 @@ public class DefaultPaintApplier implements PaintApplier {
Point2D startPoint = clonePoint(getPropertyValue(paint, "getStartPoint"));
Point2D endPoint = clonePoint(getPropertyValue(paint, "getEndPoint"));
AffineTransform gradientTransform = getPropertyValue(paint, "getTransform");
state.tf.concatenate(gradientTransform);
state.affineTransform.concatenate(gradientTransform);
// noinspection unused
MultipleGradientPaint.CycleMethod cycleMethod = getCycleMethod(paint);
// noinspection unused
MultipleGradientPaint.ColorSpaceType colorSpaceType = getColorSpaceType(paint);
state.tf.transform(startPoint, startPoint);
state.tf.transform(endPoint, endPoint);
state.affineTransform.transform(startPoint, startPoint);
state.affineTransform.transform(endPoint, endPoint);
setupShadingCoords(shading, startPoint, endPoint);
@ -483,12 +480,12 @@ public class DefaultPaintApplier implements PaintApplier {
Point2D centerPoint = clonePoint(getPropertyValue(paint, "getCenterPoint"));
Point2D focusPoint = clonePoint(getPropertyValue(paint, "getFocusPoint"));
AffineTransform gradientTransform = getPropertyValue(paint, "getTransform");
state.tf.concatenate(gradientTransform);
state.tf.transform(centerPoint, centerPoint);
state.tf.transform(focusPoint, focusPoint);
state.affineTransform.concatenate(gradientTransform);
state.affineTransform.transform(centerPoint, centerPoint);
state.affineTransform.transform(focusPoint, focusPoint);
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();
@ -523,8 +520,8 @@ public class DefaultPaintApplier implements PaintApplier {
Point2D startPoint = gradientPaint.getPoint1();
Point2D endPoint = gradientPaint.getPoint2();
state.tf.transform(startPoint, startPoint);
state.tf.transform(endPoint, endPoint);
state.affineTransform.transform(startPoint, startPoint);
state.affineTransform.transform(endPoint, endPoint);
setupShadingCoords(shading, startPoint, endPoint);
@ -670,7 +667,7 @@ public class DefaultPaintApplier implements PaintApplier {
* @return the value read from the object
*/
@SuppressWarnings("unchecked")
protected static <T> T getPropertyValue(Object obj, String propertyGetter) {
public static <T> T getPropertyValue(Object obj, String propertyGetter) {
if (obj == null) {
return null;
}
@ -696,8 +693,8 @@ public class DefaultPaintApplier implements PaintApplier {
protected PDExtendedGraphicsState pdExtendedGraphicsState;
protected Composite composite;
private COSDictionary dictExtendedState;
private PaintApplierEnv env;
public AffineTransform tf;
private PaintApplierEnvironment paintApplierEnvironment;
private AffineTransform affineTransform;
protected AffineTransform nestedTransform;
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.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDResources;
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.Composite;
@ -14,7 +17,7 @@ import java.awt.geom.AffineTransform;
import java.io.IOException;
/**
* Apply the given paint on the Content Stream.
* Apply the given paint on the content stream.
*/
public interface PaintApplier {
/**
@ -30,13 +33,13 @@ public interface PaintApplier {
* @throws IOException if its not possible to write the paint into the 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
* implemented internally by {@link PdfBoxGraphics2D}
*/
interface PaintApplierEnv {
interface PaintApplierEnvironment {
/**
* @return the color mapper
*/

View file

@ -29,7 +29,8 @@ public class DanglingCaseTest {
child2.setColor(Color.GREEN);
child2.drawOval(0, 0, 5, 5);
child.create();
pdfBoxGraphics2D.disposeDanglingChildGraphics();
child.dispose();
child2.dispose();
pdfBoxGraphics2D.dispose();
PDFormXObject appearanceStream = pdfBoxGraphics2D.getXFormObject();
Matrix matrix = new Matrix();
@ -54,15 +55,4 @@ public class DanglingCaseTest {
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.graphics.form.PDFormXObject;
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.Graphics2D;
@ -25,7 +28,7 @@ class PdfBoxGraphics2DTestBase {
void exportGraphic(String dir, String name, GraphicsExporter exporter) {
try {
PDDocument document = new PDDocument();
PDFont pdArial = PDType1Font.HELVETICA;
PDFont helvetica = PDType1Font.HELVETICA;
File parentDir = new File("build/test/" + dir);
parentDir.mkdirs();
BufferedImage image = new BufferedImage(400, 400, BufferedImage.TYPE_4BYTE_ABGR);
@ -38,7 +41,6 @@ class PdfBoxGraphics2DTestBase {
document.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
PdfBoxGraphics2D pdfBoxGraphics2D = new PdfBoxGraphics2D(document, 400, 400);
DefaultFontTextDrawer fontTextDrawer = null;
contentStream.beginText();
contentStream.setStrokingColor(0f, 0f, 0f);
contentStream.setNonStrokingColor(0f, 0f, 0f);
@ -46,20 +48,21 @@ class PdfBoxGraphics2DTestBase {
contentStream.setTextMatrix(Matrix.getTranslateInstance(10, 800));
contentStream.showText("Mode " + m);
contentStream.endText();
DefaultFontDrawer fontTextDrawer = null;
switch (m) {
case FontTextIfPossible:
fontTextDrawer = new DefaultFontTextDrawer();
registerFots(fontTextDrawer);
fontTextDrawer = new DefaultFontDrawer();
registerFonts(fontTextDrawer);
break;
case DefaultFontText: {
fontTextDrawer = new DefaultFontTextDrawerFonts();
registerFots(fontTextDrawer);
fontTextDrawer = new CoreFontDrawer();
registerFonts(fontTextDrawer);
break;
}
case ForceFontText:
fontTextDrawer = new DefaultFontTextDrawerForce();
registerFots(fontTextDrawer);
fontTextDrawer.registerFont("Arial", pdArial);
fontTextDrawer = new ForcedFontDrawer();
registerFonts(fontTextDrawer);
fontTextDrawer.registerFont("Arial", helvetica);
break;
case DefaultVectorized:
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/antonio/Antonio-Regular.ttf"));
}

View file

@ -3,6 +3,7 @@ package org.xbib.graphics.io.pdfbox;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import org.junit.jupiter.api.Test;
import org.xbib.graphics.io.pdfbox.color.CMYKColor;
import java.awt.AlphaComposite;
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.PageDrawerParameters;
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.Color;
@ -123,12 +125,12 @@ public class PdfRerenderTest {
boolean insideOwnDraw = false;
@Override
public void afterShapeFill(Shape shape, DrawControlEnv env) {
public void afterShapeFill(Shape shape, DrawControlEnvironment env) {
afterShapeDraw(shape, env);
}
@Override
public void afterShapeDraw(Shape shape, DrawControlEnv env) {
public void afterShapeDraw(Shape shape, DrawControlEnvironment env) {
if (insideOwnDraw)
return;
insideOwnDraw = true;

View file

@ -17,8 +17,11 @@ import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.util.Matrix;
import org.junit.jupiter.api.Test;
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.io.File;
import java.io.IOException;
@ -96,7 +99,7 @@ public class RenderSVGsTest extends PdfBoxGraphics2DTestBase {
"/org/apache/pdfbox/resources/icc/ISOcoated_v2_300_bas.icc"));
DefaultColorMapper colorMapper = new RGBtoCMYKColorMapper(icc_profile, pdfDocument);
pdfBoxGraphics2D.setColorMapper(colorMapper);
FontTextDrawer fontTextDrawer;
FontDrawer fontDrawer;
contentStream.beginText();
contentStream.setStrokingColor(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.showText("Mode: CMYK colorspace");
contentStream.endText();
fontTextDrawer = new DefaultFontTextDrawer();
pdfBoxGraphics2D.setFontTextDrawer(fontTextDrawer);
fontDrawer = new DefaultFontDrawer();
pdfBoxGraphics2D.setFontTextDrawer(fontDrawer);
pdfBoxGraphics2D.scale(scale, scale);
gvtRoot.paint(pdfBoxGraphics2D);
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")));
}
}