Skip to content

Commit

Permalink
add few overloaded constructors to ITextRenderer
Browse files Browse the repository at this point in the history
... to allow users easily override UserAgent, FontResolver, TextRenderer etc.
  • Loading branch information
asolntsev committed Dec 30, 2023
1 parent caa73a1 commit b575161
Show file tree
Hide file tree
Showing 12 changed files with 88 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public static byte[] readBytes(String uri) {
@Nonnull
@CheckReturnValue
public static byte[] readBytes(InputStream is) throws IOException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
ByteArrayOutputStream result = new ByteArrayOutputStream(is.available());
copyBytes(is, result);
return result.toByteArray();
}
Expand Down
9 changes: 5 additions & 4 deletions flying-saucer-examples/src/main/java/PDFRender.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.xhtmlrenderer.resource.XMLResource;
import org.xml.sax.InputSource;

import javax.annotation.ParametersAreNonnullByDefault;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
Expand Down Expand Up @@ -53,8 +54,7 @@ public static void main(String[] args) throws IOException, DocumentException {
public static void createPDF(String url, String pdf) throws IOException, DocumentException {
try (OutputStream os = newOutputStream(Paths.get(pdf))) {
ITextRenderer renderer = new ITextRenderer();
ResourceLoaderUserAgent callback = new ResourceLoaderUserAgent(renderer.getOutputDevice());
callback.setSharedContext(renderer.getSharedContext());
ResourceLoaderUserAgent callback = new ResourceLoaderUserAgent(renderer.getOutputDevice(), renderer.getSharedContext().getDotsPerPixel());
renderer.getSharedContext ().setUserAgentCallback(callback);

Document doc = XMLResource.load(new InputSource(url)).getDocument();
Expand All @@ -65,9 +65,10 @@ public static void createPDF(String url, String pdf) throws IOException, Documen
}
}

@ParametersAreNonnullByDefault
private static class ResourceLoaderUserAgent extends ITextUserAgent {
private ResourceLoaderUserAgent(ITextOutputDevice outputDevice) {
super(outputDevice);
private ResourceLoaderUserAgent(ITextOutputDevice outputDevice, int dotsPerPixel) {
super(outputDevice, dotsPerPixel);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ public void convertComplexHtmlToPdf() throws IOException, DocumentException {
private static PDF generatePDF(URL source, File output) throws IOException, DocumentException {
try (OutputStream os = newOutputStream(output.toPath())) {
ITextRenderer renderer = new ITextRenderer();
ResourceLoaderUserAgent callback = new ResourceLoaderUserAgent(renderer.getOutputDevice());
callback.setSharedContext(renderer.getSharedContext());
ResourceLoaderUserAgent callback = new ResourceLoaderUserAgent(renderer.getOutputDevice(), renderer.getSharedContext().getDotsPerPixel());
renderer.getSharedContext().setUserAgentCallback(callback);

Document doc = XMLResource.load(new InputSource(source.toString())).getDocument();
Expand All @@ -69,8 +68,8 @@ private static PDF generatePDF(URL source, File output) throws IOException, Docu

@ParametersAreNonnullByDefault
private static class ResourceLoaderUserAgent extends ITextUserAgent {
private ResourceLoaderUserAgent(ITextOutputDevice outputDevice) {
super(outputDevice);
private ResourceLoaderUserAgent(ITextOutputDevice outputDevice, int dotsPerPixel) {
super(outputDevice, dotsPerPixel);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ public void generator() throws Exception {

private void generatePDF(String xml, OutputStream os) throws DocumentException, IOException {
ITextRenderer renderer = new ITextRenderer();
ITextUserAgent ua = new ITextUserAgent(renderer.getOutputDevice());
ua.setSharedContext(renderer.getSharedContext());
ITextUserAgent ua = new ITextUserAgent(renderer.getOutputDevice(), renderer.getSharedContext().getDotsPerPixel());
renderer.getSharedContext().setUserAgentCallback(ua);
renderer.getSharedContext().setLineBreakingStrategy(new FOPLineBreakingStrategy());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.xhtmlrenderer.css.style.FSDerivedValue;
import org.xhtmlrenderer.css.value.FontSpecification;
import org.xhtmlrenderer.extend.FontResolver;
import org.xhtmlrenderer.extend.UserAgentCallback;
import org.xhtmlrenderer.layout.SharedContext;
import org.xhtmlrenderer.render.FSFont;
import org.xhtmlrenderer.util.XRLog;
Expand Down Expand Up @@ -56,10 +57,10 @@ public class ITextFontResolver implements FontResolver {
private final Map<String, FontFamily> _fontFamilies = createInitialFontMap();
private final Map<String, FontDescription> _fontCache = new HashMap<>();

private final SharedContext _sharedContext;
private final UserAgentCallback userAgent;

public ITextFontResolver(SharedContext sharedContext) {
_sharedContext = sharedContext;
public ITextFontResolver(UserAgentCallback userAgent) {
this.userAgent = userAgent;
}

/**
Expand Down Expand Up @@ -117,7 +118,7 @@ public void importFontFaces(List<FontFaceRule> fontFaces) {
continue;
}

byte[] font1 = _sharedContext.getUac().getBinaryResource(src.asString());
byte[] font1 = userAgent.getBinaryResource(src.asString());
if (font1 == null) {
XRLog.exception("Could not load font " + src.asString());
continue;
Expand All @@ -126,7 +127,7 @@ public void importFontFaces(List<FontFaceRule> fontFaces) {
byte[] font2 = null;
FSDerivedValue metricsSrc = style.valueByName(CSSName.FS_FONT_METRIC_SRC);
if (metricsSrc != IdentValue.NONE) {
font2 = _sharedContext.getUac().getBinaryResource(metricsSrc.asString());
font2 = userAgent.getBinaryResource(metricsSrc.asString());
if (font2 == null) {
XRLog.exception("Could not load font metric data " + src.asString());
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
import org.xhtmlrenderer.context.StyleReference;
import org.xhtmlrenderer.css.style.CalculatedStyle;
import org.xhtmlrenderer.css.style.derived.RectPropertySet;
import org.xhtmlrenderer.extend.FontResolver;
import org.xhtmlrenderer.extend.NamespaceHandler;
import org.xhtmlrenderer.extend.ReplacedElementFactory;
import org.xhtmlrenderer.extend.TextRenderer;
import org.xhtmlrenderer.extend.UserInterface;
import org.xhtmlrenderer.layout.BoxBuilder;
import org.xhtmlrenderer.layout.Layer;
Expand Down Expand Up @@ -100,24 +103,33 @@ public ITextRenderer() {
}

public ITextRenderer(float dotsPerPoint, int dotsPerPixel) {
_dotsPerPoint = dotsPerPoint;
this(dotsPerPoint, dotsPerPixel, new ITextOutputDevice(dotsPerPoint));
}

public ITextRenderer(float dotsPerPoint, int dotsPerPixel, ITextOutputDevice outputDevice) {
this(dotsPerPoint, dotsPerPixel, outputDevice, new ITextUserAgent(outputDevice, dotsPerPixel));
}

public ITextRenderer(ITextOutputDevice outputDevice, ITextUserAgent userAgent) {
this(outputDevice.getDotsPerPoint(), userAgent.getDotsPerPixel(), outputDevice, userAgent);
}

_outputDevice = new ITextOutputDevice(_dotsPerPoint);
public ITextRenderer(float dotsPerPoint, int dotsPerPixel, ITextOutputDevice outputDevice, ITextUserAgent userAgent) {
this(dotsPerPoint, dotsPerPixel, outputDevice, userAgent, new ITextFontResolver(userAgent),
new ITextReplacedElementFactory(outputDevice), new ITextTextRenderer());
}

ITextUserAgent userAgent = new ITextUserAgent(_outputDevice);
public ITextRenderer(float dotsPerPoint, int dotsPerPixel, ITextOutputDevice outputDevice, ITextUserAgent userAgent,
FontResolver fontResolver, ReplacedElementFactory replacedElementFactory, TextRenderer textRenderer) {
_dotsPerPoint = dotsPerPoint;
_outputDevice = outputDevice;
_sharedContext = new SharedContext();
_sharedContext.setUserAgentCallback(userAgent);
_sharedContext.setCss(new StyleReference(userAgent));
userAgent.setSharedContext(_sharedContext);
_outputDevice.setSharedContext(_sharedContext);

ITextFontResolver fontResolver = new ITextFontResolver(_sharedContext);
_sharedContext.setFontResolver(fontResolver);

ITextReplacedElementFactory replacedElementFactory = new ITextReplacedElementFactory(_outputDevice);
_sharedContext.setReplacedElementFactory(replacedElementFactory);

_sharedContext.setTextRenderer(new ITextTextRenderer());
_sharedContext.setTextRenderer(textRenderer);
_sharedContext.setDPI(72 * _dotsPerPoint);
_sharedContext.setDotsPerPixel(dotsPerPixel);
_sharedContext.setPrint(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfReader;
import org.xhtmlrenderer.extend.FSImage;
import org.xhtmlrenderer.layout.SharedContext;
import org.xhtmlrenderer.resource.ImageResource;
import org.xhtmlrenderer.swing.NaiveUserAgent;
import org.xhtmlrenderer.util.Configuration;
Expand All @@ -34,32 +33,30 @@
import org.xhtmlrenderer.util.ImageUtil;
import org.xhtmlrenderer.util.XRLog;

import java.io.ByteArrayOutputStream;
import javax.annotation.ParametersAreNonnullByDefault;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;

@ParametersAreNonnullByDefault
public class ITextUserAgent extends NaiveUserAgent {
private static final int IMAGE_CACHE_CAPACITY = 32;

private SharedContext _sharedContext;

private final ITextOutputDevice _outputDevice;
private final int dotsPerPixel;

public ITextUserAgent(ITextOutputDevice outputDevice) {
public ITextUserAgent(ITextOutputDevice outputDevice, int dotsPerPixel) {
super(Configuration.valueAsInt("xr.image.cache-capacity", IMAGE_CACHE_CAPACITY));
this.dotsPerPixel = dotsPerPixel;
_outputDevice = outputDevice;
}

public int getDotsPerPixel() {
return dotsPerPixel;
}

private byte[] readStream(InputStream is) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream(is.available());
byte[] buf = new byte[10240];
int i;
while ( (i = is.read(buf)) != -1) {
out.write(buf, 0, i);
}
out.close();
return out.toByteArray();
return IOUtil.readBytes(is);
}

@Override
Expand Down Expand Up @@ -127,17 +124,9 @@ private ImageResource loadEmbeddedBase64ImageResource(final String uri) {
}

private void scaleToOutputResolution(Image image) {
float factor = _sharedContext.getDotsPerPixel();
float factor = dotsPerPixel;
if (factor != 1.0f) {
image.scaleAbsolute(image.getPlainWidth() * factor, image.getPlainHeight() * factor);
}
}

public SharedContext getSharedContext() {
return _sharedContext;
}

public void setSharedContext(SharedContext sharedContext) {
_sharedContext = sharedContext;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,6 @@ public class ITextFontResolver implements FontResolver {
private final Map<String, FontFamily> _fontFamilies = new HashMap<>();
private final Map<String, FontDescription> _fontCache = new HashMap<>();

public ITextFontResolver() {
}

/**
* @deprecated Use default constructor (sharedContext is not used anymore by this class)
*/
@Deprecated
public ITextFontResolver(SharedContext sharedContext) {
this(sharedContext, true);
}

/**
* @param sharedContext not needed in constructor anymore
* @param withCjkfonts instead of passing this parameter, please use subclass {@link CJKFontResolver}
* @deprecated Use default constructor
*/
@Deprecated
public ITextFontResolver(SharedContext sharedContext, boolean withCjkfonts) {
}

public synchronized Map<String, FontFamily> getFonts() {
if (_fontFamilies.isEmpty()) {
_fontFamilies.putAll(loadFonts());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import org.xhtmlrenderer.css.style.CalculatedStyle;
import org.xhtmlrenderer.extend.FontResolver;
import org.xhtmlrenderer.extend.NamespaceHandler;
import org.xhtmlrenderer.extend.ReplacedElementFactory;
import org.xhtmlrenderer.extend.TextRenderer;
import org.xhtmlrenderer.extend.UserInterface;
import org.xhtmlrenderer.layout.BoxBuilder;
import org.xhtmlrenderer.layout.Layer;
Expand Down Expand Up @@ -63,8 +65,7 @@
import static java.nio.charset.StandardCharsets.UTF_8;

public class ITextRenderer {
// These two defaults combine to produce an effective resolution of 96 px to
// the inch
// These two defaults combine to produce an effective resolution of 96 px to the inch
public static final float DEFAULT_DOTS_PER_POINT = 20f * 4f / 3f;
public static final int DEFAULT_DOTS_PER_PIXEL = 20;

Expand All @@ -87,8 +88,14 @@ public class ITextRenderer {
// use one of the values in PDFWriter.VERSION...
private Character _pdfVersion;

private final char[] validPdfVersions = { PdfWriter.VERSION_1_2, PdfWriter.VERSION_1_3, PdfWriter.VERSION_1_4,
PdfWriter.VERSION_1_5, PdfWriter.VERSION_1_6, PdfWriter.VERSION_1_7 };
private final char[] validPdfVersions = {
PdfWriter.VERSION_1_2,
PdfWriter.VERSION_1_3,
PdfWriter.VERSION_1_4,
PdfWriter.VERSION_1_5,
PdfWriter.VERSION_1_6,
PdfWriter.VERSION_1_7
};

private Integer _pdfXConformance;

Expand All @@ -112,39 +119,44 @@ public ITextRenderer(float dotsPerPoint, int dotsPerPixel, FontResolver fontReso
this(dotsPerPoint, dotsPerPixel, new ITextOutputDevice(dotsPerPoint), fontResolver);
}

public ITextRenderer(ITextOutputDevice outputDevice, ITextUserAgent userAgent) {
this(outputDevice.getDotsPerPoint(), DEFAULT_DOTS_PER_PIXEL, outputDevice, userAgent, new ITextFontResolver());
}

public ITextRenderer(float dotsPerPoint, int dotsPerPixel, ITextOutputDevice outputDevice) {
this(dotsPerPoint, dotsPerPixel, outputDevice, new ITextUserAgent(outputDevice));
this(dotsPerPoint, dotsPerPixel, outputDevice, new ITextUserAgent(outputDevice, dotsPerPixel));
}

public ITextRenderer(float dotsPerPoint, int dotsPerPixel, ITextOutputDevice outputDevice, FontResolver fontResolver) {
this(dotsPerPoint, dotsPerPixel, outputDevice, new ITextUserAgent(outputDevice), fontResolver);
this(dotsPerPoint, dotsPerPixel, outputDevice, new ITextUserAgent(outputDevice, dotsPerPixel), fontResolver);
}

public ITextRenderer(float dotsPerPoint, int dotsPerPixel, ITextOutputDevice outputDevice, ITextUserAgent userAgent) {
this(dotsPerPoint, dotsPerPixel, outputDevice, userAgent, new ITextFontResolver());
}

public ITextRenderer(float dotsPerPoint, int dotsPerPixel, ITextOutputDevice outputDevice, ITextUserAgent userAgent, FontResolver fontResolver) {
public ITextRenderer(float dotsPerPoint, int dotsPerPixel, ITextOutputDevice outputDevice, ITextUserAgent userAgent,
FontResolver fontResolver) {
this(dotsPerPoint, dotsPerPixel, outputDevice, userAgent, fontResolver,
new ITextReplacedElementFactory(outputDevice), new ITextTextRenderer());
}

public ITextRenderer(float dotsPerPoint, int dotsPerPixel, ITextOutputDevice outputDevice, ITextUserAgent userAgent,
FontResolver fontResolver, ReplacedElementFactory replacedElementFactory,
TextRenderer textRenderer) {
_dotsPerPoint = dotsPerPoint;
_outputDevice = outputDevice;

_sharedContext = new SharedContext();
_sharedContext.setUserAgentCallback(userAgent);
_sharedContext.setCss(new StyleReference(userAgent));
userAgent.setSharedContext(_sharedContext);
_outputDevice.setSharedContext(_sharedContext);

_sharedContext.setFontResolver(fontResolver);

ITextReplacedElementFactory replacedElementFactory = new ITextReplacedElementFactory(_outputDevice);
_sharedContext.setReplacedElementFactory(replacedElementFactory);

_sharedContext.setTextRenderer(new ITextTextRenderer());
_sharedContext.setTextRenderer(textRenderer);
_sharedContext.setDPI(72 * _dotsPerPoint);
_sharedContext.setDotsPerPixel(dotsPerPixel);
_sharedContext.setPrint(true);
_sharedContext.setInteractive(false);

_timeouted= false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public ReplacedElement createReplacedElement(LayoutContext c, BlockBox box,
switch (nodeName) {
case "img":
String srcAttr = e.getAttribute("src");
if (srcAttr.length() > 0) {
if (!srcAttr.isEmpty()) {
FSImage fsImage = uac.getImageResource(srcAttr).getImage();
if (fsImage != null) {
if (cssWidth != -1 || cssHeight != -1) {
Expand Down
Loading

0 comments on commit b575161

Please sign in to comment.