Compare commits
45 commits
Author | SHA1 | Date | |
---|---|---|---|
a70b7e62cf | |||
a323076ca3 | |||
b13aa5f3ef | |||
2d6961e848 | |||
09086f9b5b | |||
2dedbc154f | |||
0564b2e934 | |||
aa08fa45f0 | |||
e81e605887 | |||
0f3f8d488a | |||
a58f1e6c83 | |||
afbe6eee2f | |||
229951349b | |||
27fd1956a1 | |||
55ae303d70 | |||
e42bdecb99 | |||
047fee7798 | |||
b906e7533b | |||
6e82a0fbbd | |||
840cdc36f8 | |||
ca2df9023f | |||
e88864e843 | |||
1cfc5b2989 | |||
45b783c90a | |||
64bbee5cd3 | |||
7b624e8f30 | |||
734cdfc90c | |||
75c123bd6e | |||
3b02aa2b75 | |||
923e63ccbe | |||
67609394cc | |||
b08fa2d137 | |||
319dd41658 | |||
2fdccf2c79 | |||
ff5512b813 | |||
e1266a3b44 | |||
dabbf89e5d | |||
c76b419657 | |||
ae7ea4d1ba | |||
2b9ff08296 | |||
ba25c5ed3b | |||
0162464b0f | |||
1df6a1ea16 | |||
b62aacfe59 | |||
26d8f2756a |
3350 changed files with 130586 additions and 1584 deletions
build.gradlegradle.propertiesgradlewgradlew.bat
gradle
compile
repositories
test
wrapper
graphics-barcode
build.gradle
src
graphics-chart/src
graphics-fonts-arabic
Google-Noto-LICENSE.txtbuild.gradle
src/main
java
resources
META-INF/services
org/xbib/graphics/fonts/arabic
graphics-fonts-cjk
Google-Noto-LICENSE.txtbuild.gradle
src/main
java
resources
META-INF/services
org/xbib/graphics/fonts/cjk
graphics-fonts-cyrillic
Google-Noto-LICENSE.txtNOTICE.txtbuild.gradle
src/main
java
resources
META-INF/services
org/xbib/graphics/fonts/cyrillic
graphics-fonts-hebrew
Google-Noto-LICENSE.txtbuild.gradle
src/main
java
resources
META-INF/services
org/xbib/graphics/fonts/hebrew
graphics-fonts-latin
Adobe-Source-LICENSE.txtGoogle-Noto-LICENSE.txtbuild.gradle
src
main
java
module-info.java
org/xbib/graphics/fonts/latin
resources
META-INF/services
org/xbib/graphics/fonts/latin
test/java/org/xbib/graphics/fonts/latin/test
graphics-fonts
build.gradle
src
graphics-ghostscript/src/main/java
module-info.java
org/xbib/graphics/ghostscript
13
build.gradle
13
build.gradle
|
@ -1,17 +1,13 @@
|
|||
|
||||
plugins {
|
||||
id "checkstyle"
|
||||
id "pmd"
|
||||
id 'maven-publish'
|
||||
id 'signing'
|
||||
id "io.github.gradle-nexus.publish-plugin" version "1.3.0"
|
||||
id "com.github.spotbugs" version "5.0.14"
|
||||
id "org.cyclonedx.bom" version "1.7.2"
|
||||
id "io.github.gradle-nexus.publish-plugin" version "2.0.0-rc-1"
|
||||
}
|
||||
|
||||
wrapper {
|
||||
gradleVersion = libs.versions.gradle.get()
|
||||
distributionType = Wrapper.DistributionType.ALL
|
||||
distributionType = Wrapper.DistributionType.BIN
|
||||
}
|
||||
|
||||
ext {
|
||||
|
@ -30,15 +26,10 @@ ext {
|
|||
}
|
||||
|
||||
subprojects {
|
||||
apply from: rootProject.file('gradle/ide/idea.gradle')
|
||||
apply from: rootProject.file('gradle/repositories/maven.gradle')
|
||||
apply from: rootProject.file('gradle/compile/java.gradle')
|
||||
apply from: rootProject.file('gradle/test/junit5.gradle')
|
||||
apply from: rootProject.file('gradle/quality/checkstyle.gradle')
|
||||
apply from: rootProject.file('gradle/quality/pmd.gradle')
|
||||
apply from: rootProject.file('gradle/quality/spotbugs.gradle')
|
||||
apply from: rootProject.file('gradle/publish/maven.gradle')
|
||||
}
|
||||
apply from: rootProject.file('gradle/publish/sonatype.gradle')
|
||||
apply from: rootProject.file('gradle/publish/forgejo.gradle')
|
||||
apply from: rootProject.file('gradle/quality/cyclonedx.gradle')
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
group = org.xbib.graphics
|
||||
name = graphics
|
||||
version = 4.5.3
|
||||
|
||||
org.gradle.warning.mode = ALL
|
||||
version = 5.7.0
|
||||
|
|
|
@ -2,21 +2,14 @@
|
|||
apply plugin: 'java-library'
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
}
|
||||
modularity.inferModulePath.set(true)
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
compileJava {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
compileTestJava {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes('Implementation-Version': project.version)
|
||||
|
@ -24,6 +17,8 @@ jar {
|
|||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.fork = true
|
||||
options.forkOptions.jvmArgs += ['-Duser.language=en','-Duser.country=US']
|
||||
options.compilerArgs.add('-Xlint:all,-exports')
|
||||
options.encoding = 'UTF-8'
|
||||
}
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
maven {
|
||||
//url 'https://www.dcm4che.org/maven2/'
|
||||
url 'https://maven.scijava.org/content/repositories/public/'
|
||||
}
|
||||
maven {
|
||||
url 'https://raw.githubusercontent.com/nroduit/mvn-repo/master/'
|
||||
}
|
||||
}
|
||||
|
|
33
gradle/test/junit4.gradle
Normal file
33
gradle/test/junit4.gradle
Normal file
|
@ -0,0 +1,33 @@
|
|||
dependencies {
|
||||
testImplementation testLibs.junit.jupiter.api
|
||||
testImplementation testLibs.junit.jupiter.params
|
||||
testImplementation testLibs.hamcrest
|
||||
testRuntimeOnly testLibs.junit.jupiter.engine
|
||||
testRuntimeOnly testLibs.junit.jupiter.platform.launcher
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
failFast = false
|
||||
environment 'TMPDIR', '/var/tmp/gs'
|
||||
file('/var/tmp/gs').mkdirs()
|
||||
systemProperty 'java.awt.headless', 'true'
|
||||
systemProperty 'java.io.tmpdir', '/var/tmp/'
|
||||
systemProperty 'pdfbox.fontcache', '/var/tmp/pdfbox'
|
||||
systemProperty 'jna.tmpdir', '/var/tmp/'
|
||||
systemProperty 'jna.debug', 'true'
|
||||
systemProperty 'java.util.logging.config.file', 'src/test/resources/logging.properties'
|
||||
testLogging {
|
||||
events 'STARTED', 'PASSED', 'FAILED', 'SKIPPED'
|
||||
showStandardStreams = true
|
||||
}
|
||||
afterSuite { desc, result ->
|
||||
if (!desc.parent) {
|
||||
println "\nTest result: ${result.resultType}"
|
||||
println "Test summary: ${result.testCount} tests, " +
|
||||
"${result.successfulTestCount} succeeded, " +
|
||||
"${result.failedTestCount} failed, " +
|
||||
"${result.skippedTestCount} skipped"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
dependencies {
|
||||
testImplementation libs.junit.jupiter.api
|
||||
testImplementation libs.junit.jupiter.params
|
||||
testImplementation libs.hamcrest
|
||||
testRuntimeOnly libs.junit.jupiter.engine
|
||||
testImplementation testLibs.junit.jupiter.api
|
||||
testImplementation testLibs.junit.jupiter.params
|
||||
testImplementation testLibs.hamcrest
|
||||
testRuntimeOnly testLibs.junit.jupiter.engine
|
||||
testRuntimeOnly testLibs.junit.jupiter.platform.launcher
|
||||
}
|
||||
|
||||
test {
|
||||
|
@ -12,6 +13,7 @@ test {
|
|||
file('/var/tmp/gs').mkdirs()
|
||||
systemProperty 'java.awt.headless', 'true'
|
||||
systemProperty 'java.io.tmpdir', '/var/tmp/'
|
||||
systemProperty 'pdfbox.fontcache', '/var/tmp/pdfbox'
|
||||
systemProperty 'jna.tmpdir', '/var/tmp/'
|
||||
systemProperty 'jna.debug', 'true'
|
||||
systemProperty 'java.util.logging.config.file', 'src/test/resources/logging.properties'
|
||||
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,5 +1,7 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
35
gradlew
vendored
35
gradlew
vendored
|
@ -55,7 +55,7 @@
|
|||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
|
@ -80,13 +80,11 @@ do
|
|||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
@ -133,22 +131,29 @@ location of your Java installation."
|
|||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
|
@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then
|
|||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
|
|
21
gradlew.bat
vendored
21
gradlew.bat
vendored
|
@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal
|
|||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
|
@ -42,11 +43,11 @@ set JAVA_EXE=java.exe
|
|||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
@ -56,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
dependencies {
|
||||
api project(':graphics-zxing')
|
||||
testImplementation project(':graphics-vector')
|
||||
testImplementation project(':graphics-vector-eps')
|
||||
testImplementation project(':graphics-vector-pdf')
|
||||
testImplementation project(':graphics-vector-svg')
|
||||
testImplementation libs.junit.jupiter.params
|
||||
testImplementation libs.junit4
|
||||
testImplementation libs.zxing
|
||||
testImplementation libs.reflections
|
||||
testImplementation testLibs.junit.jupiter.params
|
||||
testImplementation testLibs.junit4
|
||||
testImplementation testLibs.reflections
|
||||
}
|
||||
|
|
|
@ -46,7 +46,8 @@ module org.xbib.graphics.barcode {
|
|||
exports org.xbib.graphics.barcode;
|
||||
exports org.xbib.graphics.barcode.util;
|
||||
exports org.xbib.graphics.barcode.render;
|
||||
requires transitive java.desktop;
|
||||
requires java.desktop;
|
||||
requires org.xbib.graphics.zxing;
|
||||
provides SymbolProvider with
|
||||
AustraliaPost.Provider,
|
||||
AztecCode.Provider,
|
||||
|
|
|
@ -132,6 +132,8 @@ public class QrCode extends AbstractSymbol {
|
|||
private int inputLength;
|
||||
private EccMode preferredEccLevel = EccMode.L;
|
||||
|
||||
private int autosize;
|
||||
|
||||
/**
|
||||
* Sets the preferred symbol size. This value may be ignored if the data
|
||||
* string is too large to fit into the specified symbol. Input values
|
||||
|
@ -402,7 +404,6 @@ public class QrCode extends AbstractSymbol {
|
|||
int est_binlen;
|
||||
EccMode ecc_level;
|
||||
int max_cw;
|
||||
int autosize;
|
||||
int targetCwCount, version, blocks;
|
||||
int size;
|
||||
int bitmask;
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package org.xbib.graphics.barcode.render;
|
||||
|
||||
import org.xbib.graphics.zxing.BarcodeFormat;
|
||||
import org.xbib.graphics.zxing.MultiFormatWriter;
|
||||
import org.xbib.graphics.zxing.WriterException;
|
||||
import org.xbib.graphics.zxing.common.BitMatrix;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class Code39Writer {
|
||||
|
||||
public Code39Writer() {
|
||||
}
|
||||
|
||||
public void write(String content, Path path, String format, int width, int height)
|
||||
throws IOException {
|
||||
try {
|
||||
BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.CODE_39, width, height);
|
||||
MatrixToImageWriter.writeToPath(matrix, format, path);
|
||||
} catch (WriterException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(String content, OutputStream outputStream, String format, int width, int height)
|
||||
throws IOException {
|
||||
try {
|
||||
BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.CODE_39, width, height);
|
||||
MatrixToImageWriter.writeToStream(matrix, format, outputStream);
|
||||
} catch (WriterException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public BufferedImage write(String content, int width, int height)
|
||||
throws IOException {
|
||||
try {
|
||||
BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.CODE_39, width, height);
|
||||
return MatrixToImageWriter.toBufferedImage(matrix);
|
||||
} catch (WriterException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package org.xbib.graphics.barcode.render;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* Encapsulates custom configuration used in methods of {@link MatrixToImageWriter}.
|
||||
*/
|
||||
public final class MatrixToImageConfig {
|
||||
|
||||
public static final int BLACK = 0xFF000000;
|
||||
public static final int WHITE = 0xFFFFFFFF;
|
||||
|
||||
private final int onColor;
|
||||
private final int offColor;
|
||||
|
||||
/**
|
||||
* Creates a default config with on color {@link #BLACK} and off color {@link #WHITE}, generating normal
|
||||
* black-on-white barcodes.
|
||||
*/
|
||||
public MatrixToImageConfig() {
|
||||
this(BLACK, WHITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param onColor pixel on color, specified as an ARGB value as an int
|
||||
* @param offColor pixel off color, specified as an ARGB value as an int
|
||||
*/
|
||||
public MatrixToImageConfig(int onColor, int offColor) {
|
||||
this.onColor = onColor;
|
||||
this.offColor = offColor;
|
||||
}
|
||||
|
||||
public int getPixelOnColor() {
|
||||
return onColor;
|
||||
}
|
||||
|
||||
public int getPixelOffColor() {
|
||||
return offColor;
|
||||
}
|
||||
|
||||
int getBufferedImageColorModel() {
|
||||
if (onColor == BLACK && offColor == WHITE) {
|
||||
// Use faster BINARY if colors match default
|
||||
return BufferedImage.TYPE_BYTE_BINARY;
|
||||
}
|
||||
if (hasTransparency(onColor) || hasTransparency(offColor)) {
|
||||
// Use ARGB representation if colors specify non-opaque alpha
|
||||
return BufferedImage.TYPE_INT_ARGB;
|
||||
}
|
||||
// Default otherwise to RGB representation with ignored alpha channel
|
||||
return BufferedImage.TYPE_INT_RGB;
|
||||
}
|
||||
|
||||
private static boolean hasTransparency(int argb) {
|
||||
return (argb & 0xFF000000) != 0xFF000000;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
package org.xbib.graphics.barcode.render;
|
||||
|
||||
import org.xbib.graphics.zxing.common.BitArray;
|
||||
import org.xbib.graphics.zxing.common.BitMatrix;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.io.File;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Writes a {@link BitMatrix} to {@link BufferedImage},
|
||||
* file or stream. Provided here instead of core since it depends on
|
||||
* Java SE libraries.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class MatrixToImageWriter {
|
||||
|
||||
private static final MatrixToImageConfig DEFAULT_CONFIG = new MatrixToImageConfig();
|
||||
|
||||
private MatrixToImageWriter() {}
|
||||
|
||||
/**
|
||||
* Renders a {@link BitMatrix} as an image, where "false" bits are rendered
|
||||
* as white, and "true" bits are rendered as black. Uses default configuration.
|
||||
*
|
||||
* @param matrix {@link BitMatrix} to write
|
||||
* @return {@link BufferedImage} representation of the input
|
||||
*/
|
||||
public static BufferedImage toBufferedImage(BitMatrix matrix) {
|
||||
return toBufferedImage(matrix, DEFAULT_CONFIG);
|
||||
}
|
||||
|
||||
/**
|
||||
* As {@link #toBufferedImage(BitMatrix)}, but allows customization of the output.
|
||||
*
|
||||
* @param matrix {@link BitMatrix} to write
|
||||
* @param config output configuration
|
||||
* @return {@link BufferedImage} representation of the input
|
||||
*/
|
||||
public static BufferedImage toBufferedImage(BitMatrix matrix, MatrixToImageConfig config) {
|
||||
int width = matrix.getWidth();
|
||||
int height = matrix.getHeight();
|
||||
BufferedImage image = new BufferedImage(width, height, config.getBufferedImageColorModel());
|
||||
int onColor = config.getPixelOnColor();
|
||||
int offColor = config.getPixelOffColor();
|
||||
int[] rowPixels = new int[width];
|
||||
BitArray row = new BitArray(width);
|
||||
for (int y = 0; y < height; y++) {
|
||||
row = matrix.getRow(y, row);
|
||||
for (int x = 0; x < width; x++) {
|
||||
rowPixels[x] = row.get(x) ? onColor : offColor;
|
||||
}
|
||||
image.setRGB(0, y, width, 1, rowPixels, 0, width);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param matrix {@link BitMatrix} to write
|
||||
* @param format image format
|
||||
* @param file file {@link File} to write image to
|
||||
* @throws IOException if writes to the file fail
|
||||
* @deprecated use {@link #writeToPath(BitMatrix, String, Path)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static void writeToFile(BitMatrix matrix, String format, File file) throws IOException {
|
||||
writeToPath(matrix, format, file.toPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a {@link BitMatrix} to a file with default configuration.
|
||||
*
|
||||
* @param matrix {@link BitMatrix} to write
|
||||
* @param format image format
|
||||
* @param file file {@link Path} to write image to
|
||||
* @throws IOException if writes to the stream fail
|
||||
* @see #toBufferedImage(BitMatrix)
|
||||
*/
|
||||
public static void writeToPath(BitMatrix matrix, String format, Path file) throws IOException {
|
||||
writeToPath(matrix, format, file, DEFAULT_CONFIG);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param matrix {@link BitMatrix} to write
|
||||
* @param format image format
|
||||
* @param file file {@link File} to write image to
|
||||
* @param config output configuration
|
||||
* @throws IOException if writes to the file fail
|
||||
* @deprecated use {@link #writeToPath(BitMatrix, String, Path, MatrixToImageConfig)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static void writeToFile(BitMatrix matrix, String format, File file, MatrixToImageConfig config)
|
||||
throws IOException {
|
||||
writeToPath(matrix, format, file.toPath(), config);
|
||||
}
|
||||
|
||||
/**
|
||||
* As {@link #writeToPath(BitMatrix, String, Path)}, but allows customization of the output.
|
||||
*
|
||||
* @param matrix {@link BitMatrix} to write
|
||||
* @param format image format
|
||||
* @param file file {@link Path} to write image to
|
||||
* @param config output configuration
|
||||
* @throws IOException if writes to the file fail
|
||||
*/
|
||||
public static void writeToPath(BitMatrix matrix, String format, Path file, MatrixToImageConfig config)
|
||||
throws IOException {
|
||||
BufferedImage image = toBufferedImage(matrix, config);
|
||||
if (!ImageIO.write(image, format, file.toFile())) {
|
||||
throw new IOException("Could not write an image of format " + format + " to " + file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a {@link BitMatrix} to a stream with default configuration.
|
||||
*
|
||||
* @param matrix {@link BitMatrix} to write
|
||||
* @param format image format
|
||||
* @param stream {@link OutputStream} to write image to
|
||||
* @throws IOException if writes to the stream fail
|
||||
* @see #toBufferedImage(BitMatrix)
|
||||
*/
|
||||
public static void writeToStream(BitMatrix matrix, String format, OutputStream stream) throws IOException {
|
||||
writeToStream(matrix, format, stream, DEFAULT_CONFIG);
|
||||
}
|
||||
|
||||
/**
|
||||
* As {@link #writeToStream(BitMatrix, String, OutputStream)}, but allows customization of the output.
|
||||
*
|
||||
* @param matrix {@link BitMatrix} to write
|
||||
* @param format image format
|
||||
* @param stream {@link OutputStream} to write image to
|
||||
* @param config output configuration
|
||||
* @throws IOException if writes to the stream fail
|
||||
*/
|
||||
public static void writeToStream(BitMatrix matrix, String format, OutputStream stream, MatrixToImageConfig config)
|
||||
throws IOException {
|
||||
BufferedImage image = toBufferedImage(matrix, config);
|
||||
if (!ImageIO.write(image, format, stream)) {
|
||||
throw new IOException("Could not write an image of format " + format);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package org.xbib.graphics.barcode.render;
|
||||
|
||||
import org.xbib.graphics.zxing.BarcodeFormat;
|
||||
import org.xbib.graphics.zxing.MultiFormatWriter;
|
||||
import org.xbib.graphics.zxing.NotFoundException;
|
||||
import org.xbib.graphics.zxing.common.BitMatrix;
|
||||
|
||||
import org.xbib.graphics.zxing.WriterException;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class QRCodeWriter {
|
||||
|
||||
public QRCodeWriter() {
|
||||
}
|
||||
|
||||
public void write(String content, Path path, String format, int width, int height)
|
||||
throws IOException {
|
||||
try {
|
||||
BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height);
|
||||
MatrixToImageWriter.writeToPath(matrix, format, path);
|
||||
} catch (WriterException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(String content, OutputStream outputStream, String format, int width, int height)
|
||||
throws IOException {
|
||||
try {
|
||||
BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height);
|
||||
MatrixToImageWriter.writeToStream(matrix, format, outputStream);
|
||||
} catch (WriterException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public BufferedImage write(String content, int width, int height)
|
||||
throws IOException {
|
||||
try {
|
||||
BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height);
|
||||
return MatrixToImageWriter.toBufferedImage(matrix);
|
||||
} catch (WriterException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* Copyright 2009 ZXing authors
|
||||
*
|
||||
* Licensed 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.xbib.graphics.barcode;
|
||||
|
||||
import org.xbib.graphics.zxing.LuminanceSource;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.WritableRaster;
|
||||
|
||||
/**
|
||||
* This LuminanceSource implementation is meant for J2SE clients and our blackbox unit tests.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
* @author Sean Owen
|
||||
* @author code@elektrowolle.de (Wolfgang Jung)
|
||||
*/
|
||||
public final class BufferedImageLuminanceSource extends LuminanceSource {
|
||||
|
||||
private static final double MINUS_45_IN_RADIANS = -0.7853981633974483; // Math.toRadians(-45.0)
|
||||
|
||||
private final BufferedImage image;
|
||||
private final int left;
|
||||
private final int top;
|
||||
|
||||
public BufferedImageLuminanceSource(BufferedImage image) {
|
||||
this(image, 0, 0, image.getWidth(), image.getHeight());
|
||||
}
|
||||
|
||||
public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) {
|
||||
super(width, height);
|
||||
|
||||
if (image.getType() == BufferedImage.TYPE_BYTE_GRAY) {
|
||||
this.image = image;
|
||||
} else {
|
||||
int sourceWidth = image.getWidth();
|
||||
int sourceHeight = image.getHeight();
|
||||
if (left + width > sourceWidth || top + height > sourceHeight) {
|
||||
throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
|
||||
}
|
||||
|
||||
this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY);
|
||||
|
||||
WritableRaster raster = this.image.getRaster();
|
||||
int[] buffer = new int[width];
|
||||
for (int y = top; y < top + height; y++) {
|
||||
image.getRGB(left, y, width, 1, buffer, 0, sourceWidth);
|
||||
for (int x = 0; x < width; x++) {
|
||||
int pixel = buffer[x];
|
||||
|
||||
// The color of fully-transparent pixels is irrelevant. They are often, technically, fully-transparent
|
||||
// black (0 alpha, and then 0 RGB). They are often used, of course as the "white" area in a
|
||||
// barcode image. Force any such pixel to be white:
|
||||
if ((pixel & 0xFF000000) == 0) {
|
||||
// white, so we know its luminance is 255
|
||||
buffer[x] = 0xFF;
|
||||
} else {
|
||||
// .299R + 0.587G + 0.114B (YUV/YIQ for PAL and NTSC),
|
||||
// (306*R) >> 10 is approximately equal to R*0.299, and so on.
|
||||
// 0x200 >> 10 is 0.5, it implements rounding.
|
||||
buffer[x] =
|
||||
(306 * ((pixel >> 16) & 0xFF) +
|
||||
601 * ((pixel >> 8) & 0xFF) +
|
||||
117 * (pixel & 0xFF) +
|
||||
0x200) >> 10;
|
||||
}
|
||||
}
|
||||
raster.setPixels(left, y, width, 1, buffer);
|
||||
}
|
||||
|
||||
}
|
||||
this.left = left;
|
||||
this.top = top;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRow(int y, byte[] row) {
|
||||
if (y < 0 || y >= getHeight()) {
|
||||
throw new IllegalArgumentException("Requested row is outside the image: " + y);
|
||||
}
|
||||
int width = getWidth();
|
||||
if (row == null || row.length < width) {
|
||||
row = new byte[width];
|
||||
}
|
||||
// The underlying raster of image consists of bytes with the luminance values
|
||||
image.getRaster().getDataElements(left, top + y, width, 1, row);
|
||||
return row;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getMatrix() {
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
int area = width * height;
|
||||
byte[] matrix = new byte[area];
|
||||
// The underlying raster of image consists of area bytes with the luminance values
|
||||
image.getRaster().getDataElements(left, top, width, height, matrix);
|
||||
return matrix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCropSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuminanceSource crop(int left, int top, int width, int height) {
|
||||
return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is always true, since the image is a gray-scale image.
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
@Override
|
||||
public boolean isRotateSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuminanceSource rotateCounterClockwise() {
|
||||
int sourceWidth = image.getWidth();
|
||||
int sourceHeight = image.getHeight();
|
||||
|
||||
// Rotate 90 degrees counterclockwise.
|
||||
AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);
|
||||
|
||||
// Note width/height are flipped since we are rotating 90 degrees.
|
||||
BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY);
|
||||
|
||||
// Draw the original image into rotated, via transformation
|
||||
Graphics2D g = rotatedImage.createGraphics();
|
||||
g.drawImage(image, transform, null);
|
||||
g.dispose();
|
||||
|
||||
// Maintain the cropped region, but rotate it too.
|
||||
int width = getWidth();
|
||||
return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuminanceSource rotateCounterClockwise45() {
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
|
||||
int oldCenterX = left + width / 2;
|
||||
int oldCenterY = top + height / 2;
|
||||
|
||||
// Rotate 45 degrees counterclockwise.
|
||||
AffineTransform transform = AffineTransform.getRotateInstance(MINUS_45_IN_RADIANS, oldCenterX, oldCenterY);
|
||||
|
||||
int sourceDimension = Math.max(image.getWidth(), image.getHeight());
|
||||
BufferedImage rotatedImage = new BufferedImage(sourceDimension, sourceDimension, BufferedImage.TYPE_BYTE_GRAY);
|
||||
|
||||
// Draw the original image into rotated, via transformation
|
||||
Graphics2D g = rotatedImage.createGraphics();
|
||||
g.drawImage(image, transform, null);
|
||||
g.dispose();
|
||||
|
||||
int halfDimension = Math.max(width, height) / 2;
|
||||
int newLeft = Math.max(0, oldCenterX - halfDimension);
|
||||
int newTop = Math.max(0, oldCenterY - halfDimension);
|
||||
int newRight = Math.min(sourceDimension - 1, oldCenterX + halfDimension);
|
||||
int newBottom = Math.min(sourceDimension - 1, oldCenterY + halfDimension);
|
||||
|
||||
return new BufferedImageLuminanceSource(rotatedImage, newLeft, newTop, newRight - newLeft, newBottom - newTop);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,24 +3,23 @@ package org.xbib.graphics.barcode;
|
|||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
import com.google.zxing.DecodeHintType;
|
||||
import com.google.zxing.FormatException;
|
||||
import com.google.zxing.LuminanceSource;
|
||||
import com.google.zxing.Reader;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
|
||||
import com.google.zxing.common.HybridBinarizer;
|
||||
import com.google.zxing.oned.CodaBarReader;
|
||||
import com.google.zxing.oned.Code39Reader;
|
||||
import com.google.zxing.oned.Code93Reader;
|
||||
import com.google.zxing.oned.EAN13Reader;
|
||||
import com.google.zxing.oned.EAN8Reader;
|
||||
import com.google.zxing.oned.UPCAReader;
|
||||
import com.google.zxing.oned.UPCEReader;
|
||||
import com.google.zxing.pdf417.PDF417Reader;
|
||||
import com.google.zxing.qrcode.QRCodeReader;
|
||||
import org.xbib.graphics.zxing.BinaryBitmap;
|
||||
import org.xbib.graphics.zxing.DecodeHintType;
|
||||
import org.xbib.graphics.zxing.FormatException;
|
||||
import org.xbib.graphics.zxing.LuminanceSource;
|
||||
import org.xbib.graphics.zxing.Reader;
|
||||
import org.xbib.graphics.zxing.ReaderException;
|
||||
import org.xbib.graphics.zxing.Result;
|
||||
import org.xbib.graphics.zxing.common.HybridBinarizer;
|
||||
import org.xbib.graphics.zxing.oned.CodaBarReader;
|
||||
import org.xbib.graphics.zxing.oned.Code39Reader;
|
||||
import org.xbib.graphics.zxing.oned.Code93Reader;
|
||||
import org.xbib.graphics.zxing.oned.EAN13Reader;
|
||||
import org.xbib.graphics.zxing.oned.EAN8Reader;
|
||||
import org.xbib.graphics.zxing.oned.UPCAReader;
|
||||
import org.xbib.graphics.zxing.oned.UPCEReader;
|
||||
import org.xbib.graphics.zxing.pdf417.PDF417Reader;
|
||||
import org.xbib.graphics.zxing.qrcode.QRCodeReader;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.TestTemplate;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
|
|
@ -4,6 +4,11 @@ import org.junit.jupiter.api.Test;
|
|||
import org.xbib.graphics.barcode.Code3Of9;
|
||||
import org.xbib.graphics.barcode.HumanReadableLocation;
|
||||
import org.xbib.graphics.barcode.render.BarcodeGraphicsRenderer;
|
||||
import org.xbib.graphics.barcode.render.Code39Writer;
|
||||
import org.xbib.graphics.barcode.render.QRCodeWriter;
|
||||
import org.xbib.graphics.zxing.NotFoundException;
|
||||
import org.xbib.graphics.zxing.WriterException;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
|
@ -73,4 +78,13 @@ public class Code39Test {
|
|||
return new BarcodeGraphicsRenderer(g2d, rectangle, scalingFactorX, scalingFactorY,
|
||||
Color.WHITE, Color.BLACK, false, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQrCode() throws IOException, NotFoundException, WriterException {
|
||||
Code39Writer codeWriter = new Code39Writer();
|
||||
try (OutputStream outputStream = Files.newOutputStream(Paths.get("build/code39.png"))) {
|
||||
codeWriter.write("123456789", outputStream, "png", 200, 50);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
package org.xbib.graphics.barcode.output;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.graphics.barcode.QrCode;
|
||||
import org.xbib.graphics.barcode.render.BarcodeGraphicsRenderer;
|
||||
import org.xbib.graphics.barcode.render.QRCodeWriter;
|
||||
import org.xbib.graphics.zxing.NotFoundException;
|
||||
import org.xbib.graphics.zxing.WriterException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class QRCodeTest {
|
||||
|
||||
@Test
|
||||
public void createQRCode() throws IOException {
|
||||
//String content = "IFLA-15: Kostenlimit überschritten, erneute Bestellung, wenn Kosten akzeptiert werden";
|
||||
//String content = "IFLA-16:";
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = 128;
|
||||
int height = 128;
|
||||
QrCode code = new QrCode();
|
||||
code.setBarHeight(height - 2);
|
||||
code.setQuietZoneHorizontal(1);
|
||||
code.setQuietZoneVertical(1);
|
||||
code.setEccMode(QrCode.EccMode.L);
|
||||
//code.setContent(content);
|
||||
double scalingFactor = 5.0d;
|
||||
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
|
||||
BarcodeGraphicsRenderer renderer = createRenderer(bufferedImage, x, y, scalingFactor, scalingFactor);
|
||||
renderer.render(code);
|
||||
renderer.close();
|
||||
try (OutputStream outputStream = Files.newOutputStream(Paths.get("build/qrcode.png"))) {
|
||||
ImageIO.write(bufferedImage, "png", outputStream);
|
||||
}
|
||||
}
|
||||
|
||||
private BarcodeGraphicsRenderer createRenderer(BufferedImage bufferedImage,
|
||||
int x, int y, double scalingFactorX, double scalingFactorY) {
|
||||
Graphics2D g2d = bufferedImage.createGraphics();
|
||||
Rectangle rectangle = new Rectangle(x, y, bufferedImage.getWidth(), bufferedImage.getHeight());
|
||||
return new BarcodeGraphicsRenderer(g2d, rectangle, scalingFactorX, scalingFactorY,
|
||||
Color.WHITE, Color.BLACK, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Easy way by using zxing.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testQrCode() throws IOException {
|
||||
QRCodeWriter qrCodeWriter = new QRCodeWriter();
|
||||
try (OutputStream outputStream = Files.newOutputStream(Paths.get("build/de-361-ifla-20.png"))) {
|
||||
qrCodeWriter.write("DE-361: IFLA-20: Art der gewünschten Lieferung nicht möglich",
|
||||
outputStream, "png", 200, 200);
|
||||
}
|
||||
}
|
||||
}
|
8
graphics-barcode/src/test/resources/logging.properties
Normal file
8
graphics-barcode/src/test/resources/logging.properties
Normal file
|
@ -0,0 +1,8 @@
|
|||
handlers=java.util.logging.ConsoleHandler
|
||||
.level=ALL
|
||||
java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$-7s [%3$s] %5$s %6$s%n
|
||||
java.util.logging.ConsoleHandler.level=ALL
|
||||
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
|
||||
org.apache.fontbox.ttf.level=OFF
|
||||
org.apache.fontbox.util.autodetect.FontFileFinder.level=OFF
|
||||
org.apache.pdfbox.pdmodel.font.FileSystemFontProvider.level=OFF
|
|
@ -17,5 +17,5 @@ module org.xbib.graphics.chart {
|
|||
requires org.xbib.graphics.io.vector.eps;
|
||||
requires org.xbib.graphics.io.vector.pdf;
|
||||
requires org.xbib.graphics.io.vector.svg;
|
||||
requires transitive java.desktop;
|
||||
requires java.desktop;
|
||||
}
|
||||
|
|
8
graphics-chart/src/test/resources/logging.properties
Normal file
8
graphics-chart/src/test/resources/logging.properties
Normal file
|
@ -0,0 +1,8 @@
|
|||
handlers=java.util.logging.ConsoleHandler
|
||||
.level=ALL
|
||||
java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$-7s [%3$s] %5$s %6$s%n
|
||||
java.util.logging.ConsoleHandler.level=ALL
|
||||
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
|
||||
org.apache.fontbox.ttf.level=OFF
|
||||
org.apache.fontbox.util.autodetect.FontFileFinder.level=OFF
|
||||
org.apache.pdfbox.pdmodel.font.FileSystemFontProvider.level=OFF
|
3
graphics-fonts-arabic/build.gradle
Normal file
3
graphics-fonts-arabic/build.gradle
Normal file
|
@ -0,0 +1,3 @@
|
|||
dependencies {
|
||||
api project(':graphics-fonts')
|
||||
}
|
9
graphics-fonts-arabic/src/main/java/module-info.java
Normal file
9
graphics-fonts-arabic/src/main/java/module-info.java
Normal file
|
@ -0,0 +1,9 @@
|
|||
import org.xbib.graphics.fonts.FontEmbedder;
|
||||
import org.xbib.graphics.fonts.arabic.ArabicFontEmbedder;
|
||||
|
||||
module org.xbib.graphics.fonts.arabic {
|
||||
requires org.xbib.graphics.fonts;
|
||||
requires org.apache.pdfbox;
|
||||
exports org.xbib.graphics.fonts.arabic;
|
||||
provides FontEmbedder with ArabicFontEmbedder;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package org.xbib.graphics.fonts.arabic;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.xbib.graphics.fonts.TrueTypeEmbedder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ArabicFontEmbedder extends TrueTypeEmbedder {
|
||||
|
||||
public ArabicFontEmbedder() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlias() {
|
||||
return "notosansarabic";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void embed(PDDocument pdDocument) throws IOException {
|
||||
embed(pdDocument, getAlias(),
|
||||
"NotoSansArabic-Regular.ttf",
|
||||
"NotoSansArabic-Bold.ttf",
|
||||
"NotoSansArabic-Regular.ttf",
|
||||
"NotoSansArabic-Bold.ttf");
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.xbib.graphics.fonts.arabic.ArabicFontEmbedder
|
Binary file not shown.
Binary file not shown.
45
graphics-fonts-cjk/Google-Noto-LICENSE.txt
Normal file
45
graphics-fonts-cjk/Google-Noto-LICENSE.txt
Normal file
|
@ -0,0 +1,45 @@
|
|||
SIL Open Font License
|
||||
|
||||
Copyright 2012 Google Inc. All Rights Reserved.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
|
||||
|
||||
—————————————————————————————-
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
—————————————————————————————-
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
“Font Software” refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
|
||||
|
||||
“Reserved Font Name” refers to any names specified as such after the copyright statement(s).
|
||||
|
||||
“Original Version” refers to the collection of Font Software components as distributed by the Copyright Holder(s).
|
||||
|
||||
“Modified Version” refers to any derivative made by adding to, deleting, or substituting—in part or in whole—any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
|
||||
|
||||
“Author” refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|
3
graphics-fonts-cjk/build.gradle
Normal file
3
graphics-fonts-cjk/build.gradle
Normal file
|
@ -0,0 +1,3 @@
|
|||
dependencies {
|
||||
api project(':graphics-fonts')
|
||||
}
|
9
graphics-fonts-cjk/src/main/java/module-info.java
Normal file
9
graphics-fonts-cjk/src/main/java/module-info.java
Normal file
|
@ -0,0 +1,9 @@
|
|||
import org.xbib.graphics.fonts.FontEmbedder;
|
||||
import org.xbib.graphics.fonts.cjk.CJKFontEmbedder;
|
||||
|
||||
module org.xbib.graphics.fonts.cjk {
|
||||
requires org.xbib.graphics.fonts;
|
||||
requires org.apache.pdfbox;
|
||||
exports org.xbib.graphics.fonts.cjk;
|
||||
provides FontEmbedder with CJKFontEmbedder;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package org.xbib.graphics.fonts.cjk;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.xbib.graphics.fonts.TrueTypeEmbedder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class CJKFontEmbedder extends TrueTypeEmbedder {
|
||||
|
||||
public CJKFontEmbedder() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlias() {
|
||||
return "notosanscjksc";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void embed(PDDocument pdDocument) throws IOException {
|
||||
embed(pdDocument, getAlias(),
|
||||
"NotoSansCJKsc-Regular.ttf",
|
||||
"NotoSansCJKsc-Bold.ttf",
|
||||
"NotoSansCJKsc-Italic.ttf",
|
||||
"NotoSansCJKsc-BoldItalic.ttf");
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.xbib.graphics.fonts.cjk.CJKFontEmbedder
|
45
graphics-fonts-cyrillic/Google-Noto-LICENSE.txt
Normal file
45
graphics-fonts-cyrillic/Google-Noto-LICENSE.txt
Normal file
|
@ -0,0 +1,45 @@
|
|||
SIL Open Font License
|
||||
|
||||
Copyright 2012 Google Inc. All Rights Reserved.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
|
||||
|
||||
—————————————————————————————-
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
—————————————————————————————-
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
“Font Software” refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
|
||||
|
||||
“Reserved Font Name” refers to any names specified as such after the copyright statement(s).
|
||||
|
||||
“Original Version” refers to the collection of Font Software components as distributed by the Copyright Holder(s).
|
||||
|
||||
“Modified Version” refers to any derivative made by adding to, deleting, or substituting—in part or in whole—any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
|
||||
|
||||
“Author” refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|
2
graphics-fonts-cyrillic/NOTICE.txt
Normal file
2
graphics-fonts-cyrillic/NOTICE.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
Identical to Noto Latin fonts. There is no need to add cyrillic Noto fonst if the latin Noto fonts are already added.
|
3
graphics-fonts-cyrillic/build.gradle
Normal file
3
graphics-fonts-cyrillic/build.gradle
Normal file
|
@ -0,0 +1,3 @@
|
|||
dependencies {
|
||||
api project(':graphics-fonts')
|
||||
}
|
8
graphics-fonts-cyrillic/src/main/java/module-info.java
Normal file
8
graphics-fonts-cyrillic/src/main/java/module-info.java
Normal file
|
@ -0,0 +1,8 @@
|
|||
import org.xbib.graphics.fonts.FontEmbedder;
|
||||
import org.xbib.graphics.fonts.cyrillic.CyrillicFontEmbedder;
|
||||
|
||||
module org.xbib.graphics.fonts.cyrillic {
|
||||
requires org.xbib.graphics.fonts;
|
||||
requires org.apache.pdfbox;
|
||||
provides FontEmbedder with CyrillicFontEmbedder;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package org.xbib.graphics.fonts.cyrillic;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.xbib.graphics.fonts.TrueTypeEmbedder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class CyrillicFontEmbedder extends TrueTypeEmbedder {
|
||||
|
||||
public CyrillicFontEmbedder() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlias() {
|
||||
return "notosanscyrillic";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void embed(PDDocument pdDocument) throws IOException {
|
||||
embed(pdDocument, getAlias(),
|
||||
"NotoSans-Regular.ttf",
|
||||
"NotoSans-Bold.ttf",
|
||||
"NotoSans-Italic.ttf",
|
||||
"NotoSans-BoldItalic.ttf");
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.xbib.graphics.fonts.cyrillic.CyrillicFontEmbedder
|
45
graphics-fonts-hebrew/Google-Noto-LICENSE.txt
Normal file
45
graphics-fonts-hebrew/Google-Noto-LICENSE.txt
Normal file
|
@ -0,0 +1,45 @@
|
|||
SIL Open Font License
|
||||
|
||||
Copyright 2012 Google Inc. All Rights Reserved.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
|
||||
|
||||
—————————————————————————————-
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
—————————————————————————————-
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
“Font Software” refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
|
||||
|
||||
“Reserved Font Name” refers to any names specified as such after the copyright statement(s).
|
||||
|
||||
“Original Version” refers to the collection of Font Software components as distributed by the Copyright Holder(s).
|
||||
|
||||
“Modified Version” refers to any derivative made by adding to, deleting, or substituting—in part or in whole—any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
|
||||
|
||||
“Author” refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|
3
graphics-fonts-hebrew/build.gradle
Normal file
3
graphics-fonts-hebrew/build.gradle
Normal file
|
@ -0,0 +1,3 @@
|
|||
dependencies {
|
||||
api project(':graphics-fonts')
|
||||
}
|
8
graphics-fonts-hebrew/src/main/java/module-info.java
Normal file
8
graphics-fonts-hebrew/src/main/java/module-info.java
Normal file
|
@ -0,0 +1,8 @@
|
|||
import org.xbib.graphics.fonts.FontEmbedder;
|
||||
import org.xbib.graphics.fonts.hebrew.HebrewFontEmbedder;
|
||||
|
||||
module org.xbib.graphics.fonts.hebrew {
|
||||
requires org.xbib.graphics.fonts;
|
||||
requires org.apache.pdfbox;
|
||||
provides FontEmbedder with HebrewFontEmbedder;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package org.xbib.graphics.fonts.hebrew;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.xbib.graphics.fonts.TrueTypeEmbedder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class HebrewFontEmbedder extends TrueTypeEmbedder {
|
||||
|
||||
public HebrewFontEmbedder() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlias() {
|
||||
return "notosanshebrew";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void embed(PDDocument pdDocument) throws IOException {
|
||||
embed(pdDocument, getAlias(),
|
||||
"NotoSansHebrew-Regular.ttf",
|
||||
"NotoSansHebrew-Bold.ttf",
|
||||
"NotoSansHebrew-Regular.ttf",
|
||||
"NotoSansHebrew-Bold.ttf");
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.xbib.graphics.fonts.hebrew.HebrewFontEmbedder
|
45
graphics-fonts-latin/Google-Noto-LICENSE.txt
Normal file
45
graphics-fonts-latin/Google-Noto-LICENSE.txt
Normal file
|
@ -0,0 +1,45 @@
|
|||
SIL Open Font License
|
||||
|
||||
Copyright 2012 Google Inc. All Rights Reserved.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
|
||||
|
||||
—————————————————————————————-
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
—————————————————————————————-
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
“Font Software” refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
|
||||
|
||||
“Reserved Font Name” refers to any names specified as such after the copyright statement(s).
|
||||
|
||||
“Original Version” refers to the collection of Font Software components as distributed by the Copyright Holder(s).
|
||||
|
||||
“Modified Version” refers to any derivative made by adding to, deleting, or substituting—in part or in whole—any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
|
||||
|
||||
“Author” refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|
3
graphics-fonts-latin/build.gradle
Normal file
3
graphics-fonts-latin/build.gradle
Normal file
|
@ -0,0 +1,3 @@
|
|||
dependencies {
|
||||
api project(':graphics-fonts')
|
||||
}
|
12
graphics-fonts-latin/src/main/java/module-info.java
Normal file
12
graphics-fonts-latin/src/main/java/module-info.java
Normal file
|
@ -0,0 +1,12 @@
|
|||
import org.xbib.graphics.fonts.FontEmbedder;
|
||||
import org.xbib.graphics.fonts.latin.NotoSansFontEmbedder;
|
||||
import org.xbib.graphics.fonts.latin.OpenSansFontEmbedder;
|
||||
import org.xbib.graphics.fonts.latin.SourceSansFontEmbedder;
|
||||
|
||||
module org.xbib.graphics.fonts.latin {
|
||||
requires org.xbib.graphics.fonts;
|
||||
requires org.apache.pdfbox;
|
||||
provides FontEmbedder with NotoSansFontEmbedder,
|
||||
OpenSansFontEmbedder,
|
||||
SourceSansFontEmbedder;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package org.xbib.graphics.fonts.latin;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.xbib.graphics.fonts.TrueTypeEmbedder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class NotoSansFontEmbedder extends TrueTypeEmbedder {
|
||||
|
||||
public NotoSansFontEmbedder() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlias() {
|
||||
return "notosans";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void embed(PDDocument pdDocument) throws IOException {
|
||||
embed(pdDocument, getAlias(),
|
||||
"NotoSans-Regular.ttf",
|
||||
"NotoSans-Bold.ttf",
|
||||
"NotoSans-Italic.ttf",
|
||||
"NotoSans-BoldItalic.ttf");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package org.xbib.graphics.fonts.latin;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.xbib.graphics.fonts.TrueTypeEmbedder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class OpenSansFontEmbedder extends TrueTypeEmbedder {
|
||||
|
||||
public OpenSansFontEmbedder() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlias() {
|
||||
return "opensans";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void embed(PDDocument pdDocument) throws IOException {
|
||||
embed(pdDocument, getAlias(),
|
||||
"OpenSans-Regular.ttf",
|
||||
"OpenSans-Bold.ttf",
|
||||
"OpenSans-Italic.ttf",
|
||||
"OpenSans-BoldItalic.ttf");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package org.xbib.graphics.fonts.latin;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.xbib.graphics.fonts.TrueTypeEmbedder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class SourceSansFontEmbedder extends TrueTypeEmbedder {
|
||||
|
||||
public SourceSansFontEmbedder() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlias() {
|
||||
return "sourcesans";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void embed(PDDocument pdDocument) throws IOException {
|
||||
embed(pdDocument, getAlias(), "SourceSans3-Regular.ttf",
|
||||
"SourceSans3-Bold.ttf",
|
||||
"SourceSans3-It.ttf",
|
||||
"SourceSans3-BoldIt.ttf");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
org.xbib.graphics.fonts.latin.NotoSansFontEmbedder
|
||||
org.xbib.graphics.fonts.latin.OpenSansFontEmbedder
|
||||
org.xbib.graphics.fonts.latin.SourceSansFontEmbedder
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,28 @@
|
|||
package org.xbib.graphics.fonts.latin.test;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.graphics.fonts.latin.NotoSansFontEmbedder;
|
||||
import org.xbib.graphics.fonts.latin.OpenSansFontEmbedder;
|
||||
import org.xbib.graphics.fonts.latin.SourceSansFontEmbedder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class LatinEmbedderTest {
|
||||
|
||||
@Test
|
||||
public void testLatin() throws IOException {
|
||||
NotoSansFontEmbedder embedder = new NotoSansFontEmbedder();
|
||||
try (PDDocument document = new PDDocument()) {
|
||||
embedder.embed(document);
|
||||
}
|
||||
OpenSansFontEmbedder openSansFontEmbedder = new OpenSansFontEmbedder();
|
||||
try (PDDocument document = new PDDocument()) {
|
||||
openSansFontEmbedder.embed(document);
|
||||
}
|
||||
SourceSansFontEmbedder sourceSansFontEmbedder = new SourceSansFontEmbedder();
|
||||
try (PDDocument document = new PDDocument()) {
|
||||
sourceSansFontEmbedder.embed(document);
|
||||
}
|
||||
}
|
||||
}
|
3
graphics-fonts/build.gradle
Normal file
3
graphics-fonts/build.gradle
Normal file
|
@ -0,0 +1,3 @@
|
|||
dependencies {
|
||||
api libs.pdfbox
|
||||
}
|
8
graphics-fonts/src/main/java/module-info.java
Normal file
8
graphics-fonts/src/main/java/module-info.java
Normal file
|
@ -0,0 +1,8 @@
|
|||
module org.xbib.graphics.fonts {
|
||||
requires java.logging;
|
||||
requires java.desktop;
|
||||
requires org.apache.fontbox;
|
||||
requires org.apache.pdfbox;
|
||||
requires org.apache.pdfbox.io;
|
||||
exports org.xbib.graphics.fonts;
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package org.xbib.graphics.fonts;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.font.PDFont;
|
||||
import org.apache.pdfbox.pdmodel.font.PDType1Font;
|
||||
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* In order to easy handling with fonts, this enum bundles the
|
||||
* plain/italic/bold/bold-italic variants of the three standard font types
|
||||
* Times, Courier, Helvetica.
|
||||
*/
|
||||
public enum BaseFont implements Font {
|
||||
|
||||
TIMES("times", new PDType1Font(Standard14Fonts.FontName.TIMES_ROMAN), new PDType1Font(Standard14Fonts.FontName.TIMES_BOLD),
|
||||
new PDType1Font(Standard14Fonts.FontName.TIMES_ITALIC), new PDType1Font(Standard14Fonts.FontName.TIMES_BOLD_ITALIC)),
|
||||
|
||||
COURIER("courier", new PDType1Font(Standard14Fonts.FontName.COURIER), new PDType1Font(Standard14Fonts.FontName.COURIER_BOLD),
|
||||
new PDType1Font(Standard14Fonts.FontName.COURIER_OBLIQUE), new PDType1Font(Standard14Fonts.FontName.COURIER_BOLD_OBLIQUE)),
|
||||
|
||||
HELVETICA("helvetica", new PDType1Font(Standard14Fonts.FontName.HELVETICA), new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD),
|
||||
new PDType1Font(Standard14Fonts.FontName.HELVETICA_OBLIQUE), new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD_OBLIQUE));
|
||||
|
||||
private final String alias;
|
||||
|
||||
private final PDType1Font regularFont;
|
||||
|
||||
private final PDType1Font boldFont;
|
||||
|
||||
private final PDType1Font italicFont;
|
||||
|
||||
private final PDType1Font boldItalicFont;
|
||||
|
||||
BaseFont(String alias, PDType1Font regularFont, PDType1Font boldFont, PDType1Font italicFont, PDType1Font boldItalicFont) {
|
||||
this.alias = alias;
|
||||
this.regularFont = regularFont;
|
||||
this.boldFont = boldFont;
|
||||
this.italicFont = italicFont;
|
||||
this.boldItalicFont = boldItalicFont;
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PDFont getRegularFont() {
|
||||
return regularFont;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PDFont getBoldFont() {
|
||||
return boldFont;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PDFont getItalicFont() {
|
||||
return italicFont;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PDFont getBoldItalicFont() {
|
||||
return boldItalicFont;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGlyph(int code) {
|
||||
try {
|
||||
return regularFont.hasGlyph(code);
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRender(String string) {
|
||||
if (string == null) {
|
||||
return false;
|
||||
}
|
||||
String printable = string.replaceAll("\\P{Print}|\\p{Cntrl}|\\p{Space}", "");
|
||||
if (printable.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
return regularFont.getStringWidth(printable) > 0;
|
||||
} catch (IllegalArgumentException | IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package org.xbib.graphics.pdfbox.font;
|
||||
package org.xbib.graphics.fonts;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.font.PDFont;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.xbib.graphics.pdfbox.font;
|
||||
package org.xbib.graphics.fonts;
|
||||
|
||||
import org.apache.fontbox.ttf.TrueTypeCollection;
|
||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||
|
@ -6,7 +6,6 @@ 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.pdfbox.PdfBoxGraphics2D;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.FontFormatException;
|
||||
|
@ -44,8 +43,7 @@ import static org.apache.pdfbox.pdmodel.font.Standard14Fonts.FontName.ZAPF_DINGB
|
|||
|
||||
/**
|
||||
* Default implementation to draw fonts. You can reuse instances of this class
|
||||
* within a PDDocument for more then one {@link PdfBoxGraphics2D}.
|
||||
* Just ensure that you call close after you closed the PDDocument to free any
|
||||
* within a PDDocument. Just ensure that you call close after you closed the PDDocument to free any
|
||||
* temporary files.
|
||||
*/
|
||||
public class DefaultFontDrawer implements FontDrawer, Closeable {
|
||||
|
@ -306,17 +304,22 @@ public class DefaultFontDrawer implements FontDrawer, Closeable {
|
|||
if (windir == null) {
|
||||
windir = javaFontDir;
|
||||
}
|
||||
File[] paths = new File[]{new File(new File(windir), "fonts"),
|
||||
File[] paths = new File[] {
|
||||
new File(new File(windir), "fonts"),
|
||||
new File(System.getProperty("user.dir", ".")),
|
||||
// Mac Fonts
|
||||
new File("/Library/Fonts"), new File("/System/Library/Fonts/Supplemental/"),
|
||||
new File("/Library/Fonts"),
|
||||
new File("/System/Library/Fonts/Supplemental/"),
|
||||
// Unix Fonts
|
||||
new File("/usr/share/fonts/truetype"), new File("/usr/share/fonts/truetype/dejavu"),
|
||||
new File("/usr/share/fonts/truetype"),
|
||||
new File("/usr/share/fonts/truetype/dejavu"),
|
||||
new File("/usr/share/fonts/truetype/liberation"),
|
||||
new File("/usr/share/fonts/truetype/noto"), new File(javaFontDir)};
|
||||
for (String fontFileName : new String[]{"LucidaSansRegular.ttf", "arial.ttf", "Arial.ttf",
|
||||
new File("/usr/share/fonts/truetype/noto"),
|
||||
new File(javaFontDir)
|
||||
};
|
||||
for (String fontFileName : List.of("LucidaSansRegular.ttf", "arial.ttf", "Arial.ttf",
|
||||
"DejaVuSans.ttf", "LiberationMono-Regular.ttf", "NotoSerif-Regular.ttf",
|
||||
"Arial Unicode.ttf", "Tahoma.ttf"}) {
|
||||
"Arial Unicode.ttf", "Tahoma.ttf")) {
|
||||
for (File path : paths) {
|
||||
File arialFile = new File(path, fontFileName);
|
||||
if (arialFile.exists()) {
|
|
@ -1,4 +1,4 @@
|
|||
package org.xbib.graphics.pdfbox.font;
|
||||
package org.xbib.graphics.fonts;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.font.PDFont;
|
||||
import java.awt.Font;
|
|
@ -1,11 +1,11 @@
|
|||
package org.xbib.graphics.pdfbox.layout.font;
|
||||
package org.xbib.graphics.fonts;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.font.PDFont;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface Font {
|
||||
|
||||
String getAlias();
|
||||
|
||||
PDFont getRegularFont();
|
||||
|
||||
PDFont getBoldFont();
|
||||
|
@ -16,5 +16,5 @@ public interface Font {
|
|||
|
||||
boolean hasGlyph(int code);
|
||||
|
||||
boolean canWrite(String string);
|
||||
boolean canRender(String string);
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
package org.xbib.graphics.pdfbox.layout.font;
|
||||
package org.xbib.graphics.fonts;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.font.PDFont;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
|
@ -10,7 +10,7 @@ import java.util.Objects;
|
|||
*/
|
||||
public class FontDescriptor {
|
||||
|
||||
private final List<Font> fonts;
|
||||
private final Collection<Font> fonts;
|
||||
|
||||
private float size;
|
||||
|
||||
|
@ -20,19 +20,23 @@ public class FontDescriptor {
|
|||
|
||||
private boolean italic;
|
||||
|
||||
public FontDescriptor(List<Font> fonts, float size) {
|
||||
public FontDescriptor(Collection<Font> fonts, float size) {
|
||||
this(fonts, size, false, false);
|
||||
}
|
||||
|
||||
public FontDescriptor(List<Font> fonts, float size, boolean bold, boolean italic) {
|
||||
public FontDescriptor(Collection<Font> fonts, float size, boolean bold, boolean italic) {
|
||||
this.fonts = fonts;
|
||||
// we do not accept null fonts
|
||||
for (Font font : fonts) {
|
||||
Objects.requireNonNull(font, "no null font allowed");
|
||||
}
|
||||
this.size = size;
|
||||
this.bold = bold;
|
||||
this.italic = italic;
|
||||
this.regular = !bold && !italic;
|
||||
}
|
||||
|
||||
public List<Font> getFonts() {
|
||||
public Collection<Font> getFonts() {
|
||||
return fonts;
|
||||
}
|
||||
|
||||
|
@ -56,7 +60,7 @@ public class FontDescriptor {
|
|||
|
||||
public PDFont getSelectedFont(String text) {
|
||||
for (Font font : fonts) {
|
||||
if (font.canWrite(text)) {
|
||||
if (font.canRender(text)) {
|
||||
if (regular) {
|
||||
return font.getRegularFont();
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package org.xbib.graphics.pdfbox.font;
|
||||
package org.xbib.graphics.fonts;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.FontFormatException;
|
|
@ -1,10 +1,9 @@
|
|||
package org.xbib.graphics.pdfbox.font;
|
||||
package org.xbib.graphics.fonts;
|
||||
|
||||
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.pdfbox.PdfBoxGraphics2D;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics2D;
|
||||
|
@ -59,7 +58,7 @@ public interface FontDrawerEnvironment {
|
|||
FontRenderContext getFontRenderContext();
|
||||
|
||||
/**
|
||||
* @return the bbox of the {@link PdfBoxGraphics2D}
|
||||
* @return the bbox
|
||||
*/
|
||||
PDRectangle getGraphicsBBox();
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package org.xbib.graphics.fonts;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
public interface FontEmbedder {
|
||||
|
||||
String getAlias();
|
||||
|
||||
Collection<Font> getFonts();
|
||||
|
||||
void embed(PDDocument pdDocument) throws IOException;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package org.xbib.graphics.pdfbox.font;
|
||||
package org.xbib.graphics.fonts;
|
||||
|
||||
import java.io.File;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.xbib.graphics.pdfbox.font;
|
||||
package org.xbib.graphics.fonts;
|
||||
|
||||
import java.text.AttributedCharacterIterator;
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
package org.xbib.graphics.fonts;
|
||||
|
||||
import org.apache.fontbox.ttf.TTFParser;
|
||||
import org.apache.fontbox.ttf.TrueTypeFont;
|
||||
import org.apache.pdfbox.io.RandomAccessRead;
|
||||
import org.apache.pdfbox.io.RandomAccessReadBuffer;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.font.PDFont;
|
||||
import org.apache.pdfbox.pdmodel.font.PDType0Font;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class TrueTypeEmbedder implements FontEmbedder {
|
||||
|
||||
private final Map<String, Font> fonts = new LinkedHashMap<>();
|
||||
|
||||
public TrueTypeEmbedder() {
|
||||
}
|
||||
|
||||
public void embed(PDDocument pdDocument,
|
||||
final String name,
|
||||
final String regularFontResource,
|
||||
final String boldFontResource,
|
||||
final String italicsFontResource,
|
||||
final String boldItalicsFontResource) throws IOException {
|
||||
if (fonts.containsKey(name)) {
|
||||
return;
|
||||
}
|
||||
final PDType0Font regularFont = embedTrueTypeFont(pdDocument, regularFontResource);
|
||||
final PDType0Font boldFont = embedTrueTypeFont(pdDocument, boldFontResource);
|
||||
final PDType0Font italicsFont = embedTrueTypeFont(pdDocument, italicsFontResource);
|
||||
final PDType0Font boldItalicsFont = embedTrueTypeFont(pdDocument, boldItalicsFontResource);
|
||||
fonts.putIfAbsent(name, new Font() {
|
||||
|
||||
@Override
|
||||
public String getAlias() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PDFont getRegularFont() {
|
||||
return regularFont;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PDFont getBoldFont() {
|
||||
return boldFont;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PDFont getItalicFont() {
|
||||
return italicsFont;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PDFont getBoldItalicFont() {
|
||||
return boldItalicsFont;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGlyph(int code) {
|
||||
try {
|
||||
return regularFont.hasGlyph(code);
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRender(String string) {
|
||||
try {
|
||||
return regularFont.getStringWidth(string) > 0;
|
||||
} catch (IOException | IllegalArgumentException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Font> getFonts() {
|
||||
return fonts.values();
|
||||
}
|
||||
|
||||
private PDType0Font embedTrueTypeFont(PDDocument pdDocument, String resourceName) throws IOException {
|
||||
InputStream inputStream = getClass().getResourceAsStream(resourceName);
|
||||
TTFParser ttfParser = new TTFParser();
|
||||
RandomAccessRead randomAccessRead = new RandomAccessReadBuffer(inputStream);
|
||||
TrueTypeFont trueTypeFont = ttfParser.parse(randomAccessRead);
|
||||
return PDType0Font.load(pdDocument, trueTypeFont, true);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
package org.xbib.graphics.pdfbox.test;
|
||||
package org.xbib.graphics.fonts.test;
|
||||
|
||||
import java.util.Objects;
|
||||
import org.apache.pdfbox.pdmodel.font.PDType1Font;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.graphics.pdfbox.font.CoreFontDrawer;
|
||||
import org.xbib.graphics.fonts.CoreFontDrawer;
|
||||
|
||||
import java.awt.Font;
|
||||
|
||||
|
@ -27,7 +28,8 @@ public class FontDrawerTest {
|
|||
|
||||
@Test
|
||||
public void testFontStyleMatching() {
|
||||
Font anyFont = Font.decode("Dialog");
|
||||
Font anyFont = Font.decode(Font.DIALOG);
|
||||
Objects.requireNonNull(anyFont);
|
||||
Font anyFontBold = anyFont.deriveFont(Font.BOLD);
|
||||
Font anyFontItalic = anyFont.deriveFont(Font.ITALIC);
|
||||
Font anyFontBoldItalic = anyFont.deriveFont(Font.BOLD | Font.ITALIC);
|
||||
|
@ -48,7 +50,9 @@ public class FontDrawerTest {
|
|||
|
||||
@Test
|
||||
public void testDefaultFontMapping() {
|
||||
assertEquals(new PDType1Font(HELVETICA).getName(), CoreFontDrawer.mapToCoreFonts(Font.decode(Font.DIALOG)).getName());
|
||||
Font anyFont = Font.decode(Font.DIALOG);
|
||||
Objects.requireNonNull(anyFont);
|
||||
assertEquals(new PDType1Font(HELVETICA).getName(), CoreFontDrawer.mapToCoreFonts(anyFont).getName());
|
||||
assertEquals(new PDType1Font(HELVETICA).getName(), CoreFontDrawer.mapToCoreFonts(Font.decode(Font.DIALOG_INPUT)).getName());
|
||||
assertEquals(new PDType1Font(HELVETICA).getName(), CoreFontDrawer.mapToCoreFonts(Font.decode("Arial")).getName());
|
||||
assertEquals(new PDType1Font(COURIER).getName(), CoreFontDrawer.mapToCoreFonts(Font.decode(Font.MONOSPACED)).getName());
|
|
@ -2,7 +2,7 @@ module org.xbib.graphics.ghostscript {
|
|||
exports org.xbib.graphics.ghostscript;
|
||||
requires com.sun.jna;
|
||||
requires java.logging;
|
||||
requires transitive java.desktop;
|
||||
requires transitive org.apache.pdfbox;
|
||||
requires transitive org.apache.pdfbox.io;
|
||||
requires java.desktop;
|
||||
requires org.apache.pdfbox;
|
||||
requires org.apache.pdfbox.io;
|
||||
}
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
package org.xbib.graphics.ghostscript;
|
||||
|
||||
public class FontAnalysisItem {
|
||||
|
||||
private String name;
|
||||
|
||||
private boolean embedded;
|
||||
|
||||
private boolean subSet;
|
||||
|
||||
public FontAnalysisItem() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String embeddedString = "NOT_EMBEDDED";
|
||||
if (embedded) {
|
||||
embeddedString = "EMBEDDED";
|
||||
}
|
||||
String setString = "FULL_SET";
|
||||
if (subSet) {
|
||||
setString = "SUB_SET";
|
||||
}
|
||||
return name + ": " + embeddedString + " " + setString;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public boolean isEmbedded() {
|
||||
return embedded;
|
||||
}
|
||||
|
||||
public void setEmbedded(boolean embedded) {
|
||||
this.embedded = embedded;
|
||||
}
|
||||
|
||||
public boolean isSubSet() {
|
||||
return subSet;
|
||||
}
|
||||
|
||||
public void setSubSet(boolean subSet) {
|
||||
this.subSet = subSet;
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package org.xbib.graphics.ghostscript;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Font analyzer.
|
||||
* Analyze fonts used in a document using {@code -fonta}.
|
||||
* We use Pdfbox for font analysis, so this is not tested and not used.
|
||||
*/
|
||||
public class FontAnalyzer {
|
||||
|
||||
public FontAnalyzer() {
|
||||
}
|
||||
|
||||
public synchronized List<FontAnalysisItem> analyze(Path path) throws IOException {
|
||||
String[] gsArgs = new String[]{"-fonta",
|
||||
"-dQUIET", "-dNOPAUSE", "-dBATCH", "-dNODISPLAY",
|
||||
"-sFile=" + path.toAbsolutePath(),
|
||||
"-sOutputFile=%stdout",
|
||||
"-f", "-"};
|
||||
try (Ghostscript gs = new Ghostscript();
|
||||
InputStream is = this.getClass().getClassLoader().getResourceAsStream("script/AnalyzePDFFonts.ps");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||
gs.setStdIn(is);
|
||||
gs.setStdOut(baos);
|
||||
gs.run(gsArgs);
|
||||
List<FontAnalysisItem> result = new ArrayList<>();
|
||||
String s = baos.toString();
|
||||
String[] lines = s.split("\n");
|
||||
boolean inResults = false;
|
||||
for (String line : lines) {
|
||||
if (line.equals("---")) {
|
||||
inResults = true;
|
||||
} else if (inResults) {
|
||||
String[] columns = line.split(" ");
|
||||
if (columns.length == 2) {
|
||||
FontAnalysisItem font = new FontAnalysisItem();
|
||||
String name = columns[0];
|
||||
String[] nameParts = name.split("\\+");
|
||||
if (nameParts.length > 1) {
|
||||
name = nameParts[1];
|
||||
font.setSubSet(true);
|
||||
}
|
||||
font.setName(name);
|
||||
font.setEmbedded(false);
|
||||
if (columns[1].equals("EM") || columns[1].equals("SU")) {
|
||||
font.setEmbedded(true);
|
||||
}
|
||||
result.add(font);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,23 +2,20 @@ package org.xbib.graphics.ghostscript;
|
|||
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import org.xbib.graphics.ghostscript.internal.ErrorCodes;
|
||||
import org.xbib.graphics.ghostscript.internal.GhostscriptLibrary;
|
||||
import org.xbib.graphics.ghostscript.internal.GhostscriptLibraryLoader;
|
||||
import org.xbib.graphics.ghostscript.internal.LoggingOutputStream;
|
||||
import org.xbib.graphics.ghostscript.internal.NullOutputStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -33,21 +30,12 @@ public class Ghostscript implements AutoCloseable {
|
|||
|
||||
private final GhostscriptLibrary libraryInstance;
|
||||
|
||||
private InputStream stdIn;
|
||||
|
||||
private OutputStream stdOut;
|
||||
|
||||
private OutputStream stdErr;
|
||||
|
||||
private final AtomicBoolean closed;
|
||||
|
||||
public Ghostscript() throws IOException {
|
||||
prepareTmp();
|
||||
GhostscriptLibraryLoader libraryLoader = new GhostscriptLibraryLoader();
|
||||
this.libraryInstance = libraryLoader.getGhostscriptLibrary();
|
||||
Objects.requireNonNull(this.libraryInstance);
|
||||
this.stdOut = new LoggingOutputStream(logger);
|
||||
this.stdErr = new LoggingOutputStream(logger);
|
||||
this.libraryInstance = Objects.requireNonNull(libraryLoader.getGhostscriptLibrary(), "library instance must not be null");
|
||||
this.closed = new AtomicBoolean(false);
|
||||
}
|
||||
|
||||
|
@ -68,63 +56,8 @@ public class Ghostscript implements AutoCloseable {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error output stream of the Ghostscript interpreter (may be null
|
||||
* if not set).
|
||||
*
|
||||
* @return The OutputStream or null
|
||||
*/
|
||||
public OutputStream getStdErr() {
|
||||
return stdErr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error output stream of the Ghostscript interpreter.
|
||||
*
|
||||
* @param outputStream OutputStream object
|
||||
*/
|
||||
public void setStdErr(OutputStream outputStream) {
|
||||
stdErr = outputStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the standard output stream of the Ghostscript interpreter.
|
||||
*
|
||||
* @return The OutputStream or null
|
||||
*/
|
||||
public OutputStream getStdOut() {
|
||||
return stdOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the standard output stream of the Ghostscript interpreter.
|
||||
*
|
||||
* @param outputStream OutputStream object
|
||||
*/
|
||||
public void setStdOut(OutputStream outputStream) {
|
||||
stdOut = outputStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the standard input stream of the Ghostscript interpreter.
|
||||
*
|
||||
* @return The InputStream or null
|
||||
*/
|
||||
public InputStream getStdIn() {
|
||||
return stdIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the standard input stream of the Ghostscript interpreter.
|
||||
*
|
||||
* @param inputStream InputStream object
|
||||
*/
|
||||
public void setStdIn(InputStream inputStream) {
|
||||
stdIn = inputStream;
|
||||
}
|
||||
|
||||
public synchronized void run(String[] args) throws IOException {
|
||||
run(args, null, null);
|
||||
public synchronized int run(List<String> args) throws IOException {
|
||||
return run(args, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,78 +66,56 @@ public class Ghostscript implements AutoCloseable {
|
|||
* @param args Interpreter parameters. Use the same as Ghostscript command line arguments.
|
||||
* @param runString run a string for the Ghostscript interpreter.
|
||||
* @param fileName run a postscript file for the Ghostscript interpreter.
|
||||
* @return the ghostscript return code;
|
||||
* @throws IOException if initialize fails
|
||||
*/
|
||||
public synchronized void run(String[] args,
|
||||
String runString,
|
||||
String fileName) throws IOException {
|
||||
public synchronized int run(List<String> args,
|
||||
String runString,
|
||||
String fileName) throws IOException {
|
||||
Objects.requireNonNull(args);
|
||||
List<String> fullArgList = new LinkedList<>();
|
||||
if (!args.contains("ps2pdf")) {
|
||||
fullArgList.add("gs"); // gs or ps2pdf must be always present in the arg list
|
||||
}
|
||||
fullArgList.addAll(args);
|
||||
GhostscriptLibrary.gs_main_instance.ByReference nativeInstanceByRef = null;
|
||||
int ret = 0;
|
||||
boolean quit = false;
|
||||
try {
|
||||
nativeInstanceByRef = new GhostscriptLibrary.gs_main_instance.ByReference();
|
||||
int result = libraryInstance.gsapi_new_instance(nativeInstanceByRef.getPointer(), null);
|
||||
if (result != 0) {
|
||||
ret = libraryInstance.gsapi_new_instance(nativeInstanceByRef.getPointer(), null);
|
||||
if (ret != 0) {
|
||||
nativeInstanceByRef = null;
|
||||
throw new IOException("can not call Ghostscript gsapi_new_instance, error code " + result);
|
||||
throw new IOException("can not call Ghostscript gsapi_new_instance, error code = " + ret);
|
||||
}
|
||||
logger.log(Level.INFO, "ghostscript instance " + nativeInstanceByRef + " created");
|
||||
GhostscriptLibrary.stdin_fn stdinCallback = null;
|
||||
if (getStdIn() != null) {
|
||||
stdinCallback = (caller_handle, buf, len) -> {
|
||||
String encoding = System.getProperty(ENCODING_PARAMETER, "UTF-8");
|
||||
try {
|
||||
byte[] buffer = new byte[1024];
|
||||
int read = getStdIn().read(buffer);
|
||||
if (read != -1) {
|
||||
buf.setString(0, new String(buffer, 0, read, encoding));
|
||||
return read;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING, e.getMessage(), e);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
GhostscriptLibrary.stdout_fn stdoutCallback;
|
||||
if (getStdOut() == null) {
|
||||
setStdOut(new NullOutputStream());
|
||||
}
|
||||
stdoutCallback = (caller_handle, str, len) -> {
|
||||
try {
|
||||
getStdOut().write(str.getBytes(), 0, len);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, ex.getMessage(), ex);
|
||||
}
|
||||
logger.log(Level.FINE, "ghostscript instance " + nativeInstanceByRef + " created");
|
||||
Pointer pointer = nativeInstanceByRef.getValue();
|
||||
// always 0, we never use stdin
|
||||
GhostscriptLibrary.stdin_fn stdinCallback = (caller_handle, buf, len) -> 0;
|
||||
GhostscriptLibrary.stdout_fn stdoutCallback = (caller_handle, str, len) -> {
|
||||
logger.log(Level.FINE, str.substring(0, len));
|
||||
return len;
|
||||
};
|
||||
GhostscriptLibrary.stderr_fn stderrCallback;
|
||||
if (getStdErr() == null) {
|
||||
setStdErr(new NullOutputStream());
|
||||
}
|
||||
stderrCallback = (caller_handle, str, len) -> {
|
||||
try {
|
||||
getStdErr().write(str.getBytes(), 0, len);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, ex.getMessage(), ex);
|
||||
}
|
||||
GhostscriptLibrary.stderr_fn stderrCallback = (caller_handle, str, len) -> {
|
||||
logger.log(Level.FINE, str.substring(0, len));
|
||||
return len;
|
||||
};
|
||||
logger.log(Level.FINE, "setting gsapi_set_stdio");
|
||||
result = libraryInstance.gsapi_set_stdio(nativeInstanceByRef.getValue(), stdinCallback,
|
||||
stdoutCallback, stderrCallback);
|
||||
if (result != 0) {
|
||||
throw new IOException("can not set stdio on Ghostscript interpreter, error code " + result);
|
||||
ret = libraryInstance.gsapi_set_stdio(pointer, stdinCallback, stdoutCallback, stderrCallback);
|
||||
if (ret != 0) {
|
||||
throw new IOException("can not set stdio on Ghostscript interpreter, error code " + ret);
|
||||
}
|
||||
logger.log(Level.FINE, "gsapi_init_with_args = " + (args != null ? Arrays.asList(args) : "null"));
|
||||
result = libraryInstance.gsapi_init_with_args(nativeInstanceByRef.getValue(),
|
||||
args != null ? args.length : 0, args);
|
||||
logger.log(Level.FINE, "gsapi_init_with_args result = " + result);
|
||||
if (result == ErrorCodes.gs_error_Quit) {
|
||||
result = 0;
|
||||
logger.log(Level.FINE, "gsapi_init_with_args = " + fullArgList);
|
||||
ret = libraryInstance.gsapi_init_with_args(pointer, fullArgList.size(), fullArgList.toArray(new String[0]));
|
||||
logger.log(Level.FINE, "gsapi_init_with_args return code = " + ret);
|
||||
if (ret == ErrorCodes.gs_error_Quit) {
|
||||
quit = true;
|
||||
ret = 0;
|
||||
}
|
||||
if (result == 0) {
|
||||
if (ret == 0) {
|
||||
if (runString != null) {
|
||||
IntByReference exitCode = new IntByReference();
|
||||
libraryInstance.gsapi_run_string_begin(nativeInstanceByRef.getValue(), 0, exitCode);
|
||||
ret = libraryInstance.gsapi_run_string_begin(pointer, 0, exitCode);
|
||||
if (exitCode.getValue() != 0) {
|
||||
throw new IOException("can not run command on Ghostscript interpreter. gsapi_run_string_begin failed with error code "
|
||||
+ exitCode.getValue());
|
||||
|
@ -212,14 +123,13 @@ public class Ghostscript implements AutoCloseable {
|
|||
String[] slices = runString.split("\n");
|
||||
for (String slice1 : slices) {
|
||||
String slice = slice1 + "\n";
|
||||
libraryInstance.gsapi_run_string_continue(nativeInstanceByRef.getValue(), slice, slice.length(),
|
||||
0, exitCode);
|
||||
libraryInstance.gsapi_run_string_continue(pointer, slice, slice.length(), 0, exitCode);
|
||||
if (exitCode.getValue() != 0) {
|
||||
throw new IOException("can not run command on Ghostscript interpreter. gsapi_run_string_continue failed with error code "
|
||||
+ exitCode.getValue());
|
||||
}
|
||||
}
|
||||
libraryInstance.gsapi_run_string_end(nativeInstanceByRef.getValue(), 0, exitCode);
|
||||
ret = libraryInstance.gsapi_run_string_end(pointer, 0, exitCode);
|
||||
if (exitCode.getValue() != 0) {
|
||||
throw new IOException("can not run command on Ghostscript interpreter. gsapi_run_string_end failed with error code "
|
||||
+ exitCode.getValue());
|
||||
|
@ -228,53 +138,45 @@ public class Ghostscript implements AutoCloseable {
|
|||
}
|
||||
if (fileName != null) {
|
||||
IntByReference exitCode = new IntByReference();
|
||||
libraryInstance.gsapi_run_file(nativeInstanceByRef.getValue(), fileName, 0, exitCode);
|
||||
ret = libraryInstance.gsapi_run_file(pointer, fileName, 0, exitCode);
|
||||
if (exitCode.getValue() != 0) {
|
||||
throw new IOException("can not run file on Ghostscript interpreter, error code " + exitCode.getValue());
|
||||
throw new IOException("can not run file on Ghostscript interpreter, error code = " + exitCode.getValue());
|
||||
}
|
||||
logger.log(Level.FINE, "file completed: " + fileName);
|
||||
}
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
if (result < 0) {
|
||||
throw new IOException("can not initialize Ghostscript interpreter, error code " + result);
|
||||
if (ret < 0) {
|
||||
throw new IOException("can not initialize Ghostscript interpreter, error code = " + ret);
|
||||
}
|
||||
} finally {
|
||||
if (nativeInstanceByRef != null) {
|
||||
Pointer pointer = nativeInstanceByRef.getValue();
|
||||
if (pointer != null) {
|
||||
int result = libraryInstance.gsapi_exit(pointer);
|
||||
if (result != 0) {
|
||||
logger.log(Level.SEVERE, "can not call Ghostscript gsapi_exit, error code " + result);
|
||||
if (!quit && ret >= 0) {
|
||||
logger.log(Level.FINE, "exiting ghostscript instance " + libraryInstance);
|
||||
ret = libraryInstance.gsapi_exit(pointer);
|
||||
if (ret != 0) {
|
||||
logger.log(Level.SEVERE, "can not call Ghostscript gsapi_exit, error code " + ret);
|
||||
}
|
||||
logger.log(Level.FINE, "deleting ghostscript instance " + pointer);
|
||||
libraryInstance.gsapi_delete_instance(pointer);
|
||||
}
|
||||
} else {
|
||||
logger.log(Level.WARNING, "no pointer to exit");
|
||||
}
|
||||
libraryInstance.gsapi_delete_instance(nativeInstanceByRef.getValue());
|
||||
logger.log(Level.INFO, "ghostscript instance " + nativeInstanceByRef + " deleted");
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() throws IOException {
|
||||
if (closed.compareAndSet(false, true)) {
|
||||
if (stdIn != null) {
|
||||
stdIn.close();
|
||||
stdIn = null;
|
||||
}
|
||||
if (stdOut != null) {
|
||||
stdOut.close();
|
||||
stdOut = null;
|
||||
}
|
||||
if (stdErr != null) {
|
||||
stdErr.close();
|
||||
stdErr = null;
|
||||
}
|
||||
if (libraryInstance != null) {
|
||||
libraryInstance.dispose();
|
||||
System.gc();
|
||||
logger.log(Level.INFO, "ghostscript library instance disposed and gc'ed()");
|
||||
logger.log(Level.FINE, "ghostscript library instance disposed and gc'ed()");
|
||||
} else {
|
||||
logger.log(Level.WARNING, "ghostscript library instance is null");
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package org.xbib.graphics.ghostscript;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import org.xbib.graphics.ghostscript.internal.LoggingOutputStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -14,6 +13,7 @@ import java.nio.file.SimpleFileVisitor;
|
|||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -75,9 +75,16 @@ public class PDFConverter {
|
|||
*/
|
||||
private final PaperSize paperSize;
|
||||
|
||||
private final List<String> customGsArgs;
|
||||
|
||||
public PDFConverter() {
|
||||
this(OPTION_AUTOROTATEPAGES_OFF, OPTION_PROCESSCOLORMODEL_RGB,
|
||||
OPTION_PDFSETTINGS_PRINTER, "1.4", false, PaperSize.A4);
|
||||
OPTION_PDFSETTINGS_PRINTER, "1.4", false, PaperSize.A4, List.of());
|
||||
}
|
||||
|
||||
public PDFConverter(List<String> customGsArgs) {
|
||||
this(OPTION_AUTOROTATEPAGES_OFF, OPTION_PROCESSCOLORMODEL_RGB,
|
||||
OPTION_PDFSETTINGS_PRINTER, "1.4", false, PaperSize.A4, customGsArgs);
|
||||
}
|
||||
|
||||
public PDFConverter(int autoRotatePages,
|
||||
|
@ -85,41 +92,45 @@ public class PDFConverter {
|
|||
int pdfsettings,
|
||||
String compatibilityLevel,
|
||||
boolean pdfx,
|
||||
PaperSize paperSize) {
|
||||
PaperSize paperSize,
|
||||
List<String> customGsArgs) {
|
||||
this.autoRotatePages = autoRotatePages;
|
||||
this.processColorModel = processColorModel;
|
||||
this.pdfsettings = pdfsettings;
|
||||
this.compatibilityLevel = compatibilityLevel;
|
||||
this.pdfx = pdfx;
|
||||
this.paperSize = paperSize;
|
||||
this.customGsArgs = customGsArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run method called to perform the actual process of the converter.
|
||||
*
|
||||
* @param inputStream the input document
|
||||
* @param outputStream output stream
|
||||
* @param inputStream the input stream
|
||||
* @param outputStream the output stream
|
||||
* @return the Ghostscript return code
|
||||
* @throws IOException if conversion fails
|
||||
*/
|
||||
public synchronized void convert(InputStream inputStream, OutputStream outputStream)
|
||||
throws IOException {
|
||||
if (outputStream == null) {
|
||||
return;
|
||||
}
|
||||
public synchronized int convert(InputStream inputStream,
|
||||
OutputStream outputStream) throws IOException {
|
||||
Objects.requireNonNull(inputStream, "inputStream must not be null");
|
||||
Objects.requireNonNull(outputStream, "outputStream must not be null");
|
||||
int ret;
|
||||
Path tmpPath = createTmpPath();
|
||||
try (Ghostscript gs = new Ghostscript()) {
|
||||
Path input = Files.createTempFile(tmpPath, "pdf", "pdf");
|
||||
try (OutputStream sourceOutputStream = Files.newOutputStream(input)) {
|
||||
inputStream.transferTo(sourceOutputStream);
|
||||
}
|
||||
Path output = Files.createTempFile(tmpPath, "pdf", "pdf");
|
||||
List<String> gsArgs = new LinkedList<>();
|
||||
gsArgs.add("-ps2pdf");
|
||||
List<String> gsArgs = new LinkedList<>(customGsArgs);
|
||||
gsArgs.add("-dNOSAFER");
|
||||
gsArgs.add("-dNOPAUSE");
|
||||
gsArgs.add("-dBATCH");
|
||||
gsArgs.add("-dSAFER");
|
||||
switch (autoRotatePages) {
|
||||
case OPTION_AUTOROTATEPAGES_NONE -> gsArgs.add("-dAutoRotatePages=/None");
|
||||
case OPTION_AUTOROTATEPAGES_ALL -> gsArgs.add("-dAutoRotatePages=/All");
|
||||
case OPTION_AUTOROTATEPAGES_PAGEBYPAGE -> gsArgs.add("-dAutoRotatePages=/PageByPage");
|
||||
default -> {
|
||||
}
|
||||
default -> gsArgs.add("-dAutoRotatePages=/None");
|
||||
}
|
||||
switch (processColorModel) {
|
||||
case OPTION_PROCESSCOLORMODEL_CMYK -> gsArgs.add("-dProcessColorModel=/DeviceCMYK");
|
||||
|
@ -134,21 +145,21 @@ public class PDFConverter {
|
|||
default -> gsArgs.add("-dPDFSETTINGS=/default");
|
||||
}
|
||||
gsArgs.add("-dCompatibilityLevel=" + compatibilityLevel);
|
||||
gsArgs.add("-dPDFX=" + pdfx);
|
||||
if (pdfx) {
|
||||
gsArgs.add("-dPDFX=" + pdfx);
|
||||
}
|
||||
gsArgs.add("-dDEVICEWIDTHPOINTS=" + paperSize.getWidth());
|
||||
gsArgs.add("-dDEVICEHEIGHTPOINTS=" + paperSize.getHeight());
|
||||
gsArgs.add("-sDEVICE=pdfwrite");
|
||||
gsArgs.add("-sOutputFile=" + output.toAbsolutePath().toString());
|
||||
gsArgs.add("-sOutputFile=" + output.toAbsolutePath());
|
||||
gsArgs.add("-f");
|
||||
gsArgs.add("-");
|
||||
gs.setStdIn(inputStream);
|
||||
gs.setStdOut(new LoggingOutputStream(logger));
|
||||
gs.setStdErr(new LoggingOutputStream(logger));
|
||||
gs.run(gsArgs.toArray(new String[0]));
|
||||
gsArgs.add(input.toString());
|
||||
ret = gs.run(gsArgs);
|
||||
Files.copy(output.toAbsolutePath(), outputStream);
|
||||
} finally {
|
||||
deleteTmpPath(tmpPath);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void deleteTmpPath(Path path) throws IOException {
|
||||
|
|
|
@ -15,7 +15,6 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
|||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||
import org.xbib.graphics.ghostscript.internal.LoggingOutputStream;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedOutputStream;
|
||||
|
@ -72,8 +71,9 @@ public class PDFRasterizer {
|
|||
this.subject = subject;
|
||||
}
|
||||
|
||||
public synchronized void convert(Path source, Path target) throws IOException {
|
||||
logger.info("convert source=" + source + " target=" + target);
|
||||
public synchronized void convert(Path source,
|
||||
Path target) throws IOException {
|
||||
logger.log(Level.FINE, "convert source=" + source + " target=" + target);
|
||||
if (!Files.exists(source)) {
|
||||
throw new FileNotFoundException(source.toString());
|
||||
}
|
||||
|
@ -86,18 +86,19 @@ public class PDFRasterizer {
|
|||
Path tmpPath = createTmpPath();
|
||||
try {
|
||||
Path path = Files.createTempDirectory(tmpPath, "pdf-rasterize");
|
||||
pdfToImage(source, path, "pdf", null);
|
||||
pdfToImage(source, path, "pdf");
|
||||
Path tmpTarget = path.resolve(target.getFileName());
|
||||
mergeImagesToPDF(path, tmpTarget);
|
||||
scalePDF(tmpTarget, target);
|
||||
logger.info("convert source=" + source + " done");
|
||||
logger.log(Level.FINE, "convert source=" + source + " done");
|
||||
} finally {
|
||||
deleteTmpPath(tmpPath);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void screenConvert(Path source, Path target) throws IOException {
|
||||
logger.info("screen convert source=" + source.toAbsolutePath() + " target=" + target);
|
||||
public synchronized void screenConvert(Path source,
|
||||
Path target) throws IOException {
|
||||
logger.log(Level.FINE, "screen convert source=" + source.toAbsolutePath() + " target=" + target);
|
||||
if (!Files.exists(source.toAbsolutePath())) {
|
||||
throw new FileNotFoundException(source.toString());
|
||||
}
|
||||
|
@ -115,14 +116,15 @@ public class PDFRasterizer {
|
|||
mergeImagesToPDF(path, tmpTarget);
|
||||
//toPDFA(tmpTarget, target);
|
||||
scalePDF(tmpTarget, target);
|
||||
logger.info("screen convert source=" + source.toAbsolutePath() + " done");
|
||||
logger.log(Level.FINE, "screen convert source=" + source.toAbsolutePath() + " done");
|
||||
} finally {
|
||||
deleteTmpPath(tmpPath);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void pdfToGrayScreenImage(Path source, Path target) throws IOException {
|
||||
logger.info("pdfToGrayScreenImage source=" + source + " target=" + target);
|
||||
public synchronized void pdfToGrayScreenImage(Path source,
|
||||
Path target) throws IOException {
|
||||
logger.log(Level.FINE, "pdfToGrayScreenImage source=" + source + " target=" + target);
|
||||
if (!Files.exists(source.toAbsolutePath())) {
|
||||
throw new FileNotFoundException("not found: " + source);
|
||||
}
|
||||
|
@ -144,21 +146,25 @@ public class PDFRasterizer {
|
|||
gsArgs.add("-sOutputFile=" + target.resolve("screen-gray-pdf-%05d.png"));
|
||||
gsArgs.add("-f");
|
||||
gsArgs.add(source.toString());
|
||||
logger.info("pdfToImage args=" + gsArgs);
|
||||
logger.log(Level.FINE, "pdfToImage args=" + gsArgs);
|
||||
try (Ghostscript gs = new Ghostscript()) {
|
||||
gs.setStdIn(null);
|
||||
gs.setStdOut(new LoggingOutputStream(logger));
|
||||
gs.setStdErr(new LoggingOutputStream(logger));
|
||||
gs.run(gsArgs.toArray(new String[0]));
|
||||
logger.info("pdfToImage done");
|
||||
gs.run(gsArgs);
|
||||
logger.log(Level.FINE, "pdfToImage done");
|
||||
}
|
||||
}
|
||||
|
||||
public void pdfToImage(Path sourceFile,
|
||||
Path targetDir,
|
||||
String prefix) throws IOException {
|
||||
pdfToImage(sourceFile, targetDir, prefix, null, null);
|
||||
}
|
||||
|
||||
public synchronized void pdfToImage(Path sourceFile,
|
||||
Path targetDir,
|
||||
String prefix,
|
||||
String pageRange) throws IOException {
|
||||
logger.info("pdfToImage source=" + sourceFile + " target=" + targetDir + " started");
|
||||
String firstPage,
|
||||
String lastPage) throws IOException {
|
||||
logger.log(Level.FINE, "pdfToImage source=" + sourceFile + " target=" + targetDir + " started");
|
||||
List<String> gsArgs = new LinkedList<>();
|
||||
gsArgs.add("-dNOPAUSE");
|
||||
gsArgs.add("-dBATCH");
|
||||
|
@ -167,9 +173,11 @@ public class PDFRasterizer {
|
|||
gsArgs.add("-dINTERPOLATE");
|
||||
// how do we know we have a crop box or not?
|
||||
gsArgs.add("-dUseCropBox");
|
||||
// page range, if not null
|
||||
if (pageRange != null) {
|
||||
gsArgs.add("-sPageList=" + pageRange);
|
||||
if (firstPage != null) {
|
||||
gsArgs.add("-sFirstPage=" + firstPage);
|
||||
}
|
||||
if (lastPage != null) {
|
||||
gsArgs.add("-sLastPage=" + lastPage);
|
||||
}
|
||||
gsArgs.add("-sDEVICE=png16m");
|
||||
gsArgs.add("-r300");
|
||||
|
@ -181,23 +189,21 @@ public class PDFRasterizer {
|
|||
gsArgs.add("100000000 setvmthreshold");
|
||||
gsArgs.add("-f");
|
||||
gsArgs.add(sourceFile.toString());
|
||||
logger.info("pdfToImage args=" + gsArgs);
|
||||
try (Ghostscript gs = new Ghostscript()) {
|
||||
// reset stdin
|
||||
gs.setStdIn(null);
|
||||
gs.setStdOut(new LoggingOutputStream(logger));
|
||||
gs.setStdErr(new LoggingOutputStream(logger));
|
||||
gs.run(gsArgs.toArray(new String[0]));
|
||||
logger.info("pdfToImage done");
|
||||
gs.run(gsArgs);
|
||||
logger.log(Level.FINE, "pdfToImage done");
|
||||
}
|
||||
}
|
||||
|
||||
public int mergeImagesToPDF(Path sourceDir, Path targetFile) throws IOException {
|
||||
public int mergeImagesToPDF(Path sourceDir,
|
||||
Path targetFile) throws IOException {
|
||||
return mergeImagesToPDF(sourceDir, targetFile, "**/*");
|
||||
}
|
||||
|
||||
public synchronized int mergeImagesToPDF(Path sourceDir, Path targetFile, String globPattern) throws IOException {
|
||||
logger.info("mergeImagesToPDF: source=" + sourceDir + " target=" + targetFile + " glob =" + globPattern);
|
||||
public synchronized int mergeImagesToPDF(Path sourceDir,
|
||||
Path targetFile,
|
||||
String globPattern) throws IOException {
|
||||
logger.log(Level.FINE, "mergeImagesToPDF: source=" + sourceDir + " target=" + targetFile + " glob =" + globPattern);
|
||||
AtomicInteger pagecount = new AtomicInteger();
|
||||
PathMatcher pathMatcher = sourceDir.getFileSystem().getPathMatcher("glob:" + globPattern);
|
||||
List<PDDocument> coverPageDocs = new ArrayList<>();
|
||||
|
@ -222,7 +228,7 @@ public class PDFRasterizer {
|
|||
}
|
||||
for (Path path : entries) {
|
||||
if (path.getFileName().toString().toLowerCase(Locale.ROOT).endsWith(".pdf")) {
|
||||
logger.info("found pdf " + path);
|
||||
logger.log(Level.FINE, "found pdf " + path);
|
||||
try (InputStream inputStream = Files.newInputStream(path)) {
|
||||
PDDocument doc = Loader.loadPDF(inputStream.readAllBytes());
|
||||
for (int i = 0; i < doc.getNumberOfPages(); i++) {
|
||||
|
@ -266,7 +272,7 @@ public class PDFRasterizer {
|
|||
}
|
||||
}
|
||||
pdDocument.save(outputStream);
|
||||
logger.info("mergeImagesToPDF: done, " + pagecount.get() + " pages");
|
||||
logger.log(Level.FINE, "pagesToPDF: done, " + pagecount.get() + " pages");
|
||||
} finally {
|
||||
for (PDDocument pd : coverPageDocs) {
|
||||
pd.close();
|
||||
|
@ -277,7 +283,7 @@ public class PDFRasterizer {
|
|||
|
||||
public synchronized void scalePDF(Path sourceFile,
|
||||
Path targetFile) throws IOException {
|
||||
logger.info("scalePDF: source = " + sourceFile + " target = " + targetFile + " starting");
|
||||
logger.log(Level.FINE, "scalePDF: source = " + sourceFile + " target = " + targetFile + " starting");
|
||||
List<String> gsArgs = new LinkedList<>();
|
||||
gsArgs.add("-dNOPAUSE");
|
||||
gsArgs.add("-dBATCH");
|
||||
|
@ -292,10 +298,27 @@ public class PDFRasterizer {
|
|||
gsArgs.add("-sOutputFile=" + targetFile.toString());
|
||||
gsArgs.add(sourceFile.toString());
|
||||
try (Ghostscript gs = new Ghostscript()) {
|
||||
gs.setStdIn(null);
|
||||
logger.info(gsArgs.toString());
|
||||
gs.run(gsArgs.toArray(new String[0]));
|
||||
logger.info("scalePDF: source = " + sourceFile + " target = " + targetFile + " done");
|
||||
gs.run(gsArgs);
|
||||
logger.log(Level.FINE, "scalePDF: source = " + sourceFile + " target = " + targetFile + " done");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void downgradePDF(Path sourceFile,
|
||||
Path targetFile) throws IOException {
|
||||
logger.log(Level.FINE, "downgradePDF: source = " + sourceFile + " target = " + targetFile + " starting");
|
||||
List<String> gsArgs = new LinkedList<>();
|
||||
gsArgs.add("-dNOPAUSE");
|
||||
gsArgs.add("-dBATCH");
|
||||
gsArgs.add("-dQUIET");
|
||||
gsArgs.add("-dPDFSETTINGS=/printer");
|
||||
gsArgs.add("-dFIXEDMEDIA");
|
||||
gsArgs.add("-dCompatibilityLevel=1.4");
|
||||
gsArgs.add("-sDEVICE=pdfwrite");
|
||||
gsArgs.add("-sOutputFile=" + targetFile.toString());
|
||||
gsArgs.add(sourceFile.toString());
|
||||
try (Ghostscript gs = new Ghostscript()) {
|
||||
gs.run(gsArgs);
|
||||
logger.log(Level.FINE, "downgradePDF: source = " + sourceFile + " target = " + targetFile + " done");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,14 +356,16 @@ public class PDFRasterizer {
|
|||
gsArgs.add("-sOutputFile=" + target.toString());
|
||||
gsArgs.add(pdfapsPath.toAbsolutePath().toString());
|
||||
gsArgs.add(source.toString());
|
||||
gs.setStdIn(null);
|
||||
gs.run(gsArgs.toArray(new String[0]));
|
||||
gs.run(gsArgs);
|
||||
} finally {
|
||||
deleteTmpPath(tmpPath);
|
||||
}
|
||||
}
|
||||
|
||||
private static void copyAndReplace(Path source, Path target, String from, String to) throws IOException {
|
||||
private static void copyAndReplace(Path source,
|
||||
Path target,
|
||||
String from,
|
||||
String to) throws IOException {
|
||||
try (BufferedReader br = Files.newBufferedReader(source); BufferedWriter bw = Files.newBufferedWriter(target)) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
package org.xbib.graphics.ghostscript;
|
||||
|
||||
public class PageRaster {
|
||||
|
||||
private int width;
|
||||
|
||||
private int height;
|
||||
|
||||
private int raster;
|
||||
|
||||
private int format;
|
||||
|
||||
private byte[] data;
|
||||
|
||||
public PageRaster() {
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setHeight(int height) {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public int getRaster() {
|
||||
return raster;
|
||||
}
|
||||
|
||||
public void setRaster(int raster) {
|
||||
this.raster = raster;
|
||||
}
|
||||
|
||||
public int getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public void setFormat(int format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue