Skip to content

Commit

Permalink
#612 #608 #405 Allow to add font files for SVGs instead of input stream
Browse files Browse the repository at this point in the history
  • Loading branch information
danfickle committed Nov 30, 2020
1 parent a9ba3af commit 9a9ccd0
Show file tree
Hide file tree
Showing 12 changed files with 357 additions and 122 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.openhtmltopdf.extend;

import java.awt.FontFormatException;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.List;

import org.w3c.dom.Element;

import com.openhtmltopdf.css.sheet.FontFaceRule;
import com.openhtmltopdf.css.style.CssContext;
import com.openhtmltopdf.layout.SharedContext;
import com.openhtmltopdf.outputdevice.helper.BaseRendererBuilder.FontStyle;
import com.openhtmltopdf.render.Box;
import com.openhtmltopdf.render.RenderingContext;

Expand All @@ -28,4 +32,6 @@ interface SVGImage {
void drawSVG(OutputDevice outputDevice, RenderingContext ctx,
double x, double y);
}

void addFontFile(File fontFile, String family, Integer weight, FontStyle style) throws IOException, FontFormatException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import java.io.File;
import java.io.InputStream;
import java.util.Set;

import com.openhtmltopdf.extend.FSSupplier;
import com.openhtmltopdf.outputdevice.helper.BaseRendererBuilder.FSFontUseCase;
import com.openhtmltopdf.outputdevice.helper.BaseRendererBuilder.FontStyle;

public class AddedFont {
Expand All @@ -14,25 +16,40 @@ public class AddedFont {
public final boolean subset;
public final FontStyle style;
public final Object pdfontSupplier; // Bit of a hack, not type-safe!
public final Set<FSFontUseCase> usedFor;

public AddedFont(FSSupplier<InputStream> supplier, File fontFile, Integer weight, String family, boolean subset,
FontStyle style) {
public AddedFont(
FSSupplier<InputStream> supplier,
File fontFile,
Integer weight,
String family,
boolean subset,
FontStyle style,
Set<FSFontUseCase> usedFor) {
this.supplier = supplier;
this.fontFile = fontFile;
this.pdfontSupplier = null;
this.weight = weight;
this.family = family;
this.subset = subset;
this.style = style;
this.usedFor = usedFor;
}

public AddedFont(Object pdfontSupplier, Integer weight, String family, boolean subset, FontStyle style) {
public AddedFont(
Object pdfontSupplier,
Integer weight,
String family,
boolean subset,
FontStyle style,
Set<FSFontUseCase> usedFor) {
this.supplier = null;
this.fontFile = null;
this.pdfontSupplier = pdfontSupplier;
this.weight = weight;
this.family = family;
this.subset = subset;
this.style = style;
this.usedFor = usedFor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -453,61 +454,98 @@ public final TFinalClass useFastMode() {
}

/**
* Like {@link #useFont(FSSupplier, String, Integer, FontStyle, boolean)}, but
* allows to supply a font file. If the font file is a .ttc file it is handled
* as TrueTypeCollection (PDF only). If you have the font in file form you should use this
* API.
* <p>Allows the user to provide a font file for use by the main
* document only (not SVGs). See:
* {@link #useFont(File, String, Integer, FontStyle, boolean, Set)}</p>
*
* <p>For gotchas related to font handling please see:
* <a href="https://github.com/danfickle/openhtmltopdf/wiki/Fonts">Wiki: Fonts</a></p>
*/
public TFinalClass useFont(File fontFile, String fontFamily, Integer fontWeight, FontStyle fontStyle,
public TFinalClass useFont(
File fontFile,
String fontFamily,
Integer fontWeight,
FontStyle fontStyle,
boolean subset) {
state._fonts.add(new AddedFont(null, fontFile, fontWeight, fontFamily, subset, fontStyle));
state._fonts.add(new AddedFont(null, fontFile, fontWeight, fontFamily, subset, fontStyle, EnumSet.of(FSFontUseCase.DOCUMENT)));
return (TFinalClass) this;
}

/**
* <p>Allows the user to provide a font file for use any or all of
* the use cases listed in {@link FSFontUseCase} such as main
* document, SVGs, etc.</p>
*
* <p>For gotchas related to font handling please see:
* <a href="https://github.com/danfickle/openhtmltopdf/wiki/Fonts">Wiki: Fonts</a></p>
*
* @param fontFile A file system font file in true-type format. Beware of using resources as
* they will not be separate files in the final jar.
* @param fontFamily Font family name. If using a font in Java2D, SVG or MathML this should match
* <code>Font.createFont(Font.TRUETYPE_FONT, fontFile).getFamily()</code>.
* @param fontWeight Font boldness, usually 400 for regular fonts and 700 for bold fonts.
* @param fontStyle Normal, italic or oblique.
* @param subset For PDF use whether the font is subset, usually true unless the font is
* being used by form controls.
* @param fontUsedFor Which components use the font such as main document, SVG, etc. Example:
* <code>EnumSet.of(FSFontUseCase.DOCUMENT, FSFontUseCase.SVG)</code>
* @return this for method chaining
*/
public TFinalClass useFont(
File fontFile,
String fontFamily,
Integer fontWeight,
FontStyle fontStyle,
boolean subset,
Set<FSFontUseCase> fontUsedFor) {
state._fonts.add(new AddedFont(null, fontFile, fontWeight, fontFamily, subset, fontStyle, fontUsedFor));
return (TFinalClass) this;
}

/**
* Simpler overload for
* {@link #useFont(File, String, Integer, FontStyle, boolean)}
*
* @param fontFile
* @param fontFamily
* @return this for method chaining
*/
public TFinalClass useFont(File fontFile, String fontFamily) {
return this.useFont(fontFile, fontFamily, 400, FontStyle.NORMAL, true);
}

/**
* Add a font programmatically. If the font is NOT subset, it will be downloaded
* <p>Add a font programmatically. If the font is NOT subset, it will be downloaded
* when the renderer is run, otherwise, assuming a font-metrics cache has been configured,
* the font will only be downloaded if required. Therefore, the user could add many fonts,
* confident that only those that are needed will be downloaded and processed.
* confident that only those that are needed will be downloaded and processed.</p>
*
* The InputStream returned by the supplier will be closed by the caller. Fonts
* should generally be subset (Java2D rendered ignores this argument),
* except when used in form controls. FSSupplier is a lambda compatible interface.
* <p>The InputStream returned by the supplier will be closed by the caller. Fonts
* should generally be subset (Java2D renderer ignores this argument),
* except when used in form controls. FSSupplier is a lambda compatible interface.</p>
*
* Fonts can also be added using a font-face at-rule in the CSS.
* <p>Fonts can also be added using a font-face at-rule in the CSS (not
* recommended for Java2D usage).</p>
*
* <p><strong>IMPORTANT:</strong> This method will add fonts for use by the main document
* only. It is not recommended for use with Java2D.
* To add fonts for use by Java2D, SVG, etc see:
* {@link #useFont(File, String, Integer, FontStyle, boolean, Set)}</p>
*
* <p>For gotchas related to font handling please see:
* <a href="https://github.com/danfickle/openhtmltopdf/wiki/Fonts">Wiki: Fonts</a></p>
*
* @param supplier
* @param fontFamily
* @param fontWeight
* @param fontStyle
* @param subset
* @return
* @return this for method chaining
*/
public TFinalClass useFont(FSSupplier<InputStream> supplier, String fontFamily, Integer fontWeight,
FontStyle fontStyle, boolean subset) {
state._fonts.add(new AddedFont(supplier, null, fontWeight, fontFamily, subset, fontStyle));
state._fonts.add(new AddedFont(supplier, null, fontWeight, fontFamily, subset, fontStyle, EnumSet.of(FSFontUseCase.DOCUMENT)));
return (TFinalClass) this;
}

/**
* Simpler overload for
* {@link #useFont(FSSupplier, String, Integer, FontStyle, boolean)}
*
* @param supplier
* @param fontFamily
* @return
* @return this for method chaining
*/
public TFinalClass useFont(FSSupplier<InputStream> supplier, String fontFamily) {
return this.useFont(supplier, fontFamily, 400, FontStyle.NORMAL, true);
Expand All @@ -533,4 +571,14 @@ public enum PageSizeUnits {
public enum FontStyle {
NORMAL, ITALIC, OBLIQUE
}

/**
* Use cases for fonts.
*/
public enum FSFontUseCase {
/** Main document (PDF or Java2D) */
DOCUMENT,
SVG,
MATHML
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<html>
<head>
<style>
@page {
size: 300px 300px;
}
svg {
border: 1px solid red;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<text y="40" x="10" font-family="Karla" font-weight="bold" font-size="32">Karla Bold</text>
<circle cx="50" cy="80" r="20"/>
</svg>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
package com.openhtmltopdf.visualregressiontests;

import java.awt.Font;
import java.awt.FontFormatException;
import java.io.*;

import static org.junit.Assert.assertTrue;

import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.EnumSet;

import com.openhtmltopdf.bidi.support.ICUBidiReorderer;
import com.openhtmltopdf.bidi.support.ICUBidiSplitter;
import com.openhtmltopdf.extend.FSStream;
import com.openhtmltopdf.objects.zxing.ZXingObjectDrawer;
import com.openhtmltopdf.outputdevice.helper.BaseRendererBuilder.FSFontUseCase;
import com.openhtmltopdf.outputdevice.helper.BaseRendererBuilder.FontStyle;

import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
Expand Down Expand Up @@ -1295,6 +1301,25 @@ public void testPr610ForcePageBreakLine() throws IOException {
assertTrue(vt.runTest("pr-610-force-page-break-line"));
}


/**
* Tests that a font can be added as a file for use with SVGs.
*/
@Test
public void testSVGFontFileAddition() throws IOException, FontFormatException {
TestSupport.makeFontFiles();

assertTrue(vt.runTest("svg-font-file-addition",
builder -> {
TestSupport.WITH_SVG.configure(builder);
builder.useFont(
new File("target/test/visual-tests/Karla-Bold.ttf"),
"Karla",
700, FontStyle.NORMAL, true,
EnumSet.of(FSFontUseCase.SVG));
}));
}

// TODO:
// + Elements that appear just on generated overflow pages.
// + content property (page counters, etc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.awt.Font;
import java.awt.FontFormatException;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
Expand All @@ -27,6 +28,7 @@
import com.openhtmltopdf.css.style.FSDerivedValue;
import com.openhtmltopdf.extend.SVGDrawer;
import com.openhtmltopdf.layout.SharedContext;
import com.openhtmltopdf.outputdevice.helper.BaseRendererBuilder.FontStyle;
import com.openhtmltopdf.render.Box;
import com.openhtmltopdf.util.XRLog;

Expand Down Expand Up @@ -125,4 +127,9 @@ public SVGImage buildSVGImage(Element mathMlElement, Box box, CssContext c, doub
public void close() throws IOException {
FontFactory.clearThreadFontFactory();
}

public void addFontFile(File fontFile, String family, Integer weight, FontStyle style) {
// TODO Auto-generated method stub

}
}
Loading

0 comments on commit 9a9ccd0

Please sign in to comment.