Skip to content

Commit

Permalink
Merge pull request #2863 from apache/3854-internalize.boxable
Browse files Browse the repository at this point in the history
CAUSEWAY-3854: internalize boxable
  • Loading branch information
andi-huber authored Jan 26, 2025
2 parents 4c3db06 + 73cd6ab commit fdc6a00
Show file tree
Hide file tree
Showing 26 changed files with 4,589 additions and 114 deletions.
22 changes: 1 addition & 21 deletions bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,7 @@ identified

<ognl.version>3.4.5</ognl.version>

<pdfbox.version>3.0.0</pdfbox.version> <!-- don't upgrade as boxable depends on it -->
<boxable.version>1.7.0</boxable.version>
<pdfbox.version>3.0.4</pdfbox.version>
<picocontainer.version>2.15</picocontainer.version>
<poi.version>5.4.0</poi.version>

Expand Down Expand Up @@ -1891,25 +1890,6 @@ identified
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.dhorions</groupId>
<artifactId>boxable</artifactId>
<version>${boxable.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.apache.poi</groupId>
Expand Down
9 changes: 0 additions & 9 deletions extensions/vw/tabular/pdf/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
</exclusion>
</exclusions>
</dependency>

Expand All @@ -64,11 +60,6 @@
<artifactId>pdfbox</artifactId>
</dependency>

<dependency>
<groupId>com.github.dhorions</groupId>
<artifactId>boxable</artifactId>
</dependency>

</dependencies>

</project>
36 changes: 36 additions & 0 deletions extensions/vw/tabular/pdf/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
module org.apache.causeway.extensions.tabular.pdf {
exports org.apache.causeway.extensions.tabular.pdf.factory;
exports org.apache.causeway.extensions.tabular.pdf.exporter;
exports org.apache.causeway.extensions.tabular.pdf;

requires static lombok;

requires java.desktop;

requires org.apache.causeway.applib;
requires org.apache.causeway.commons;
requires org.apache.logging.log4j;
requires org.apache.pdfbox;
requires org.apache.pdfbox.io;
requires org.jsoup;
requires spring.context;
requires spring.core;
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,47 +29,48 @@
import java.util.Date;
import java.util.List;

import be.quodlibet.boxable.Cell;
import be.quodlibet.boxable.Row;
import be.quodlibet.boxable.image.Image;
import org.apache.causeway.extensions.tabular.pdf.factory.internal.Cell;
import org.apache.causeway.extensions.tabular.pdf.factory.internal.Row;

record CellFactory(Row<?> row, Cell<?> template) {
record CellFactory(Row row, Cell template) {

public Cell createCell(final int i, final float width, final List<Object> rowData) {

public Cell<?> createCell(int i, float width, List<Object> rowData) {

Object cellValue = null;
if (rowData.size() >= i) {
cellValue = rowData.get(i);
if (cellValue instanceof String s) {
cellValue = s.replaceAll("\n", "<br>");
if (cellValue instanceof CharSequence seq) {
cellValue = seq.toString()
.replaceAll("\r", "")
.replaceAll("\n", "<br>");
}
}
if(cellValue==null) cellValue = "";

var cell = switch(cellValue.getClass().getSimpleName()) {
case "BufferedImage" -> row.createImageCell(width, new Image((BufferedImage)cellValue));
case "BufferedImage" -> row.createImageCell(width, (BufferedImage)cellValue);
default -> row.createCell(width, toString(cellValue));
};

cell.copyCellStyle(template);

return cell;
}

/**
* @param cellValue not {@code null} nor {@link BufferedImage}
*/
private String toString(Object valueAsObj) {
private String toString(final Object valueAsObj) {
// String
if(valueAsObj instanceof CharSequence value) {
return value.toString();
if(valueAsObj instanceof String value) {
return value;
}

// boolean
if(valueAsObj instanceof Boolean value) {
return value ? "" : "";
return value ? "+" : "-";
}

// date
if(valueAsObj instanceof Date value) {
var dateTime = LocalDateTime.ofInstant(value.toInstant(), ZoneId.systemDefault());
Expand Down Expand Up @@ -114,5 +115,5 @@ private String toString(Object valueAsObj) {
// if all else fails fallback to value's toString method
return valueAsObj.toString();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.causeway.extensions.tabular.pdf.factory;

import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.font.Standard14Fonts.FontName;

import lombok.experimental.UtilityClass;

@UtilityClass
class FontFactory {

PDFont helvetica() {
return new PDType1Font(FontName.HELVETICA);
}

PDFont helveticaBold() {
return new PDType1Font(FontName.HELVETICA_BOLD);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.causeway.extensions.tabular.pdf.factory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;

import lombok.experimental.UtilityClass;
import lombok.extern.log4j.Log4j2;

@UtilityClass
@Log4j2
public class FontUtils {

private record FontMetrics(
float height,
float ascent,
float descent) {
}

/**
* {@link HashMap} for caching {@link FontMetrics} for designated
* {@link PDFont} because {@link FontUtils#getHeight(PDFont, float)} is
* expensive to calculate and the results are only approximate.
*/
private static final Map<String, FontMetrics> fontMetrics = new HashMap<>();

private static final Map<String, PDFont> defaultFonts = new HashMap<>();

/**
* Loads the {@link PDType0Font} to be embedded in the specified
* {@link PDDocument}.
* @param document
* {@link PDDocument} where fonts will be loaded
* @param fontPath
* font path which will be loaded
* @return The read {@link PDType0Font}
*/
public static final PDType0Font loadFont(final PDDocument document, final String fontPath) {
try {
return PDType0Font.load(document, FontUtils.class.getClassLoader().getResourceAsStream(fontPath));
} catch (IOException e) {
log.warn("Cannot load given external font", e);
return null;
}
}

/**
* Retrieving {@link String} width depending on current font size. The width
* of the string in 1/1000 units of text space.
* @param font
* The font of text whose width will be retrieved
* @param text
* The text whose width will be retrieved
* @param fontSize
* The font size of text whose width will be retrieved
* @return text width
*/
public static float getStringWidth(final PDFont font, final String text, final float fontSize) {
try {
return font.getStringWidth(text) / 1000 * fontSize;
} catch (final IOException e) {
// turn into runtime exception
throw new IllegalStateException("Unable to determine text width", e);
}
}

/**
* Calculate the font ascent distance.
* @param font
* The font from which calculation will be applied
* @param fontSize
* The font size from which calculation will be applied
* @return Positive font ascent distance
*/
public static float getAscent(final PDFont font, final float fontSize) {
final String fontName = font.getName();
if (!fontMetrics.containsKey(fontName)) {
createFontMetrics(font);
}

return fontMetrics.get(fontName).ascent * fontSize;
}

/**
* Calculate the font descent distance.
* @param font
* The font from which calculation will be applied
* @param fontSize
* The font size from which calculation will be applied
* @return Negative font descent distance
*/
public static float getDescent(final PDFont font, final float fontSize) {
final String fontName = font.getName();
if (!fontMetrics.containsKey(fontName)) {
createFontMetrics(font);
}

return fontMetrics.get(fontName).descent * fontSize;
}

/**
* Calculate the font height.
* @param font
* {@link PDFont} from which the height will be calculated.
* @param fontSize
* font size for current {@link PDFont}.
* @return {@link PDFont}'s height
*/
public static float getHeight(final PDFont font, final float fontSize) {
final String fontName = font.getName();
if (!fontMetrics.containsKey(fontName)) {
createFontMetrics(font);
}

return fontMetrics.get(fontName).height * fontSize;
}

/**
* Create basic {@link FontMetrics} for current font.
* @param font
* The font from which calculation will be applied <<<<<<< HEAD
* @throws IOException
* If reading the font file fails ======= >>>>>>> using FreeSans
* as default font and added new free fonts
*/
private static void createFontMetrics(final PDFont font) {
final float base = font.getFontDescriptor().getXHeight() / 1000;
final float ascent = font.getFontDescriptor().getAscent() / 1000 - base;
final float descent = font.getFontDescriptor().getDescent() / 1000;
fontMetrics.put(font.getName(), new FontMetrics(base + ascent - descent, ascent, descent));
}

public static void addDefaultFonts(final PDFont font, final PDFont fontBold, final PDFont fontItalic,
final PDFont fontBoldItalic) {
defaultFonts.put("font", font);
defaultFonts.put("fontBold", fontBold);
defaultFonts.put("fontItalic", fontItalic);
defaultFonts.put("fontBoldItalic", fontBoldItalic);
}

public static Map<String, PDFont> getDefaultfonts() {
return defaultFonts;
}

public static void setSansFontsAsDefault(final PDDocument document) {
defaultFonts.put("font", loadFont(document, "fonts/FreeSans.ttf"));
defaultFonts.put("fontBold", loadFont(document, "fonts/FreeSansBold.ttf"));
defaultFonts.put("fontItalic", loadFont(document, "fonts/FreeSansOblique.ttf"));
defaultFonts.put("fontBoldItalic", loadFont(document, "fonts/FreeSansBoldOblique.ttf"));
}
}
Loading

0 comments on commit fdc6a00

Please sign in to comment.