diff --git a/barcode/build.gradle b/barcode/build.gradle index f125b34..540a510 100644 --- a/barcode/build.gradle +++ b/barcode/build.gradle @@ -1,5 +1,8 @@ dependencies { testImplementation project(':io-vector') + testImplementation project(':io-vector-eps') + testImplementation project(':io-vector-pdf') + testImplementation project(':io-vector-svg') testImplementation "org.junit.jupiter:junit-jupiter-params:5.7.0" testImplementation "junit:junit:4.12" testImplementation "com.google.zxing:javase:${project.property('zxing.version')}" diff --git a/barcode/src/main/java/org/xbib/graphics/barcode/MaxiCode.java b/barcode/src/main/java/org/xbib/graphics/barcode/MaxiCode.java index dc7ecb2..e90db8a 100755 --- a/barcode/src/main/java/org/xbib/graphics/barcode/MaxiCode.java +++ b/barcode/src/main/java/org/xbib/graphics/barcode/MaxiCode.java @@ -474,21 +474,16 @@ public class MaxiCode extends Symbol { * @return the primary message codewords */ private int[] getPrimaryCodewords() { - - assert mode == 2 || mode == 3; - if (primaryData.length() != 15) { errorMsg.append("Invalid Primary String"); return null; } - for (int i = 9; i < 15; i++) { /* check that country code and service are numeric */ if ((primaryData.charAt(i) < '0') || (primaryData.charAt(i) > '9')) { errorMsg.append("Invalid Primary String"); return null; } } - String postcode; if (mode == 2) { postcode = primaryData.substring(0, 9); @@ -500,10 +495,8 @@ public class MaxiCode extends Symbol { // if (mode == 3) postcode = primaryData.substring(0, 6); } - int country = Integer.parseInt(primaryData.substring(9, 12)); int service = Integer.parseInt(primaryData.substring(12, 15)); - if (mode == 2) { return getMode2PrimaryCodewords(postcode, country, service); } else { // mode == 3 diff --git a/barcode/src/main/java/org/xbib/graphics/barcode/Pdf417.java b/barcode/src/main/java/org/xbib/graphics/barcode/Pdf417.java index 32922ef..8e72bc9 100755 --- a/barcode/src/main/java/org/xbib/graphics/barcode/Pdf417.java +++ b/barcode/src/main/java/org/xbib/graphics/barcode/Pdf417.java @@ -442,7 +442,7 @@ public class Pdf417 extends Symbol { 579, 623, 766, 146, 10, 739, 246, 127, 71, 244, 211, 477, 920, 876, 427, 820, 718, 435 }; - private int[] codeWords = new int[2700]; + private final int[] codeWords = new int[2700]; private int codeWordCount; private Mode symbolMode = Mode.NORMAL; private int[] inputData; @@ -651,7 +651,7 @@ public class Pdf417 extends Symbol { */ public void setPreferredEccLevel(int eccLevel) { if (eccLevel < 0 || eccLevel > 8) { - throw new IllegalArgumentException("ECC level must be between 0 and 8."); + throw new IllegalArgumentException("ECC level must be between 0 and 8, but is " + eccLevel); } preferredEccLevel = eccLevel; } @@ -664,10 +664,10 @@ public class Pdf417 extends Symbol { */ public void setVariant(int variant) { if (symbolMode != Mode.MICRO) { - throw new IllegalArgumentException("Can only set variant when using MICRO mode."); + throw new IllegalArgumentException("Can only set variant when using MICRO mode"); } if (variant < 1 || variant > 34) { - throw new IllegalArgumentException("Variant must be between 1 and 34."); + throw new IllegalArgumentException("Variant must be between 1 and 34"); } this.columns = MICRO_VARIANTS[variant - 1]; this.rows = MICRO_VARIANTS[variant - 1 + 34]; diff --git a/barcode/src/test/java/org/xbib/graphics/barcode/ParameterizedExtension.java b/barcode/src/test/java/org/xbib/graphics/barcode/ParameterizedExtension.java index 41a5eac..54e0881 100644 --- a/barcode/src/test/java/org/xbib/graphics/barcode/ParameterizedExtension.java +++ b/barcode/src/test/java/org/xbib/graphics/barcode/ParameterizedExtension.java @@ -48,18 +48,15 @@ public class ParameterizedExtension implements TestTemplateInvocationContextProv boolean hasParameterFields = !fields.isEmpty(); boolean hasCorrectParameterFields = areParametersFormedCorrectly(fields); boolean hasArgsConstructor = hasArgsConstructor(context); - if (hasArgsConstructor) { return !hasParameterFields; - } - else { + } else { return !hasParameterFields || hasCorrectParameterFields; } } @Override public Stream provideTestTemplateInvocationContexts(ExtensionContext context) { - // grabbing the parent ensures the PARAMETERS are stored in the same store across multiple TestTemplates. return context.getParent().flatMap(ParameterizedExtension::parameters).map( o -> testTemplateContextsFromParameters(o, context)).orElse(Stream.empty()); } @@ -68,35 +65,28 @@ public class ParameterizedExtension implements TestTemplateInvocationContextProv List parameterValues = parameterIndexes(fields); List duplicateIndexes = duplicatedIndexes(parameterValues); boolean hasAllIndexes = indexRangeComplete(parameterValues); - return hasAllIndexes && duplicateIndexes.isEmpty(); } private static List parameterIndexes(List fields) { - // @formatter:off return fields.stream() .map(f -> f.getAnnotation(Parameterized.Parameter.class)) .map(Parameterized.Parameter::value) .collect(toList()); - // @formatter:on } private static List duplicatedIndexes(List parameterValues) { - // @formatter:off return parameterValues.stream().collect(groupingBy(identity())).entrySet().stream() .filter(e -> e.getValue().size() > 1) .map(Map.Entry::getKey) .collect(toList()); - // @formatter:on } private static Boolean indexRangeComplete(List parameterValues) { - // @formatter:off return parameterValues.stream() .max(Integer::compareTo) .map(i -> parameterValues.containsAll(IntStream.range(0, i).boxed().collect(toList()))) .orElse(false); - // @formatter:on } private static Optional> parameters(ExtensionContext context) { @@ -106,11 +96,9 @@ public class ParameterizedExtension implements TestTemplateInvocationContextProv } private static Optional> callParameters(ExtensionContext context) { - // @formatter:off return findParametersMethod(context) .map(m -> ReflectionUtils.invokeMethod(m, null)) .map(ParameterizedExtension::convertParametersMethodReturnType); - // @formatter:on } private static boolean hasParametersMethod(ExtensionContext context) { @@ -118,11 +106,9 @@ public class ParameterizedExtension implements TestTemplateInvocationContextProv } private static Optional findParametersMethod(ExtensionContext extensionContext) { - // @formatter:off return extensionContext.getTestClass() .flatMap(ParameterizedExtension::ensureSingleParametersMethod) .filter(ReflectionUtils::isPublic); - // @formatter:on } private static Optional ensureSingleParametersMethod(Class testClass) { @@ -135,14 +121,11 @@ public class ParameterizedExtension implements TestTemplateInvocationContextProv List fields = parametersFields(context); boolean hasParameterFields = !fields.isEmpty(); boolean hasCorrectParameterFields = areParametersFormedCorrectly(fields); - if (!hasParameterFields) { return o.stream().map(ParameterizedExtension::parameterResolver); - } - else if (hasCorrectParameterFields) { + } else if (hasCorrectParameterFields) { return o.stream().map(ParameterizedExtension::contextFactory); } - return Stream.empty(); } @@ -181,11 +164,9 @@ public class ParameterizedExtension implements TestTemplateInvocationContextProv @Override public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception { List parameters = parametersFields(context); - if (!parameters.isEmpty() && parameters.size() != this.parameters.length) { throw unMatchedAmountOfParametersException(); } - for (Field param : parameters) { Parameterized.Parameter annotation = param.getAnnotation(Parameterized.Parameter.class); int paramIndex = annotation.value(); @@ -205,29 +186,21 @@ public class ParameterizedExtension implements TestTemplateInvocationContextProv } private static boolean hasArgsConstructor(ExtensionContext context) { - // @formatter:off return context.getTestClass() .map(ReflectionUtils::getDeclaredConstructor) .filter(c -> c.getParameterCount() > 0) .isPresent(); - // @formatter:on } private static List parametersFields(ExtensionContext context) { - // @formatter:off Stream fieldStream = context.getTestClass() - .map(Class::getDeclaredFields) - .map(Stream::of) - .orElse(Stream.empty()); - // @formatter:on - + .map(Class::getDeclaredFields).stream().flatMap(Stream::of); return fieldStream.filter(f -> f.isAnnotationPresent(Parameterized.Parameter.class)).filter( ReflectionUtils::isPublic).collect(toList()); } private static ParameterResolutionException unMatchedAmountOfParametersException() { - return new ParameterResolutionException( - "The amount of parametersFields in the constructor doesn't match those in the provided parametersFields"); + return new ParameterResolutionException("The amount of parametersFields in the constructor doesn't match those in the provided parametersFields"); } private static Collection convertParametersMethodReturnType(Object obj) { @@ -240,6 +213,7 @@ public class ParameterizedExtension implements TestTemplateInvocationContextProv } private static class ParameterWrapper { + private final Optional> value; public ParameterWrapper(Optional> value) { diff --git a/barcode/src/test/java/org/xbib/graphics/barcode/SymbolTest.java b/barcode/src/test/java/org/xbib/graphics/barcode/SymbolTest.java index ef199be..afef5f4 100755 --- a/barcode/src/test/java/org/xbib/graphics/barcode/SymbolTest.java +++ b/barcode/src/test/java/org/xbib/graphics/barcode/SymbolTest.java @@ -53,7 +53,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.logging.Logger; import javax.imageio.ImageIO; /** @@ -62,17 +61,16 @@ import javax.imageio.ImageIO; * Tests that verify successful behavior will contain the following sets of files: * *
- *   /src/test/resources/uk/org/okapibarcode/backend/[symbol-name]/[test-name].properties (bar code initialization attributes)
- *   /src/test/resources/uk/org/okapibarcode/backend/[symbol-name]/[test-name].codewords  (expected intermediate coding of the bar code)
- *   /src/test/resources/uk/org/okapibarcode/backend/[symbol-name]/[test-name].png        (expected final rendering of the bar code)
+ *   backend/[symbol-name]/[test-name].properties (bar code initialization attributes)
+ *   /backend/[symbol-name]/[test-name].codewords  (expected intermediate coding of the bar code)
+ *   backend/[symbol-name]/[test-name].png        (expected final rendering of the bar code)
  * 
* - *

* Tests that verify error conditions will contain the following sets of files: * *

- *   /src/test/resources/uk/org/okapibarcode/backend/[symbol-name]/[test-name].properties (bar code initialization attributes)
- *   /src/test/resources/uk/org/okapibarcode/backend/[symbol-name]/[test-name].error      (expected error message)
+ *   backend/[symbol-name]/[test-name].properties (bar code initialization attributes)
+ *   backend/[symbol-name]/[test-name].error      (expected error message)
  * 
* * If a properties file is found with no matching expectation files, we assume that it was recently added to the test suite and @@ -109,8 +107,8 @@ public class SymbolTest { * @throws IOException if there is an error reading a file */ @Parameterized.Parameters - public static List< Object[] > data() throws IOException { - String path = "/org/xbib/graphics/barcode/fonts/OkapiDejaVuSans.ttf"; + public static List data() throws IOException { + String path = "/org/xbib/graphics/barcode/fonts/DejaVuSans.ttf"; try { InputStream is = SymbolTest.class.getResourceAsStream(path); DEJA_VU_SANS = Font.createFont(Font.TRUETYPE_FONT, is); @@ -139,6 +137,7 @@ public class SymbolTest { } return data; } + /** * Creates a new test. * @@ -174,14 +173,12 @@ public class SymbolTest { } catch (InvocationTargetException e) { symbol.errorMsg.append(e.getCause().getMessage()); } + //generateExpectationFiles(symbol); if (codewordsFile.exists()) { verifySuccess(symbol); } else if (errorFile.exists()) { verifyError(symbol); } - if (!pngFile.exists()) { - generateExpectationFiles(symbol); - } } /** @@ -224,7 +221,7 @@ public class SymbolTest { if (expected != null && actual != null) { assertEqualImage(pngFile.getName(), expected, actual); } - // if possible, ensure an independent third party (ZXing) can read the generated barcode and agrees on what it represents + //*/ if possible, ensure an independent third party (ZXing) can read the generated barcode and agrees on what it represents Reader zxingReader = findReader(symbol); if (zxingReader != null && expected != null) { LuminanceSource source = new BufferedImageLuminanceSource(expected); @@ -316,7 +313,7 @@ public class SymbolTest { */ private void verifyError(Symbol symbol) throws IOException { String expectedError = Files.readAllLines(errorFile.toPath(), StandardCharsets.UTF_8).get(0); - assertTrue(symbol.errorMsg.toString().startsWith(expectedError)); + assertTrue(symbol.errorMsg.toString().contains(expectedError)); } /** @@ -355,7 +352,7 @@ public class SymbolTest { * @throws IOException if there is any I/O error */ private void generateCodewordsExpectationFile(Symbol symbol) throws IOException { - if (!codewordsFile.exists()) { + //if (!codewordsFile.exists()) { PrintWriter writer = new PrintWriter(codewordsFile); try { int[] codewords = symbol.getCodewords(); @@ -368,7 +365,7 @@ public class SymbolTest { } } writer.close(); - } + //} } /** @@ -411,9 +408,7 @@ public class SymbolTest { if (width > 0 && height > 0) { BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); Graphics2D g2d = img.createGraphics(); - g2d.setPaint(Color.WHITE); - g2d.fillRect(0, 0, width, height); - GraphicsRenderer renderer = new GraphicsRenderer(g2d, scalingFactor, Color.WHITE, Color.BLACK, true, true); + GraphicsRenderer renderer = new GraphicsRenderer(g2d, scalingFactor, Color.WHITE, Color.BLACK, true, false); renderer.render(symbol); g2d.dispose(); return img; diff --git a/barcode/src/test/java/org/xbib/graphics/barcode/output/Code39Test.java b/barcode/src/test/java/org/xbib/graphics/barcode/output/Code39Test.java index c5e38bb..99c7012 100644 --- a/barcode/src/test/java/org/xbib/graphics/barcode/output/Code39Test.java +++ b/barcode/src/test/java/org/xbib/graphics/barcode/output/Code39Test.java @@ -51,9 +51,6 @@ public class Code39Test { private GraphicsRenderer createRenderer(BufferedImage bufferedImage, double scalingFactor) { Graphics2D g2d = bufferedImage.createGraphics(); - g2d.setPaint(Color.WHITE); - g2d.setBackground(Color.BLACK); - g2d.fillRect(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight()); return new GraphicsRenderer(g2d, scalingFactor, Color.WHITE, Color.BLACK, false, false); } } diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/code11/basic.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/code11/basic.codewords index 6785c36..5fbc040 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/code11/basic.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/code11/basic.codewords @@ -1,15 +1,15 @@ -112211 start -111121 0 -211121 1 -121121 2 -221111 3 -112121 4 -112111 - -212111 5 -122111 6 -111221 7 -211211 8 -211111 9 -112121 4 (check digit C) -221111 3 (check digit K) -112211 stop +112211 +111121 +211121 +121121 +221111 +112121 +112111 +212111 +122111 +111221 +211211 +211111 +112121 +221111 +112211 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/fonts/OkapiDejaVuSans.ttf b/barcode/src/test/resources/org/xbib/graphics/barcode/fonts/DejaVuSans.ttf similarity index 100% rename from barcode/src/test/resources/org/xbib/graphics/barcode/fonts/OkapiDejaVuSans.ttf rename to barcode/src/test/resources/org/xbib/graphics/barcode/fonts/DejaVuSans.ttf diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-max-data.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-max-data.png index f7c37d5..210300b 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-max-data.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-max-data.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-standard.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-standard.codewords index 911cf43..4414274 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-standard.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-standard.codewords @@ -1,4 +1,4 @@ -34 mode 2 + part of the postal code +34 20 45 20 @@ -7,8 +7,8 @@ 2 18 7 -0 end primary message -61 start primary message error correction +0 +61 53 12 1 @@ -17,92 +17,92 @@ 55 6 31 -40 end primary message error correction -59 [Shift B] -42 [ -41 ) -59 [Shift B] -40 > -30 RS -48 0 -49 1 -29 GS -57 9 -54 6 -49 1 -26 Z -48 0 -48 0 -48 0 -48 0 -52 4 -57 9 -53 5 -49 1 -29 GS -21 U -16 P -19 S -14 N -29 GS -48 0 -54 6 -24 X -54 6 -49 1 -48 0 -29 GS -49 1 -53 5 -57 9 -29 GS -49 1 -50 2 -51 3 -52 4 -53 5 -54 6 -55 7 -29 GS -49 1 -47 / -49 1 -29 GS -29 GS -25 Y -29 GS -54 6 -51 3 -52 4 -32 -1 A -12 L -16 P -8 H -1 A -32 -4 D -18 R -29 GS -16 P -9 I -20 T -20 T -19 S -2 B -21 U -18 R -7 G -8 H -29 GS -16 P -1 A -30 RS -62 [Shift E] -4 EOT -33 start padding +40 +59 +42 +41 +59 +40 +30 +48 +49 +29 +57 +54 +49 +26 +48 +48 +48 +48 +52 +57 +53 +49 +29 +21 +16 +19 +14 +29 +48 +54 +24 +54 +49 +48 +29 +49 +53 +57 +29 +49 +50 +51 +52 +53 +54 +55 +29 +49 +47 +49 +29 +29 +25 +29 +54 +51 +52 +32 +1 +12 +16 +8 +1 +32 +4 +18 +29 +16 +9 +20 +20 +19 +2 +21 +18 +7 +8 +29 +16 +1 +30 +62 +4 33 -44 start secondary message error correction +33 +44 40 52 23 @@ -141,4 +141,4 @@ 40 17 49 -31 end secondary message error correction +31 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-standard.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-standard.png index 2baf8d9..a5104fa 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-standard.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-standard.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-structured-append-1-of-8.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-structured-append-1-of-8.codewords index c5714ed..15cf82e 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-structured-append-1-of-8.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-structured-append-1-of-8.codewords @@ -1,4 +1,4 @@ -34 mode 2 + part of the postal code +34 20 45 20 @@ -7,8 +7,8 @@ 2 18 7 -0 end primary message -61 start primary message error correction +0 +61 53 12 1 @@ -17,9 +17,9 @@ 55 6 31 -40 end primary message error correction -33 padding -7 structured append 1 of 8 = 000 111 = 7 +40 +33 +7 59 42 41 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-structured-append-1-of-8.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-structured-append-1-of-8.png index 2b55ec9..6f5e7d1 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-structured-append-1-of-8.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-2-structured-append-1-of-8.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-3-standard.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-3-standard.codewords index db2e4c2..b7eaaf4 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-3-standard.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-3-standard.codewords @@ -1,4 +1,4 @@ -19 mode 3 + part of the postal code +19 28 16 28 @@ -8,7 +8,7 @@ 31 4 0 -59 start primary message error correction +59 33 49 2 @@ -18,7 +18,7 @@ 0 48 25 -59 start secondary message +59 42 41 59 @@ -102,7 +102,7 @@ 4 33 33 -44 start secondary message error correction +44 40 52 23 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-3-standard.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-3-standard.png index 36d9932..f8899b5 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-3-standard.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-3-standard.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-basic-structured-append-total-1.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-basic-structured-append-total-1.codewords index cecd045..4bbb8f3 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-basic-structured-append-total-1.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-basic-structured-append-total-1.codewords @@ -1,14 +1,14 @@ -4 mode 4 -1 A -2 B -3 C -33 start padding +4 +1 +2 +3 33 33 33 33 33 -13 start primary message error correction +33 +13 1 28 60 @@ -17,8 +17,7 @@ 0 48 52 -15 end primary message error correction -33 start secondary message +15 33 33 33 @@ -102,7 +101,8 @@ 33 33 33 -60 start secondary message error correction +33 +60 60 40 40 @@ -141,4 +141,4 @@ 31 31 40 -40 end secondary message error correction +40 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-basic-structured-append-total-1.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-basic-structured-append-total-1.png index 050f89a..0d8415f 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-basic-structured-append-total-1.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-basic-structured-append-total-1.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-basic.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-basic.codewords index cecd045..4bbb8f3 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-basic.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-basic.codewords @@ -1,14 +1,14 @@ -4 mode 4 -1 A -2 B -3 C -33 start padding +4 +1 +2 +3 33 33 33 33 33 -13 start primary message error correction +33 +13 1 28 60 @@ -17,8 +17,7 @@ 0 48 52 -15 end primary message error correction -33 start secondary message +15 33 33 33 @@ -102,7 +101,8 @@ 33 33 33 -60 start secondary message error correction +33 +60 60 40 40 @@ -141,4 +141,4 @@ 31 31 40 -40 end secondary message error correction +40 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-basic.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-basic.png index 050f89a..0d8415f 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-basic.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-basic.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-set-a-all-symbols.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-set-a-all-symbols.codewords index 12a96a0..2ce8eb8 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-set-a-all-symbols.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-set-a-all-symbols.codewords @@ -1,5 +1,5 @@ -4 mode 4 -0 start primary message +4 +0 1 2 3 @@ -7,8 +7,8 @@ 5 6 7 -8 end primary message -52 start primary message error correction +8 +52 20 12 4 @@ -17,8 +17,8 @@ 12 15 8 -39 end primary message error correction -9 start secondary message +39 +9 10 11 12 @@ -65,7 +65,6 @@ 55 56 57 -33 start padding 33 33 33 @@ -101,8 +100,9 @@ 33 33 33 -33 end secondary message -57 start secondary message error correction +33 +33 +57 9 46 29 @@ -141,4 +141,4 @@ 34 31 61 -46 end secondary message error correction +46 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-set-a-all-symbols.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-set-a-all-symbols.png index c437156..2a8bff8 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-set-a-all-symbols.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-set-a-all-symbols.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-set-b-all-symbols.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-set-b-all-symbols.codewords index fe1d3d2..27a051e 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-set-b-all-symbols.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-set-b-all-symbols.codewords @@ -1,5 +1,5 @@ -4 mode 4 -63 [Latch B], since next 2+ chars are in Code Set B +4 +63 0 1 2 @@ -8,7 +8,7 @@ 5 6 7 -42 start primary message error correction +42 34 1 61 @@ -17,8 +17,8 @@ 59 47 38 -7 end primary message error correction -8 start secondary message +7 +8 9 10 11 @@ -62,7 +62,6 @@ 52 53 54 -33 start padding 33 33 33 @@ -101,8 +100,9 @@ 33 33 33 -33 end secondary message -8 start secondary message error correction +33 +33 +8 25 22 26 @@ -141,4 +141,4 @@ 48 40 9 -10 end secondary message error correction +10 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-set-b-all-symbols.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-set-b-all-symbols.png index 1241727..be06461 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-set-b-all-symbols.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-set-b-all-symbols.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-sets-a-and-b.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-sets-a-and-b.codewords index f19a9b2..26b9717 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-sets-a-and-b.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-sets-a-and-b.codewords @@ -1,14 +1,14 @@ -4 mode 4 -1 A -59 [Shift B], since only next 1 char is in Code Set B -2 b -1 A -1 A -1 A -63 [Latch B], since next 2 chars are in Code Set B -2 b -2 b -11 start primary message error correction +4 +1 +59 +2 +1 +1 +1 +63 +2 +2 +11 13 16 33 @@ -17,34 +17,33 @@ 48 15 56 -56 end primary message error correction -59 [Shift A], since only next 1 char is in Code Set A -1 A -2 b -2 b -2 b -63 [Latch A], since next 4 chars are in Code Set A -1 A -1 A -1 A -1 A -63 [Latch B], since next 2 chars are in Code Set B -2 b -2 b -57 [3 Shift A], since next 3 chars are in Code Set A -1 A -1 A -1 A -2 b -2 b -56 [2 Shift A], since next 2 chars are in Code Set A -1 A -1 A -2 b -2 b -63 [Latch A], since next 4 chars (including padding) are in Code Set A -1 A -33 start padding +56 +59 +1 +2 +2 +2 +63 +1 +1 +1 +1 +63 +2 +2 +57 +1 +1 +1 +2 +2 +56 +1 +1 +2 +2 +63 +1 33 33 33 @@ -102,7 +101,8 @@ 33 33 33 -18 start secondary message error correction +33 +18 45 20 58 @@ -141,4 +141,4 @@ 52 57 59 -53 end secondary message error correction +53 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-sets-a-and-b.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-sets-a-and-b.png index 6c7f145..46a21e8 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-sets-a-and-b.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-sets-a-and-b.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-sets-c-d-e.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-sets-c-d-e.codewords index c18a172..e9c3e1b 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-sets-c-d-e.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-sets-c-d-e.codewords @@ -1,14 +1,14 @@ -4 mode 4 -60 [Shift C] +4 +60 7 -61 [Shift D] +61 17 -62 [Shift E] +62 39 -60 [Shift C] +60 7 -60 [Shift C] -34 start primary message error correction +60 +34 18 16 28 @@ -17,75 +17,74 @@ 1 47 51 -8 end primary message error correction -7 start secondary message -61 [Shift D] -17 -61 [Shift D] -17 -62 [Shift E] -39 -62 [Shift E] -39 -60 [Shift C] +8 7 -60 [Shift C] +61 +17 +61 +17 +62 +39 +62 +39 +60 7 -60 [Shift C] +60 7 -61 [Shift D] +60 +7 +61 17 -61 [Shift D] +61 17 -61 [Shift D] +61 17 -62 [Shift E] +62 39 -62 [Shift E] +62 39 -62 [Shift E] +62 39 -60 [Shift C] -60 [Lock In C] +60 +60 7 7 7 7 -61 [Shift D] -61 [Lock In D] +61 +61 17 17 17 17 -62 [Shift E] -62 [Lock In E] +62 +62 39 39 39 39 -60 [Shift C] -60 [Lock In C] +60 +60 7 7 7 7 7 -61 [Shift D] -61 [Lock In D] +61 +61 17 17 17 17 17 -62 [Shift E] -62 [Lock In E] +62 +62 39 39 39 39 39 -63 [Latch B] -33 start padding +63 33 33 33 @@ -102,7 +101,8 @@ 33 33 33 -5 start secondary message error correction +33 +5 43 15 62 @@ -141,4 +141,4 @@ 29 16 61 -5 end secondary message error correction +5 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-sets-c-d-e.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-sets-c-d-e.png index 1bacd8d..7f78d8f 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-sets-c-d-e.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-code-sets-c-d-e.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-max-data.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-max-data.codewords index 2f0b147..f0f238e 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-max-data.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-max-data.codewords @@ -1,4 +1,4 @@ -4 mode 4 +4 1 2 3 @@ -8,7 +8,7 @@ 7 8 9 -2 start primary message error correction +2 35 59 36 @@ -17,8 +17,8 @@ 42 17 52 -51 end primary message error correction -10 start secondary message +51 +10 11 12 13 @@ -101,8 +101,8 @@ 12 13 14 -15 end secondary message -58 start secondary message error correction +15 +58 47 56 17 @@ -141,4 +141,4 @@ 26 25 39 -9 end secondary message error correction +9 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-max-data.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-max-data.png index f328de4..bb057c5 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-max-data.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-max-data.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-numeric-shift.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-numeric-shift.codewords index bad69e1..f5f1354 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-numeric-shift.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-numeric-shift.codewords @@ -1,14 +1,14 @@ -4 mode 4 -31 start numeric shift [NS] -7 numeric compression codeword 1 -22 numeric compression codeword 2 -60 numeric compression codeword 3 -52 numeric compression codeword 4 -21 numeric compression codeword 5 -1 A -1 A -1 A -40 start primary message error correction +4 +31 +7 +22 +60 +52 +21 +1 +1 +1 +40 60 12 24 @@ -17,16 +17,15 @@ 21 40 5 -55 end primary message error correction -1 A -1 A -31 start numeric shift [NS] -58 numeric compression codeword 1 -55 numeric compression codeword 2 -38 numeric compression codeword 3 -34 numeric compression codeword 4 -49 numeric compression codeword 5 -33 start padding +55 +1 +1 +31 +58 +55 +38 +34 +49 33 33 33 @@ -102,7 +101,8 @@ 33 33 33 -47 start secondary message error correction +33 +47 46 50 54 @@ -141,4 +141,4 @@ 21 26 43 -47 end secondary message error correction +47 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-numeric-shift.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-numeric-shift.png index bd503aa..7434de5 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-numeric-shift.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-numeric-shift.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-1-of-3.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-1-of-3.codewords index cd9a1cc..bfc08ff 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-1-of-3.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-1-of-3.codewords @@ -1,6 +1,6 @@ -4 mode 4 -33 padding -2 structured append 1 of 3 = 000 010 = 2 +4 +33 +2 1 2 3 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-1-of-3.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-1-of-3.png index 740155b..a8066cc 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-1-of-3.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-1-of-3.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-2-of-3.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-2-of-3.codewords index ab8376d..5a1964e 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-2-of-3.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-2-of-3.codewords @@ -1,6 +1,6 @@ -4 mode 4 -33 padding -10 structured append 2 of 3 = 001 010 = 10 +4 +33 +10 4 5 6 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-2-of-3.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-2-of-3.png index c53022d..d397d82 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-2-of-3.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-2-of-3.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-3-of-3.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-3-of-3.codewords index 29c6d75..03f0d0d 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-3-of-3.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-3-of-3.codewords @@ -1,6 +1,6 @@ -4 mode 4 -33 padding -18 structured append 3 of 3 = 010 010 = 18 +4 +33 +18 7 8 9 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-3-of-3.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-3-of-3.png index d415e00..19ca07a 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-3-of-3.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-4-structured-append-3-of-3.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-5-basic.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-5-basic.codewords index 78bfe26..38d6225 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-5-basic.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-5-basic.codewords @@ -1,14 +1,14 @@ -5 mode 5 -1 A -2 B -3 C -33 start padding +5 +1 +2 +3 33 33 33 33 33 -26 start primary message error correction +33 +26 33 12 53 @@ -17,8 +17,7 @@ 21 37 45 -59 end primary message error correction -33 start secondary message +59 33 33 33 @@ -85,8 +84,9 @@ 33 33 33 -33 end secondary message -5 start secondary message error correction +33 +33 +5 5 39 39 @@ -141,4 +141,4 @@ 44 44 34 -34 end secondary message error correction +34 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-5-basic.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-5-basic.png index b439a4d..c123be1 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-5-basic.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-5-basic.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-5-max-data.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-5-max-data.codewords index f32c2aa..9898279 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-5-max-data.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-5-max-data.codewords @@ -1,4 +1,4 @@ -5 mode 5 +5 1 2 3 @@ -8,7 +8,7 @@ 7 8 9 -21 start primary message error correction +21 3 43 45 @@ -17,33 +17,7 @@ 63 4 45 -7 end primary message error correction -10 start secondary message -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -1 -2 -3 -4 -5 -6 7 -8 -9 10 11 12 @@ -85,8 +59,34 @@ 22 23 24 -25 end secondary message -5 start secondary message error correction +25 +26 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +5 60 20 38 @@ -141,4 +141,4 @@ 36 53 20 -11 end secondary message error correction +11 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-5-max-data.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-5-max-data.png index 0d33bb5..a2dbc17 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-5-max-data.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-5-max-data.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-6-max-data.codewords b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-6-max-data.codewords index 0f1d58a..de60c56 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-6-max-data.codewords +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-6-max-data.codewords @@ -1,5 +1,4 @@ -6 mode 6 -47 start primary message +6 47 47 47 @@ -7,8 +6,9 @@ 47 47 47 -47 end primary message -37 start primary message error correction +47 +47 +37 32 5 29 @@ -17,8 +17,7 @@ 35 21 27 -58 end primary message error correction -47 start secondary message +58 47 47 47 @@ -101,8 +100,9 @@ 47 47 47 -47 end secondary message -49 start secondary message error correction +47 +47 +49 49 31 31 @@ -141,4 +141,4 @@ 36 36 31 -31 end secondary message error correction +31 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-6-max-data.png b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-6-max-data.png index 71aec56..ad93ba1 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-6-max-data.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/maxicode/mode-6-max-data.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-basic.eps b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-basic.eps old mode 100755 new mode 100644 index 62bea42..62db211 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-basic.eps +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-basic.eps @@ -1,71 +1,76 @@ %!PS-Adobe-3.0 EPSF-3.0 -%%Creator: OkapiBarcode -%%Title: 123456789 -%%Pages: 0 -%%BoundingBox: 0 0 128 60 +%%BoundingBox: 0 0 363 171 +%%HiResBoundingBox: 0.0 0.0 362.8346456692914 170.07874015748033 +%%LanguageLevel: 3 +%%Pages: 1 %%EndComments -/TL { setlinewidth moveto lineto stroke } bind def -/TC { moveto 0 360 arc 360 0 arcn fill } bind def -/TH { 0 setlinewidth moveto lineto lineto lineto lineto lineto closepath fill } bind def -/TB { 2 copy } bind def -/TR { newpath 4 1 roll exch moveto 1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath fill } bind def -/TE { pop pop } bind def -newpath -0.00 0.00 0.00 setrgbcolor -1.00 1.00 1.00 setrgbcolor -60.00 0.00 TB 0.00 128.00 TR -TE -0.00 0.00 0.00 setrgbcolor -40.00 15.00 TB 5.00 1.00 TR -TB 7.00 1.00 TR -TB 9.00 4.00 TR -TB 14.00 1.00 TR -TB 16.00 1.00 TR -TB 19.00 1.00 TR -TB 23.00 1.00 TR -TB 25.00 1.00 TR -TB 29.00 1.00 TR -TB 32.00 1.00 TR -TB 34.00 1.00 TR -TB 39.00 1.00 TR -TB 41.00 1.00 TR -TB 44.00 1.00 TR -TB 46.00 1.00 TR -TB 50.00 1.00 TR -TB 53.00 1.00 TR -TB 56.00 1.00 TR -TB 59.00 1.00 TR -TB 62.00 1.00 TR -TB 66.00 1.00 TR -TB 68.00 1.00 TR -TB 70.00 1.00 TR -TB 72.00 1.00 TR -TB 77.00 1.00 TR -TB 81.00 1.00 TR -TB 84.00 1.00 TR -TB 86.00 1.00 TR -TB 91.00 1.00 TR -TB 93.00 1.00 TR -TB 95.00 1.00 TR -TB 98.00 1.00 TR -TB 100.00 2.00 TR -TB 104.00 1.00 TR -TB 107.00 2.00 TR -TB 111.00 1.00 TR -TB 113.00 1.00 TR -TB 115.00 1.00 TR -TB 117.00 4.00 TR -TB 122.00 1.00 TR -TE -0.00 0.00 0.00 setrgbcolor -matrix currentmatrix -/Helvetica findfont -8.00 scalefont setfont - 0 0 moveto 64.00 7.00 translate 0.00 rotate 0 0 moveto - (123456789Od) stringwidth -pop --2 div 0 rmoveto - (123456789Od) show -setmatrix - -showpage +%%Page: 1 1 +/M /moveto load def +/L /lineto load def +/C /curveto load def +/Z /closepath load def +/RL /rlineto load def +/rgb /setrgbcolor load def +/rect { /height exch def /width exch def /y exch def /x exch def x y M width 0 RL 0 height RL width neg 0 RL } bind def +/ellipse { /endangle exch def /startangle exch def /ry exch def /rx exch def /y exch def /x exch def /savematrix matrix currentmatrix def x y translate rx ry scale 0 0 1 startangle endangle arcn savematrix setmatrix } bind def +/imgdict { /datastream exch def /hasdata exch def /decodeScale exch def /bits exch def /bands exch def /imgheight exch def /imgwidth exch def << /ImageType 1 /Width imgwidth /Height imgheight /BitsPerComponent bits /Decode [bands {0 decodeScale} repeat] +/ImageMatrix [imgwidth 0 0 imgheight 0 0] hasdata { /DataSource datastream } if >> } bind def +/latinize { /fontName exch def /fontNameNew exch def fontName findfont 0 dict copy begin /Encoding ISOLatin1Encoding def fontNameNew /FontName def currentdict end dup /FID undef fontNameNew exch definefont pop } bind def +/LucidaGrandeLat /LucidaGrande latinize /LucidaGrandeLat 12.0 selectfont +gsave +clipsave +/DeviceRGB setcolorspace +0 170.07874015748033 translate +2.834645669291339 -2.834645669291339 scale +/basematrix matrix currentmatrix def +gsave +0.0 0.0 0.0 rgb +1.0 setlinewidth 0 setlinejoin 0 setlinecap [] 0.0 setdash +1.0 1.0 1.0 rgb +newpath 0.0 0.0 1920.0 1200.0 rect Z fill +0.0 0.0 0.0 rgb +newpath 5.0 5.0 M 6.0 5.0 L 6.0 45.0 L 5.0 45.0 L Z fill +newpath 7.0 5.0 M 8.0 5.0 L 8.0 45.0 L 7.0 45.0 L Z fill +newpath 9.0 5.0 M 13.0 5.0 L 13.0 45.0 L 9.0 45.0 L Z fill +newpath 14.0 5.0 M 15.0 5.0 L 15.0 45.0 L 14.0 45.0 L Z fill +newpath 16.0 5.0 M 17.0 5.0 L 17.0 45.0 L 16.0 45.0 L Z fill +newpath 19.0 5.0 M 20.0 5.0 L 20.0 45.0 L 19.0 45.0 L Z fill +newpath 23.0 5.0 M 24.0 5.0 L 24.0 45.0 L 23.0 45.0 L Z fill +newpath 25.0 5.0 M 26.0 5.0 L 26.0 45.0 L 25.0 45.0 L Z fill +newpath 29.0 5.0 M 30.0 5.0 L 30.0 45.0 L 29.0 45.0 L Z fill +newpath 32.0 5.0 M 33.0 5.0 L 33.0 45.0 L 32.0 45.0 L Z fill +newpath 34.0 5.0 M 35.0 5.0 L 35.0 45.0 L 34.0 45.0 L Z fill +newpath 39.0 5.0 M 40.0 5.0 L 40.0 45.0 L 39.0 45.0 L Z fill +newpath 41.0 5.0 M 42.0 5.0 L 42.0 45.0 L 41.0 45.0 L Z fill +newpath 44.0 5.0 M 45.0 5.0 L 45.0 45.0 L 44.0 45.0 L Z fill +newpath 46.0 5.0 M 47.0 5.0 L 47.0 45.0 L 46.0 45.0 L Z fill +newpath 50.0 5.0 M 51.0 5.0 L 51.0 45.0 L 50.0 45.0 L Z fill +newpath 53.0 5.0 M 54.0 5.0 L 54.0 45.0 L 53.0 45.0 L Z fill +newpath 56.0 5.0 M 57.0 5.0 L 57.0 45.0 L 56.0 45.0 L Z fill +newpath 59.0 5.0 M 60.0 5.0 L 60.0 45.0 L 59.0 45.0 L Z fill +newpath 62.0 5.0 M 63.0 5.0 L 63.0 45.0 L 62.0 45.0 L Z fill +newpath 66.0 5.0 M 67.0 5.0 L 67.0 45.0 L 66.0 45.0 L Z fill +newpath 68.0 5.0 M 69.0 5.0 L 69.0 45.0 L 68.0 45.0 L Z fill +newpath 70.0 5.0 M 71.0 5.0 L 71.0 45.0 L 70.0 45.0 L Z fill +newpath 72.0 5.0 M 73.0 5.0 L 73.0 45.0 L 72.0 45.0 L Z fill +newpath 77.0 5.0 M 78.0 5.0 L 78.0 45.0 L 77.0 45.0 L Z fill +newpath 81.0 5.0 M 82.0 5.0 L 82.0 45.0 L 81.0 45.0 L Z fill +newpath 84.0 5.0 M 85.0 5.0 L 85.0 45.0 L 84.0 45.0 L Z fill +newpath 86.0 5.0 M 87.0 5.0 L 87.0 45.0 L 86.0 45.0 L Z fill +newpath 91.0 5.0 M 92.0 5.0 L 92.0 45.0 L 91.0 45.0 L Z fill +newpath 93.0 5.0 M 94.0 5.0 L 94.0 45.0 L 93.0 45.0 L Z fill +newpath 95.0 5.0 M 96.0 5.0 L 96.0 45.0 L 95.0 45.0 L Z fill +newpath 98.0 5.0 M 99.0 5.0 L 99.0 45.0 L 98.0 45.0 L Z fill +newpath 100.0 5.0 M 102.0 5.0 L 102.0 45.0 L 100.0 45.0 L Z fill +newpath 104.0 5.0 M 105.0 5.0 L 105.0 45.0 L 104.0 45.0 L Z fill +newpath 107.0 5.0 M 109.0 5.0 L 109.0 45.0 L 107.0 45.0 L Z fill +newpath 111.0 5.0 M 112.0 5.0 L 112.0 45.0 L 111.0 45.0 L Z fill +newpath 113.0 5.0 M 114.0 5.0 L 114.0 45.0 L 113.0 45.0 L Z fill +newpath 115.0 5.0 M 116.0 5.0 L 116.0 45.0 L 115.0 45.0 L Z fill +newpath 117.0 5.0 M 121.0 5.0 L 121.0 45.0 L 117.0 45.0 L Z fill +newpath 122.0 5.0 M 123.0 5.0 L 123.0 45.0 L 122.0 45.0 L Z fill +/HelveticaLat /Helvetica latinize /HelveticaLat 8.0 selectfont +gsave 1 -1 scale 41.0 -53.0 M (123456789Od) show grestore +/LucidaGrandeLat /LucidaGrande latinize /LucidaGrandeLat 12.0 selectfont +grestore +%%EOF \ No newline at end of file diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-basic.svg b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-basic.svg old mode 100755 new mode 100644 index 9d52bd0..9e54698 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-basic.svg +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-basic.svg @@ -1,53 +1,46 @@ - - - - 123456789 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 123456789Od - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 123456789Od diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-colors.eps b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-colors.eps old mode 100755 new mode 100644 index 1853e2f..cf91e96 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-colors.eps +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-colors.eps @@ -1,71 +1,77 @@ %!PS-Adobe-3.0 EPSF-3.0 -%%Creator: OkapiBarcode -%%Title: 123456789 -%%Pages: 0 -%%BoundingBox: 0 0 128 60 +%%BoundingBox: 0 0 363 171 +%%HiResBoundingBox: 0.0 0.0 362.8346456692914 170.07874015748033 +%%LanguageLevel: 3 +%%Pages: 1 %%EndComments -/TL { setlinewidth moveto lineto stroke } bind def -/TC { moveto 0 360 arc 360 0 arcn fill } bind def -/TH { 0 setlinewidth moveto lineto lineto lineto lineto lineto closepath fill } bind def -/TB { 2 copy } bind def -/TR { newpath 4 1 roll exch moveto 1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath fill } bind def -/TE { pop pop } bind def -newpath -1.00 0.00 0.00 setrgbcolor -0.00 1.00 0.00 setrgbcolor -60.00 0.00 TB 0.00 128.00 TR -TE -1.00 0.00 0.00 setrgbcolor -40.00 15.00 TB 5.00 1.00 TR -TB 7.00 1.00 TR -TB 9.00 4.00 TR -TB 14.00 1.00 TR -TB 16.00 1.00 TR -TB 19.00 1.00 TR -TB 23.00 1.00 TR -TB 25.00 1.00 TR -TB 29.00 1.00 TR -TB 32.00 1.00 TR -TB 34.00 1.00 TR -TB 39.00 1.00 TR -TB 41.00 1.00 TR -TB 44.00 1.00 TR -TB 46.00 1.00 TR -TB 50.00 1.00 TR -TB 53.00 1.00 TR -TB 56.00 1.00 TR -TB 59.00 1.00 TR -TB 62.00 1.00 TR -TB 66.00 1.00 TR -TB 68.00 1.00 TR -TB 70.00 1.00 TR -TB 72.00 1.00 TR -TB 77.00 1.00 TR -TB 81.00 1.00 TR -TB 84.00 1.00 TR -TB 86.00 1.00 TR -TB 91.00 1.00 TR -TB 93.00 1.00 TR -TB 95.00 1.00 TR -TB 98.00 1.00 TR -TB 100.00 2.00 TR -TB 104.00 1.00 TR -TB 107.00 2.00 TR -TB 111.00 1.00 TR -TB 113.00 1.00 TR -TB 115.00 1.00 TR -TB 117.00 4.00 TR -TB 122.00 1.00 TR -TE -1.00 0.00 0.00 setrgbcolor -matrix currentmatrix -/Helvetica findfont -8.00 scalefont setfont - 0 0 moveto 64.00 7.00 translate 0.00 rotate 0 0 moveto - (123456789Od) stringwidth -pop --2 div 0 rmoveto - (123456789Od) show -setmatrix - -showpage +%%Page: 1 1 +/M /moveto load def +/L /lineto load def +/C /curveto load def +/Z /closepath load def +/RL /rlineto load def +/rgb /setrgbcolor load def +/rect { /height exch def /width exch def /y exch def /x exch def x y M width 0 RL 0 height RL width neg 0 RL } bind def +/ellipse { /endangle exch def /startangle exch def /ry exch def /rx exch def /y exch def /x exch def /savematrix matrix currentmatrix def x y translate rx ry scale 0 0 1 startangle endangle arcn savematrix setmatrix } bind def +/imgdict { /datastream exch def /hasdata exch def /decodeScale exch def /bits exch def /bands exch def /imgheight exch def /imgwidth exch def << /ImageType 1 /Width imgwidth /Height imgheight /BitsPerComponent bits /Decode [bands {0 decodeScale} repeat] +/ImageMatrix [imgwidth 0 0 imgheight 0 0] hasdata { /DataSource datastream } if >> } bind def +/latinize { /fontName exch def /fontNameNew exch def fontName findfont 0 dict copy begin /Encoding ISOLatin1Encoding def fontNameNew /FontName def currentdict end dup /FID undef fontNameNew exch definefont pop } bind def +/LucidaGrandeLat /LucidaGrande latinize /LucidaGrandeLat 12.0 selectfont +gsave +clipsave +/DeviceRGB setcolorspace +0 170.07874015748033 translate +2.834645669291339 -2.834645669291339 scale +/basematrix matrix currentmatrix def +gsave +0.0 0.0 0.0 rgb +1.0 setlinewidth 0 setlinejoin 0 setlinecap [] 0.0 setdash +0.0 1.0 0.0 rgb +newpath 0.0 0.0 1920.0 1200.0 rect Z fill +1.0 0.0 0.0 rgb +newpath 5.0 5.0 M 6.0 5.0 L 6.0 45.0 L 5.0 45.0 L Z fill +newpath 7.0 5.0 M 8.0 5.0 L 8.0 45.0 L 7.0 45.0 L Z fill +newpath 9.0 5.0 M 13.0 5.0 L 13.0 45.0 L 9.0 45.0 L Z fill +newpath 14.0 5.0 M 15.0 5.0 L 15.0 45.0 L 14.0 45.0 L Z fill +newpath 16.0 5.0 M 17.0 5.0 L 17.0 45.0 L 16.0 45.0 L Z fill +newpath 19.0 5.0 M 20.0 5.0 L 20.0 45.0 L 19.0 45.0 L Z fill +newpath 23.0 5.0 M 24.0 5.0 L 24.0 45.0 L 23.0 45.0 L Z fill +newpath 25.0 5.0 M 26.0 5.0 L 26.0 45.0 L 25.0 45.0 L Z fill +newpath 29.0 5.0 M 30.0 5.0 L 30.0 45.0 L 29.0 45.0 L Z fill +newpath 32.0 5.0 M 33.0 5.0 L 33.0 45.0 L 32.0 45.0 L Z fill +newpath 34.0 5.0 M 35.0 5.0 L 35.0 45.0 L 34.0 45.0 L Z fill +newpath 39.0 5.0 M 40.0 5.0 L 40.0 45.0 L 39.0 45.0 L Z fill +newpath 41.0 5.0 M 42.0 5.0 L 42.0 45.0 L 41.0 45.0 L Z fill +newpath 44.0 5.0 M 45.0 5.0 L 45.0 45.0 L 44.0 45.0 L Z fill +newpath 46.0 5.0 M 47.0 5.0 L 47.0 45.0 L 46.0 45.0 L Z fill +newpath 50.0 5.0 M 51.0 5.0 L 51.0 45.0 L 50.0 45.0 L Z fill +newpath 53.0 5.0 M 54.0 5.0 L 54.0 45.0 L 53.0 45.0 L Z fill +newpath 56.0 5.0 M 57.0 5.0 L 57.0 45.0 L 56.0 45.0 L Z fill +newpath 59.0 5.0 M 60.0 5.0 L 60.0 45.0 L 59.0 45.0 L Z fill +newpath 62.0 5.0 M 63.0 5.0 L 63.0 45.0 L 62.0 45.0 L Z fill +newpath 66.0 5.0 M 67.0 5.0 L 67.0 45.0 L 66.0 45.0 L Z fill +newpath 68.0 5.0 M 69.0 5.0 L 69.0 45.0 L 68.0 45.0 L Z fill +newpath 70.0 5.0 M 71.0 5.0 L 71.0 45.0 L 70.0 45.0 L Z fill +newpath 72.0 5.0 M 73.0 5.0 L 73.0 45.0 L 72.0 45.0 L Z fill +newpath 77.0 5.0 M 78.0 5.0 L 78.0 45.0 L 77.0 45.0 L Z fill +newpath 81.0 5.0 M 82.0 5.0 L 82.0 45.0 L 81.0 45.0 L Z fill +newpath 84.0 5.0 M 85.0 5.0 L 85.0 45.0 L 84.0 45.0 L Z fill +newpath 86.0 5.0 M 87.0 5.0 L 87.0 45.0 L 86.0 45.0 L Z fill +newpath 91.0 5.0 M 92.0 5.0 L 92.0 45.0 L 91.0 45.0 L Z fill +newpath 93.0 5.0 M 94.0 5.0 L 94.0 45.0 L 93.0 45.0 L Z fill +newpath 95.0 5.0 M 96.0 5.0 L 96.0 45.0 L 95.0 45.0 L Z fill +newpath 98.0 5.0 M 99.0 5.0 L 99.0 45.0 L 98.0 45.0 L Z fill +newpath 100.0 5.0 M 102.0 5.0 L 102.0 45.0 L 100.0 45.0 L Z fill +newpath 104.0 5.0 M 105.0 5.0 L 105.0 45.0 L 104.0 45.0 L Z fill +newpath 107.0 5.0 M 109.0 5.0 L 109.0 45.0 L 107.0 45.0 L Z fill +newpath 111.0 5.0 M 112.0 5.0 L 112.0 45.0 L 111.0 45.0 L Z fill +newpath 113.0 5.0 M 114.0 5.0 L 114.0 45.0 L 113.0 45.0 L Z fill +newpath 115.0 5.0 M 116.0 5.0 L 116.0 45.0 L 115.0 45.0 L Z fill +newpath 117.0 5.0 M 121.0 5.0 L 121.0 45.0 L 117.0 45.0 L Z fill +newpath 122.0 5.0 M 123.0 5.0 L 123.0 45.0 L 122.0 45.0 L Z fill +/HelveticaLat /Helvetica latinize /HelveticaLat 8.0 selectfont +gsave 1 -1 scale 41.0 -53.0 M (123456789Od) show grestore +/LucidaGrandeLat /LucidaGrande latinize /LucidaGrandeLat 12.0 selectfont +0.0 0.0 0.0 rgb +grestore +%%EOF \ No newline at end of file diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-colors.svg b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-colors.svg old mode 100755 new mode 100644 index cab3f5b..fe65e8a --- a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-colors.svg +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-colors.svg @@ -1,53 +1,46 @@ - - - - 123456789 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 123456789Od - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 123456789Od diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-custom-font.eps b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-custom-font.eps old mode 100755 new mode 100644 index 18ba809..b1d5e52 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-custom-font.eps +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-custom-font.eps @@ -1,71 +1,76 @@ %!PS-Adobe-3.0 EPSF-3.0 -%%Creator: OkapiBarcode -%%Title: 123456789 -%%Pages: 0 -%%BoundingBox: 0 0 128 82 +%%BoundingBox: 0 0 363 233 +%%HiResBoundingBox: 0.0 0.0 362.8346456692914 232.44094488188978 +%%LanguageLevel: 3 +%%Pages: 1 %%EndComments -/TL { setlinewidth moveto lineto stroke } bind def -/TC { moveto 0 360 arc 360 0 arcn fill } bind def -/TH { 0 setlinewidth moveto lineto lineto lineto lineto lineto closepath fill } bind def -/TB { 2 copy } bind def -/TR { newpath 4 1 roll exch moveto 1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath fill } bind def -/TE { pop pop } bind def -newpath -0.00 0.00 0.00 setrgbcolor -1.00 1.00 1.00 setrgbcolor -82.00 0.00 TB 0.00 128.00 TR -TE -0.00 0.00 0.00 setrgbcolor -40.00 37.00 TB 5.00 1.00 TR -TB 7.00 1.00 TR -TB 9.00 4.00 TR -TB 14.00 1.00 TR -TB 16.00 1.00 TR -TB 19.00 1.00 TR -TB 23.00 1.00 TR -TB 25.00 1.00 TR -TB 29.00 1.00 TR -TB 32.00 1.00 TR -TB 34.00 1.00 TR -TB 39.00 1.00 TR -TB 41.00 1.00 TR -TB 44.00 1.00 TR -TB 46.00 1.00 TR -TB 50.00 1.00 TR -TB 53.00 1.00 TR -TB 56.00 1.00 TR -TB 59.00 1.00 TR -TB 62.00 1.00 TR -TB 66.00 1.00 TR -TB 68.00 1.00 TR -TB 70.00 1.00 TR -TB 72.00 1.00 TR -TB 77.00 1.00 TR -TB 81.00 1.00 TR -TB 84.00 1.00 TR -TB 86.00 1.00 TR -TB 91.00 1.00 TR -TB 93.00 1.00 TR -TB 95.00 1.00 TR -TB 98.00 1.00 TR -TB 100.00 2.00 TR -TB 104.00 1.00 TR -TB 107.00 2.00 TR -TB 111.00 1.00 TR -TB 113.00 1.00 TR -TB 115.00 1.00 TR -TB 117.00 4.00 TR -TB 122.00 1.00 TR -TE -0.00 0.00 0.00 setrgbcolor -matrix currentmatrix -/Arial findfont -26.00 scalefont setfont - 0 0 moveto 64.00 11.00 translate 0.00 rotate 0 0 moveto - (123456789Od) stringwidth -pop --2 div 0 rmoveto - (123456789Od) show -setmatrix - -showpage +%%Page: 1 1 +/M /moveto load def +/L /lineto load def +/C /curveto load def +/Z /closepath load def +/RL /rlineto load def +/rgb /setrgbcolor load def +/rect { /height exch def /width exch def /y exch def /x exch def x y M width 0 RL 0 height RL width neg 0 RL } bind def +/ellipse { /endangle exch def /startangle exch def /ry exch def /rx exch def /y exch def /x exch def /savematrix matrix currentmatrix def x y translate rx ry scale 0 0 1 startangle endangle arcn savematrix setmatrix } bind def +/imgdict { /datastream exch def /hasdata exch def /decodeScale exch def /bits exch def /bands exch def /imgheight exch def /imgwidth exch def << /ImageType 1 /Width imgwidth /Height imgheight /BitsPerComponent bits /Decode [bands {0 decodeScale} repeat] +/ImageMatrix [imgwidth 0 0 imgheight 0 0] hasdata { /DataSource datastream } if >> } bind def +/latinize { /fontName exch def /fontNameNew exch def fontName findfont 0 dict copy begin /Encoding ISOLatin1Encoding def fontNameNew /FontName def currentdict end dup /FID undef fontNameNew exch definefont pop } bind def +/LucidaGrandeLat /LucidaGrande latinize /LucidaGrandeLat 12.0 selectfont +gsave +clipsave +/DeviceRGB setcolorspace +0 232.44094488188978 translate +2.834645669291339 -2.834645669291339 scale +/basematrix matrix currentmatrix def +gsave +0.0 0.0 0.0 rgb +1.0 setlinewidth 0 setlinejoin 0 setlinecap [] 0.0 setdash +1.0 1.0 1.0 rgb +newpath 0.0 0.0 1920.0 1200.0 rect Z fill +0.0 0.0 0.0 rgb +newpath 5.0 5.0 M 6.0 5.0 L 6.0 45.0 L 5.0 45.0 L Z fill +newpath 7.0 5.0 M 8.0 5.0 L 8.0 45.0 L 7.0 45.0 L Z fill +newpath 9.0 5.0 M 13.0 5.0 L 13.0 45.0 L 9.0 45.0 L Z fill +newpath 14.0 5.0 M 15.0 5.0 L 15.0 45.0 L 14.0 45.0 L Z fill +newpath 16.0 5.0 M 17.0 5.0 L 17.0 45.0 L 16.0 45.0 L Z fill +newpath 19.0 5.0 M 20.0 5.0 L 20.0 45.0 L 19.0 45.0 L Z fill +newpath 23.0 5.0 M 24.0 5.0 L 24.0 45.0 L 23.0 45.0 L Z fill +newpath 25.0 5.0 M 26.0 5.0 L 26.0 45.0 L 25.0 45.0 L Z fill +newpath 29.0 5.0 M 30.0 5.0 L 30.0 45.0 L 29.0 45.0 L Z fill +newpath 32.0 5.0 M 33.0 5.0 L 33.0 45.0 L 32.0 45.0 L Z fill +newpath 34.0 5.0 M 35.0 5.0 L 35.0 45.0 L 34.0 45.0 L Z fill +newpath 39.0 5.0 M 40.0 5.0 L 40.0 45.0 L 39.0 45.0 L Z fill +newpath 41.0 5.0 M 42.0 5.0 L 42.0 45.0 L 41.0 45.0 L Z fill +newpath 44.0 5.0 M 45.0 5.0 L 45.0 45.0 L 44.0 45.0 L Z fill +newpath 46.0 5.0 M 47.0 5.0 L 47.0 45.0 L 46.0 45.0 L Z fill +newpath 50.0 5.0 M 51.0 5.0 L 51.0 45.0 L 50.0 45.0 L Z fill +newpath 53.0 5.0 M 54.0 5.0 L 54.0 45.0 L 53.0 45.0 L Z fill +newpath 56.0 5.0 M 57.0 5.0 L 57.0 45.0 L 56.0 45.0 L Z fill +newpath 59.0 5.0 M 60.0 5.0 L 60.0 45.0 L 59.0 45.0 L Z fill +newpath 62.0 5.0 M 63.0 5.0 L 63.0 45.0 L 62.0 45.0 L Z fill +newpath 66.0 5.0 M 67.0 5.0 L 67.0 45.0 L 66.0 45.0 L Z fill +newpath 68.0 5.0 M 69.0 5.0 L 69.0 45.0 L 68.0 45.0 L Z fill +newpath 70.0 5.0 M 71.0 5.0 L 71.0 45.0 L 70.0 45.0 L Z fill +newpath 72.0 5.0 M 73.0 5.0 L 73.0 45.0 L 72.0 45.0 L Z fill +newpath 77.0 5.0 M 78.0 5.0 L 78.0 45.0 L 77.0 45.0 L Z fill +newpath 81.0 5.0 M 82.0 5.0 L 82.0 45.0 L 81.0 45.0 L Z fill +newpath 84.0 5.0 M 85.0 5.0 L 85.0 45.0 L 84.0 45.0 L Z fill +newpath 86.0 5.0 M 87.0 5.0 L 87.0 45.0 L 86.0 45.0 L Z fill +newpath 91.0 5.0 M 92.0 5.0 L 92.0 45.0 L 91.0 45.0 L Z fill +newpath 93.0 5.0 M 94.0 5.0 L 94.0 45.0 L 93.0 45.0 L Z fill +newpath 95.0 5.0 M 96.0 5.0 L 96.0 45.0 L 95.0 45.0 L Z fill +newpath 98.0 5.0 M 99.0 5.0 L 99.0 45.0 L 98.0 45.0 L Z fill +newpath 100.0 5.0 M 102.0 5.0 L 102.0 45.0 L 100.0 45.0 L Z fill +newpath 104.0 5.0 M 105.0 5.0 L 105.0 45.0 L 104.0 45.0 L Z fill +newpath 107.0 5.0 M 109.0 5.0 L 109.0 45.0 L 107.0 45.0 L Z fill +newpath 111.0 5.0 M 112.0 5.0 L 112.0 45.0 L 111.0 45.0 L Z fill +newpath 113.0 5.0 M 114.0 5.0 L 114.0 45.0 L 113.0 45.0 L Z fill +newpath 115.0 5.0 M 116.0 5.0 L 116.0 45.0 L 115.0 45.0 L Z fill +newpath 117.0 5.0 M 121.0 5.0 L 121.0 45.0 L 117.0 45.0 L Z fill +newpath 122.0 5.0 M 123.0 5.0 L 123.0 45.0 L 122.0 45.0 L Z fill +/ArialMTLat /ArialMT latinize /ArialMTLat 26.0 selectfont +gsave 1 -1 scale -16.0 -71.0 M (123456789Od) show grestore +/LucidaGrandeLat /LucidaGrande latinize /LucidaGrandeLat 12.0 selectfont +grestore +%%EOF \ No newline at end of file diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-custom-font.svg b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-custom-font.svg old mode 100755 new mode 100644 index 5db0be1..1344d43 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-custom-font.svg +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-custom-font.svg @@ -1,53 +1,46 @@ - - - - 123456789 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 123456789Od - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 123456789Od diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-magnification-2.eps b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-magnification-2.eps old mode 100755 new mode 100644 index 1d8d66e..e35a617 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-magnification-2.eps +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-magnification-2.eps @@ -1,71 +1,76 @@ %!PS-Adobe-3.0 EPSF-3.0 -%%Creator: OkapiBarcode -%%Title: 123456789 -%%Pages: 0 -%%BoundingBox: 0 0 256 120 +%%BoundingBox: 0 0 726 341 +%%HiResBoundingBox: 0.0 0.0 725.6692913385828 340.15748031496065 +%%LanguageLevel: 3 +%%Pages: 1 %%EndComments -/TL { setlinewidth moveto lineto stroke } bind def -/TC { moveto 0 360 arc 360 0 arcn fill } bind def -/TH { 0 setlinewidth moveto lineto lineto lineto lineto lineto closepath fill } bind def -/TB { 2 copy } bind def -/TR { newpath 4 1 roll exch moveto 1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath fill } bind def -/TE { pop pop } bind def -newpath -0.00 0.00 0.00 setrgbcolor -1.00 1.00 1.00 setrgbcolor -120.00 0.00 TB 0.00 256.00 TR -TE -0.00 0.00 0.00 setrgbcolor -80.00 30.00 TB 10.00 2.00 TR -TB 14.00 2.00 TR -TB 18.00 8.00 TR -TB 28.00 2.00 TR -TB 32.00 2.00 TR -TB 38.00 2.00 TR -TB 46.00 2.00 TR -TB 50.00 2.00 TR -TB 58.00 2.00 TR -TB 64.00 2.00 TR -TB 68.00 2.00 TR -TB 78.00 2.00 TR -TB 82.00 2.00 TR -TB 88.00 2.00 TR -TB 92.00 2.00 TR -TB 100.00 2.00 TR -TB 106.00 2.00 TR -TB 112.00 2.00 TR -TB 118.00 2.00 TR -TB 124.00 2.00 TR -TB 132.00 2.00 TR -TB 136.00 2.00 TR -TB 140.00 2.00 TR -TB 144.00 2.00 TR -TB 154.00 2.00 TR -TB 162.00 2.00 TR -TB 168.00 2.00 TR -TB 172.00 2.00 TR -TB 182.00 2.00 TR -TB 186.00 2.00 TR -TB 190.00 2.00 TR -TB 196.00 2.00 TR -TB 200.00 4.00 TR -TB 208.00 2.00 TR -TB 214.00 4.00 TR -TB 222.00 2.00 TR -TB 226.00 2.00 TR -TB 230.00 2.00 TR -TB 234.00 8.00 TR -TB 244.00 2.00 TR -TE -0.00 0.00 0.00 setrgbcolor -matrix currentmatrix -/Helvetica findfont -16.00 scalefont setfont - 0 0 moveto 128.00 14.00 translate 0.00 rotate 0 0 moveto - (123456789Od) stringwidth -pop --2 div 0 rmoveto - (123456789Od) show -setmatrix - -showpage +%%Page: 1 1 +/M /moveto load def +/L /lineto load def +/C /curveto load def +/Z /closepath load def +/RL /rlineto load def +/rgb /setrgbcolor load def +/rect { /height exch def /width exch def /y exch def /x exch def x y M width 0 RL 0 height RL width neg 0 RL } bind def +/ellipse { /endangle exch def /startangle exch def /ry exch def /rx exch def /y exch def /x exch def /savematrix matrix currentmatrix def x y translate rx ry scale 0 0 1 startangle endangle arcn savematrix setmatrix } bind def +/imgdict { /datastream exch def /hasdata exch def /decodeScale exch def /bits exch def /bands exch def /imgheight exch def /imgwidth exch def << /ImageType 1 /Width imgwidth /Height imgheight /BitsPerComponent bits /Decode [bands {0 decodeScale} repeat] +/ImageMatrix [imgwidth 0 0 imgheight 0 0] hasdata { /DataSource datastream } if >> } bind def +/latinize { /fontName exch def /fontNameNew exch def fontName findfont 0 dict copy begin /Encoding ISOLatin1Encoding def fontNameNew /FontName def currentdict end dup /FID undef fontNameNew exch definefont pop } bind def +/LucidaGrandeLat /LucidaGrande latinize /LucidaGrandeLat 12.0 selectfont +gsave +clipsave +/DeviceRGB setcolorspace +0 340.15748031496065 translate +2.834645669291339 -2.834645669291339 scale +/basematrix matrix currentmatrix def +gsave +0.0 0.0 0.0 rgb +1.0 setlinewidth 0 setlinejoin 0 setlinecap [] 0.0 setdash +1.0 1.0 1.0 rgb +newpath 0.0 0.0 1920.0 1200.0 rect Z fill +0.0 0.0 0.0 rgb +newpath 10.0 10.0 M 12.0 10.0 L 12.0 90.0 L 10.0 90.0 L Z fill +newpath 14.0 10.0 M 16.0 10.0 L 16.0 90.0 L 14.0 90.0 L Z fill +newpath 18.0 10.0 M 26.0 10.0 L 26.0 90.0 L 18.0 90.0 L Z fill +newpath 28.0 10.0 M 30.0 10.0 L 30.0 90.0 L 28.0 90.0 L Z fill +newpath 32.0 10.0 M 34.0 10.0 L 34.0 90.0 L 32.0 90.0 L Z fill +newpath 38.0 10.0 M 40.0 10.0 L 40.0 90.0 L 38.0 90.0 L Z fill +newpath 46.0 10.0 M 48.0 10.0 L 48.0 90.0 L 46.0 90.0 L Z fill +newpath 50.0 10.0 M 52.0 10.0 L 52.0 90.0 L 50.0 90.0 L Z fill +newpath 58.0 10.0 M 60.0 10.0 L 60.0 90.0 L 58.0 90.0 L Z fill +newpath 64.0 10.0 M 66.0 10.0 L 66.0 90.0 L 64.0 90.0 L Z fill +newpath 68.0 10.0 M 70.0 10.0 L 70.0 90.0 L 68.0 90.0 L Z fill +newpath 78.0 10.0 M 80.0 10.0 L 80.0 90.0 L 78.0 90.0 L Z fill +newpath 82.0 10.0 M 84.0 10.0 L 84.0 90.0 L 82.0 90.0 L Z fill +newpath 88.0 10.0 M 90.0 10.0 L 90.0 90.0 L 88.0 90.0 L Z fill +newpath 92.0 10.0 M 94.0 10.0 L 94.0 90.0 L 92.0 90.0 L Z fill +newpath 100.0 10.0 M 102.0 10.0 L 102.0 90.0 L 100.0 90.0 L Z fill +newpath 106.0 10.0 M 108.0 10.0 L 108.0 90.0 L 106.0 90.0 L Z fill +newpath 112.0 10.0 M 114.0 10.0 L 114.0 90.0 L 112.0 90.0 L Z fill +newpath 118.0 10.0 M 120.0 10.0 L 120.0 90.0 L 118.0 90.0 L Z fill +newpath 124.0 10.0 M 126.0 10.0 L 126.0 90.0 L 124.0 90.0 L Z fill +newpath 132.0 10.0 M 134.0 10.0 L 134.0 90.0 L 132.0 90.0 L Z fill +newpath 136.0 10.0 M 138.0 10.0 L 138.0 90.0 L 136.0 90.0 L Z fill +newpath 140.0 10.0 M 142.0 10.0 L 142.0 90.0 L 140.0 90.0 L Z fill +newpath 144.0 10.0 M 146.0 10.0 L 146.0 90.0 L 144.0 90.0 L Z fill +newpath 154.0 10.0 M 156.0 10.0 L 156.0 90.0 L 154.0 90.0 L Z fill +newpath 162.0 10.0 M 164.0 10.0 L 164.0 90.0 L 162.0 90.0 L Z fill +newpath 168.0 10.0 M 170.0 10.0 L 170.0 90.0 L 168.0 90.0 L Z fill +newpath 172.0 10.0 M 174.0 10.0 L 174.0 90.0 L 172.0 90.0 L Z fill +newpath 182.0 10.0 M 184.0 10.0 L 184.0 90.0 L 182.0 90.0 L Z fill +newpath 186.0 10.0 M 188.0 10.0 L 188.0 90.0 L 186.0 90.0 L Z fill +newpath 190.0 10.0 M 192.0 10.0 L 192.0 90.0 L 190.0 90.0 L Z fill +newpath 196.0 10.0 M 198.0 10.0 L 198.0 90.0 L 196.0 90.0 L Z fill +newpath 200.0 10.0 M 204.0 10.0 L 204.0 90.0 L 200.0 90.0 L Z fill +newpath 208.0 10.0 M 210.0 10.0 L 210.0 90.0 L 208.0 90.0 L Z fill +newpath 214.0 10.0 M 218.0 10.0 L 218.0 90.0 L 214.0 90.0 L Z fill +newpath 222.0 10.0 M 224.0 10.0 L 224.0 90.0 L 222.0 90.0 L Z fill +newpath 226.0 10.0 M 228.0 10.0 L 228.0 90.0 L 226.0 90.0 L Z fill +newpath 230.0 10.0 M 232.0 10.0 L 232.0 90.0 L 230.0 90.0 L Z fill +newpath 234.0 10.0 M 242.0 10.0 L 242.0 90.0 L 234.0 90.0 L Z fill +newpath 244.0 10.0 M 246.0 10.0 L 246.0 90.0 L 244.0 90.0 L Z fill +/HelveticaLat /Helvetica latinize /HelveticaLat 16.0 selectfont +gsave 1 -1 scale 77.0 -106.0 M (123456789Od) show grestore +/LucidaGrandeLat /LucidaGrande latinize /LucidaGrandeLat 12.0 selectfont +grestore +%%EOF \ No newline at end of file diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-magnification-2.svg b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-magnification-2.svg old mode 100755 new mode 100644 index 34baea3..729fa70 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-magnification-2.svg +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-magnification-2.svg @@ -1,53 +1,46 @@ - - - - 123456789 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 123456789Od - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 123456789Od diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-margin-size-20.eps b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-margin-size-20.eps old mode 100755 new mode 100644 index 2dfa31b..6679eed --- a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-margin-size-20.eps +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-margin-size-20.eps @@ -1,71 +1,76 @@ %!PS-Adobe-3.0 EPSF-3.0 -%%Creator: OkapiBarcode -%%Title: 123456789 -%%Pages: 0 -%%BoundingBox: 0 0 158 90 +%%BoundingBox: 0 0 448 256 +%%HiResBoundingBox: 0.0 0.0 447.8740157480315 255.1181102362205 +%%LanguageLevel: 3 +%%Pages: 1 %%EndComments -/TL { setlinewidth moveto lineto stroke } bind def -/TC { moveto 0 360 arc 360 0 arcn fill } bind def -/TH { 0 setlinewidth moveto lineto lineto lineto lineto lineto closepath fill } bind def -/TB { 2 copy } bind def -/TR { newpath 4 1 roll exch moveto 1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath fill } bind def -/TE { pop pop } bind def -newpath -0.00 0.00 0.00 setrgbcolor -1.00 1.00 1.00 setrgbcolor -90.00 0.00 TB 0.00 158.00 TR -TE -0.00 0.00 0.00 setrgbcolor -40.00 30.00 TB 20.00 1.00 TR -TB 22.00 1.00 TR -TB 24.00 4.00 TR -TB 29.00 1.00 TR -TB 31.00 1.00 TR -TB 34.00 1.00 TR -TB 38.00 1.00 TR -TB 40.00 1.00 TR -TB 44.00 1.00 TR -TB 47.00 1.00 TR -TB 49.00 1.00 TR -TB 54.00 1.00 TR -TB 56.00 1.00 TR -TB 59.00 1.00 TR -TB 61.00 1.00 TR -TB 65.00 1.00 TR -TB 68.00 1.00 TR -TB 71.00 1.00 TR -TB 74.00 1.00 TR -TB 77.00 1.00 TR -TB 81.00 1.00 TR -TB 83.00 1.00 TR -TB 85.00 1.00 TR -TB 87.00 1.00 TR -TB 92.00 1.00 TR -TB 96.00 1.00 TR -TB 99.00 1.00 TR -TB 101.00 1.00 TR -TB 106.00 1.00 TR -TB 108.00 1.00 TR -TB 110.00 1.00 TR -TB 113.00 1.00 TR -TB 115.00 2.00 TR -TB 119.00 1.00 TR -TB 122.00 2.00 TR -TB 126.00 1.00 TR -TB 128.00 1.00 TR -TB 130.00 1.00 TR -TB 132.00 4.00 TR -TB 137.00 1.00 TR -TE -0.00 0.00 0.00 setrgbcolor -matrix currentmatrix -/Helvetica findfont -8.00 scalefont setfont - 0 0 moveto 79.00 22.00 translate 0.00 rotate 0 0 moveto - (123456789Od) stringwidth -pop --2 div 0 rmoveto - (123456789Od) show -setmatrix - -showpage +%%Page: 1 1 +/M /moveto load def +/L /lineto load def +/C /curveto load def +/Z /closepath load def +/RL /rlineto load def +/rgb /setrgbcolor load def +/rect { /height exch def /width exch def /y exch def /x exch def x y M width 0 RL 0 height RL width neg 0 RL } bind def +/ellipse { /endangle exch def /startangle exch def /ry exch def /rx exch def /y exch def /x exch def /savematrix matrix currentmatrix def x y translate rx ry scale 0 0 1 startangle endangle arcn savematrix setmatrix } bind def +/imgdict { /datastream exch def /hasdata exch def /decodeScale exch def /bits exch def /bands exch def /imgheight exch def /imgwidth exch def << /ImageType 1 /Width imgwidth /Height imgheight /BitsPerComponent bits /Decode [bands {0 decodeScale} repeat] +/ImageMatrix [imgwidth 0 0 imgheight 0 0] hasdata { /DataSource datastream } if >> } bind def +/latinize { /fontName exch def /fontNameNew exch def fontName findfont 0 dict copy begin /Encoding ISOLatin1Encoding def fontNameNew /FontName def currentdict end dup /FID undef fontNameNew exch definefont pop } bind def +/LucidaGrandeLat /LucidaGrande latinize /LucidaGrandeLat 12.0 selectfont +gsave +clipsave +/DeviceRGB setcolorspace +0 255.1181102362205 translate +2.834645669291339 -2.834645669291339 scale +/basematrix matrix currentmatrix def +gsave +0.0 0.0 0.0 rgb +1.0 setlinewidth 0 setlinejoin 0 setlinecap [] 0.0 setdash +1.0 1.0 1.0 rgb +newpath 0.0 0.0 1920.0 1200.0 rect Z fill +0.0 0.0 0.0 rgb +newpath 20.0 20.0 M 21.0 20.0 L 21.0 60.0 L 20.0 60.0 L Z fill +newpath 22.0 20.0 M 23.0 20.0 L 23.0 60.0 L 22.0 60.0 L Z fill +newpath 24.0 20.0 M 28.0 20.0 L 28.0 60.0 L 24.0 60.0 L Z fill +newpath 29.0 20.0 M 30.0 20.0 L 30.0 60.0 L 29.0 60.0 L Z fill +newpath 31.0 20.0 M 32.0 20.0 L 32.0 60.0 L 31.0 60.0 L Z fill +newpath 34.0 20.0 M 35.0 20.0 L 35.0 60.0 L 34.0 60.0 L Z fill +newpath 38.0 20.0 M 39.0 20.0 L 39.0 60.0 L 38.0 60.0 L Z fill +newpath 40.0 20.0 M 41.0 20.0 L 41.0 60.0 L 40.0 60.0 L Z fill +newpath 44.0 20.0 M 45.0 20.0 L 45.0 60.0 L 44.0 60.0 L Z fill +newpath 47.0 20.0 M 48.0 20.0 L 48.0 60.0 L 47.0 60.0 L Z fill +newpath 49.0 20.0 M 50.0 20.0 L 50.0 60.0 L 49.0 60.0 L Z fill +newpath 54.0 20.0 M 55.0 20.0 L 55.0 60.0 L 54.0 60.0 L Z fill +newpath 56.0 20.0 M 57.0 20.0 L 57.0 60.0 L 56.0 60.0 L Z fill +newpath 59.0 20.0 M 60.0 20.0 L 60.0 60.0 L 59.0 60.0 L Z fill +newpath 61.0 20.0 M 62.0 20.0 L 62.0 60.0 L 61.0 60.0 L Z fill +newpath 65.0 20.0 M 66.0 20.0 L 66.0 60.0 L 65.0 60.0 L Z fill +newpath 68.0 20.0 M 69.0 20.0 L 69.0 60.0 L 68.0 60.0 L Z fill +newpath 71.0 20.0 M 72.0 20.0 L 72.0 60.0 L 71.0 60.0 L Z fill +newpath 74.0 20.0 M 75.0 20.0 L 75.0 60.0 L 74.0 60.0 L Z fill +newpath 77.0 20.0 M 78.0 20.0 L 78.0 60.0 L 77.0 60.0 L Z fill +newpath 81.0 20.0 M 82.0 20.0 L 82.0 60.0 L 81.0 60.0 L Z fill +newpath 83.0 20.0 M 84.0 20.0 L 84.0 60.0 L 83.0 60.0 L Z fill +newpath 85.0 20.0 M 86.0 20.0 L 86.0 60.0 L 85.0 60.0 L Z fill +newpath 87.0 20.0 M 88.0 20.0 L 88.0 60.0 L 87.0 60.0 L Z fill +newpath 92.0 20.0 M 93.0 20.0 L 93.0 60.0 L 92.0 60.0 L Z fill +newpath 96.0 20.0 M 97.0 20.0 L 97.0 60.0 L 96.0 60.0 L Z fill +newpath 99.0 20.0 M 100.0 20.0 L 100.0 60.0 L 99.0 60.0 L Z fill +newpath 101.0 20.0 M 102.0 20.0 L 102.0 60.0 L 101.0 60.0 L Z fill +newpath 106.0 20.0 M 107.0 20.0 L 107.0 60.0 L 106.0 60.0 L Z fill +newpath 108.0 20.0 M 109.0 20.0 L 109.0 60.0 L 108.0 60.0 L Z fill +newpath 110.0 20.0 M 111.0 20.0 L 111.0 60.0 L 110.0 60.0 L Z fill +newpath 113.0 20.0 M 114.0 20.0 L 114.0 60.0 L 113.0 60.0 L Z fill +newpath 115.0 20.0 M 117.0 20.0 L 117.0 60.0 L 115.0 60.0 L Z fill +newpath 119.0 20.0 M 120.0 20.0 L 120.0 60.0 L 119.0 60.0 L Z fill +newpath 122.0 20.0 M 124.0 20.0 L 124.0 60.0 L 122.0 60.0 L Z fill +newpath 126.0 20.0 M 127.0 20.0 L 127.0 60.0 L 126.0 60.0 L Z fill +newpath 128.0 20.0 M 129.0 20.0 L 129.0 60.0 L 128.0 60.0 L Z fill +newpath 130.0 20.0 M 131.0 20.0 L 131.0 60.0 L 130.0 60.0 L Z fill +newpath 132.0 20.0 M 136.0 20.0 L 136.0 60.0 L 132.0 60.0 L Z fill +newpath 137.0 20.0 M 138.0 20.0 L 138.0 60.0 L 137.0 60.0 L Z fill +/HelveticaLat /Helvetica latinize /HelveticaLat 8.0 selectfont +gsave 1 -1 scale 56.0 -68.0 M (123456789Od) show grestore +/LucidaGrandeLat /LucidaGrande latinize /LucidaGrandeLat 12.0 selectfont +grestore +%%EOF \ No newline at end of file diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-margin-size-20.svg b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-margin-size-20.svg old mode 100755 new mode 100644 index f27da66..9ef4d9d --- a/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-margin-size-20.svg +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/output/code93-margin-size-20.svg @@ -1,53 +1,46 @@ - - - - 123456789 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 123456789Od - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 123456789Od diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/output/maxicode-basic.eps b/barcode/src/test/resources/org/xbib/graphics/barcode/output/maxicode-basic.eps old mode 100755 new mode 100644 index c256da2..b3ac438 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/output/maxicode-basic.eps +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/output/maxicode-basic.eps @@ -1,393 +1,416 @@ %!PS-Adobe-3.0 EPSF-3.0 -%%Creator: OkapiBarcode -%%Title: 123456789 -%%Pages: 0 -%%BoundingBox: 0 0 420 410 +%%BoundingBox: 0 0 1191 1163 +%%HiResBoundingBox: 0.0 0.0 1190.5511811023623 1162.204724409449 +%%LanguageLevel: 3 +%%Pages: 1 %%EndComments -/TL { setlinewidth moveto lineto stroke } bind def -/TC { moveto 0 360 arc 360 0 arcn fill } bind def -/TH { 0 setlinewidth moveto lineto lineto lineto lineto lineto closepath fill } bind def -/TB { 2 copy } bind def -/TR { newpath 4 1 roll exch moveto 1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath fill } bind def -/TE { pop pop } bind def -newpath -0.00 0.00 0.00 setrgbcolor -1.00 1.00 1.00 setrgbcolor -410.00 0.00 TB 0.00 420.00 TR -TE -0.00 0.00 0.00 setrgbcolor -0.00 0.00 0.00 setrgbcolor -60.76 349.40 10.85 60.76 349.40 8.97 69.73 349.40 TC -60.76 349.40 7.10 60.76 349.40 5.22 65.98 349.40 TC -60.76 349.40 3.31 60.76 349.40 1.43 62.19 349.40 TC -28.69 382.32 29.77 382.95 29.77 384.20 28.69 384.82 27.62 384.20 27.62 382.95 TH -33.61 382.32 34.69 382.95 34.69 384.20 33.61 384.82 32.54 384.20 32.54 382.95 TH -38.53 382.32 39.61 382.95 39.61 384.20 38.53 384.82 37.46 384.20 37.46 382.95 TH -43.45 382.32 44.53 382.95 44.53 384.20 43.45 384.82 42.38 384.20 42.38 382.95 TH -48.37 382.32 49.45 382.95 49.45 384.20 48.37 384.82 47.30 384.20 47.30 382.95 TH -53.29 382.32 54.36 382.95 54.36 384.20 53.29 384.82 52.22 384.20 52.22 382.95 TH -58.21 382.32 59.29 382.95 59.29 384.20 58.21 384.82 57.14 384.20 57.14 382.95 TH -63.13 382.32 64.21 382.95 64.21 384.20 63.13 384.82 62.05 384.20 62.05 382.95 TH -68.05 382.32 69.13 382.95 69.13 384.20 68.05 384.82 66.98 384.20 66.98 382.95 TH -72.97 382.32 74.05 382.95 74.05 384.20 72.97 384.82 71.90 384.20 71.90 382.95 TH -77.89 382.32 78.97 382.95 78.97 384.20 77.89 384.82 76.82 384.20 76.82 382.95 TH -82.81 382.32 83.88 382.95 83.88 384.20 82.81 384.82 81.73 384.20 81.73 382.95 TH -87.73 382.32 88.81 382.95 88.81 384.20 87.73 384.82 86.66 384.20 86.66 382.95 TH -92.65 382.32 93.73 382.95 93.73 384.20 92.65 384.82 91.58 384.20 91.58 382.95 TH -95.11 382.32 96.19 382.95 96.19 384.20 95.11 384.82 94.04 384.20 94.04 382.95 TH -97.57 382.32 98.65 382.95 98.65 384.20 97.57 384.82 96.50 384.20 96.50 382.95 TH -26.23 378.05 27.31 378.68 27.31 379.93 26.23 380.55 25.16 379.93 25.16 378.68 TH -31.15 378.05 32.23 378.68 32.23 379.93 31.15 380.55 30.08 379.93 30.08 378.68 TH -36.07 378.05 37.14 378.68 37.14 379.93 36.07 380.55 35.00 379.93 35.00 378.68 TH -40.99 378.05 42.07 378.68 42.07 379.93 40.99 380.55 39.92 379.93 39.92 378.68 TH -45.91 378.05 46.99 378.68 46.99 379.93 45.91 380.55 44.84 379.93 44.84 378.68 TH -50.83 378.05 51.91 378.68 51.91 379.93 50.83 380.55 49.76 379.93 49.76 378.68 TH -55.75 378.05 56.83 378.68 56.83 379.93 55.75 380.55 54.68 379.93 54.68 378.68 TH -60.67 378.05 61.75 378.68 61.75 379.93 60.67 380.55 59.59 379.93 59.59 378.68 TH -65.59 378.05 66.66 378.68 66.66 379.93 65.59 380.55 64.51 379.93 64.51 378.68 TH -70.51 378.05 71.59 378.68 71.59 379.93 70.51 380.55 69.44 379.93 69.44 378.68 TH -75.43 378.05 76.51 378.68 76.51 379.93 75.43 380.55 74.35 379.93 74.35 378.68 TH -80.35 378.05 81.43 378.68 81.43 379.93 80.35 380.55 79.27 379.93 79.27 378.68 TH -85.27 378.05 86.35 378.68 86.35 379.93 85.27 380.55 84.20 379.93 84.20 378.68 TH -90.19 378.05 91.27 378.68 91.27 379.93 90.19 380.55 89.12 379.93 89.12 378.68 TH -95.11 378.05 96.19 378.68 96.19 379.93 95.11 380.55 94.04 379.93 94.04 378.68 TH -29.92 375.92 31.00 376.54 31.00 377.79 29.92 378.42 28.85 377.79 28.85 376.54 TH -34.84 375.92 35.92 376.54 35.92 377.79 34.84 378.42 33.77 377.79 33.77 376.54 TH -39.76 375.92 40.84 376.54 40.84 377.79 39.76 378.42 38.69 377.79 38.69 376.54 TH -44.68 375.92 45.75 376.54 45.75 377.79 44.68 378.42 43.61 377.79 43.61 376.54 TH -49.60 375.92 50.68 376.54 50.68 377.79 49.60 378.42 48.53 377.79 48.53 376.54 TH -54.52 375.92 55.60 376.54 55.60 377.79 54.52 378.42 53.45 377.79 53.45 376.54 TH -59.44 375.92 60.52 376.54 60.52 377.79 59.44 378.42 58.36 377.79 58.36 376.54 TH -64.36 375.92 65.44 376.54 65.44 377.79 64.36 378.42 63.28 377.79 63.28 376.54 TH -69.28 375.92 70.35 376.54 70.35 377.79 69.28 378.42 68.20 377.79 68.20 376.54 TH -74.20 375.92 75.28 376.54 75.28 377.79 74.20 378.42 73.13 377.79 73.13 376.54 TH -79.12 375.92 80.20 376.54 80.20 377.79 79.12 378.42 78.04 377.79 78.04 376.54 TH -84.04 375.92 85.12 376.54 85.12 377.79 84.04 378.42 82.96 377.79 82.96 376.54 TH -88.96 375.92 90.04 376.54 90.04 377.79 88.96 378.42 87.88 377.79 87.88 376.54 TH -93.88 375.92 94.96 376.54 94.96 377.79 93.88 378.42 92.81 377.79 92.81 376.54 TH -96.34 375.92 97.42 376.54 97.42 377.79 96.34 378.42 95.27 377.79 95.27 376.54 TH -97.57 373.78 98.65 374.41 98.65 375.66 97.57 376.28 96.50 375.66 96.50 374.41 TH -27.46 371.65 28.54 372.27 28.54 373.52 27.46 374.15 26.39 373.52 26.39 372.27 TH -32.38 371.65 33.46 372.27 33.46 373.52 32.38 374.15 31.31 373.52 31.31 372.27 TH -37.30 371.65 38.38 372.27 38.38 373.52 37.30 374.15 36.23 373.52 36.23 372.27 TH -42.22 371.65 43.30 372.27 43.30 373.52 42.22 374.15 41.14 373.52 41.14 372.27 TH -47.14 371.65 48.22 372.27 48.22 373.52 47.14 374.15 46.07 373.52 46.07 372.27 TH -52.06 371.65 53.14 372.27 53.14 373.52 52.06 374.15 50.99 373.52 50.99 372.27 TH -56.98 371.65 58.06 372.27 58.06 373.52 56.98 374.15 55.91 373.52 55.91 372.27 TH -61.90 371.65 62.97 372.27 62.97 373.52 61.90 374.15 60.82 373.52 60.82 372.27 TH -66.82 371.65 67.90 372.27 67.90 373.52 66.82 374.15 65.74 373.52 65.74 372.27 TH -71.74 371.65 72.82 372.27 72.82 373.52 71.74 374.15 70.66 373.52 70.66 372.27 TH -76.66 371.65 77.74 372.27 77.74 373.52 76.66 374.15 75.59 373.52 75.59 372.27 TH -81.58 371.65 82.66 372.27 82.66 373.52 81.58 374.15 80.51 373.52 80.51 372.27 TH -86.50 371.65 87.57 372.27 87.57 373.52 86.50 374.15 85.42 373.52 85.42 372.27 TH -91.42 371.65 92.50 372.27 92.50 373.52 91.42 374.15 90.35 373.52 90.35 372.27 TH -28.69 369.51 29.77 370.14 29.77 371.39 28.69 372.01 27.62 371.39 27.62 370.14 TH -33.61 369.51 34.69 370.14 34.69 371.39 33.61 372.01 32.54 371.39 32.54 370.14 TH -38.53 369.51 39.61 370.14 39.61 371.39 38.53 372.01 37.46 371.39 37.46 370.14 TH -43.45 369.51 44.53 370.14 44.53 371.39 43.45 372.01 42.38 371.39 42.38 370.14 TH -48.37 369.51 49.45 370.14 49.45 371.39 48.37 372.01 47.30 371.39 47.30 370.14 TH -53.29 369.51 54.36 370.14 54.36 371.39 53.29 372.01 52.22 371.39 52.22 370.14 TH -58.21 369.51 59.29 370.14 59.29 371.39 58.21 372.01 57.14 371.39 57.14 370.14 TH -63.13 369.51 64.21 370.14 64.21 371.39 63.13 372.01 62.05 371.39 62.05 370.14 TH -68.05 369.51 69.13 370.14 69.13 371.39 68.05 372.01 66.98 371.39 66.98 370.14 TH -72.97 369.51 74.05 370.14 74.05 371.39 72.97 372.01 71.90 371.39 71.90 370.14 TH -77.89 369.51 78.97 370.14 78.97 371.39 77.89 372.01 76.82 371.39 76.82 370.14 TH -82.81 369.51 83.88 370.14 83.88 371.39 82.81 372.01 81.73 371.39 81.73 370.14 TH -87.73 369.51 88.81 370.14 88.81 371.39 87.73 372.01 86.66 371.39 86.66 370.14 TH -92.65 369.51 93.73 370.14 93.73 371.39 92.65 372.01 91.58 371.39 91.58 370.14 TH -95.11 369.51 96.19 370.14 96.19 371.39 95.11 372.01 94.04 371.39 94.04 370.14 TH -96.34 367.38 97.42 368.00 97.42 369.25 96.34 369.88 95.27 369.25 95.27 368.00 TH -26.23 365.24 27.31 365.87 27.31 367.12 26.23 367.74 25.16 367.12 25.16 365.87 TH -31.15 365.24 32.23 365.87 32.23 367.12 31.15 367.74 30.08 367.12 30.08 365.87 TH -36.07 365.24 37.14 365.87 37.14 367.12 36.07 367.74 35.00 367.12 35.00 365.87 TH -40.99 365.24 42.07 365.87 42.07 367.12 40.99 367.74 39.92 367.12 39.92 365.87 TH -45.91 365.24 46.99 365.87 46.99 367.12 45.91 367.74 44.84 367.12 44.84 365.87 TH -50.83 365.24 51.91 365.87 51.91 367.12 50.83 367.74 49.76 367.12 49.76 365.87 TH -55.75 365.24 56.83 365.87 56.83 367.12 55.75 367.74 54.68 367.12 54.68 365.87 TH -60.67 365.24 61.75 365.87 61.75 367.12 60.67 367.74 59.59 367.12 59.59 365.87 TH -65.59 365.24 66.66 365.87 66.66 367.12 65.59 367.74 64.51 367.12 64.51 365.87 TH -70.51 365.24 71.59 365.87 71.59 367.12 70.51 367.74 69.44 367.12 69.44 365.87 TH -75.43 365.24 76.51 365.87 76.51 367.12 75.43 367.74 74.35 367.12 74.35 365.87 TH -80.35 365.24 81.43 365.87 81.43 367.12 80.35 367.74 79.27 367.12 79.27 365.87 TH -85.27 365.24 86.35 365.87 86.35 367.12 85.27 367.74 84.20 367.12 84.20 365.87 TH -90.19 365.24 91.27 365.87 91.27 367.12 90.19 367.74 89.12 367.12 89.12 365.87 TH -97.57 365.24 98.65 365.87 98.65 367.12 97.57 367.74 96.50 367.12 96.50 365.87 TH -29.92 363.11 31.00 363.73 31.00 364.98 29.92 365.61 28.85 364.98 28.85 363.73 TH -34.84 363.11 35.92 363.73 35.92 364.98 34.84 365.61 33.77 364.98 33.77 363.73 TH -39.76 363.11 40.84 363.73 40.84 364.98 39.76 365.61 38.69 364.98 38.69 363.73 TH -44.68 363.11 45.75 363.73 45.75 364.98 44.68 365.61 43.61 364.98 43.61 363.73 TH -47.14 363.11 48.22 363.73 48.22 364.98 47.14 365.61 46.07 364.98 46.07 363.73 TH -49.60 363.11 50.68 363.73 50.68 364.98 49.60 365.61 48.53 364.98 48.53 363.73 TH -52.06 363.11 53.14 363.73 53.14 364.98 52.06 365.61 50.99 364.98 50.99 363.73 TH -54.52 363.11 55.60 363.73 55.60 364.98 54.52 365.61 53.45 364.98 53.45 363.73 TH -61.90 363.11 62.97 363.73 62.97 364.98 61.90 365.61 60.82 364.98 60.82 363.73 TH -76.66 363.11 77.74 363.73 77.74 364.98 76.66 365.61 75.59 364.98 75.59 363.73 TH -79.12 363.11 80.20 363.73 80.20 364.98 79.12 365.61 78.04 364.98 78.04 363.73 TH -84.04 363.11 85.12 363.73 85.12 364.98 84.04 365.61 82.96 364.98 82.96 363.73 TH -88.96 363.11 90.04 363.73 90.04 364.98 88.96 365.61 87.88 364.98 87.88 363.73 TH -93.88 363.11 94.96 363.73 94.96 364.98 93.88 365.61 92.81 364.98 92.81 363.73 TH -53.29 360.97 54.36 361.60 54.36 362.85 53.29 363.47 52.22 362.85 52.22 361.60 TH -55.75 360.97 56.83 361.60 56.83 362.85 55.75 363.47 54.68 362.85 54.68 361.60 TH -60.67 360.97 61.75 361.60 61.75 362.85 60.67 363.47 59.59 362.85 59.59 361.60 TH -65.59 360.97 66.66 361.60 66.66 362.85 65.59 363.47 64.51 362.85 64.51 361.60 TH -75.43 360.97 76.51 361.60 76.51 362.85 75.43 363.47 74.35 362.85 74.35 361.60 TH -77.89 360.97 78.97 361.60 78.97 362.85 77.89 363.47 76.82 362.85 76.82 361.60 TH -27.46 358.84 28.54 359.46 28.54 360.71 27.46 361.34 26.39 360.71 26.39 359.46 TH -32.38 358.84 33.46 359.46 33.46 360.71 32.38 361.34 31.31 360.71 31.31 359.46 TH -37.30 358.84 38.38 359.46 38.38 360.71 37.30 361.34 36.23 360.71 36.23 359.46 TH -42.22 358.84 43.30 359.46 43.30 360.71 42.22 361.34 41.14 360.71 41.14 359.46 TH -52.06 358.84 53.14 359.46 53.14 360.71 52.06 361.34 50.99 360.71 50.99 359.46 TH -71.74 358.84 72.82 359.46 72.82 360.71 71.74 361.34 70.66 360.71 70.66 359.46 TH -76.66 358.84 77.74 359.46 77.74 360.71 76.66 361.34 75.59 360.71 75.59 359.46 TH -81.58 358.84 82.66 359.46 82.66 360.71 81.58 361.34 80.51 360.71 80.51 359.46 TH -86.50 358.84 87.57 359.46 87.57 360.71 86.50 361.34 85.42 360.71 85.42 359.46 TH -91.42 358.84 92.50 359.46 92.50 360.71 91.42 361.34 90.35 360.71 90.35 359.46 TH -96.34 358.84 97.42 359.46 97.42 360.71 96.34 361.34 95.27 360.71 95.27 359.46 TH -28.69 356.70 29.77 357.33 29.77 358.58 28.69 359.20 27.62 358.58 27.62 357.33 TH -33.61 356.70 34.69 357.33 34.69 358.58 33.61 359.20 32.54 358.58 32.54 357.33 TH -38.53 356.70 39.61 357.33 39.61 358.58 38.53 359.20 37.46 358.58 37.46 357.33 TH -43.45 356.70 44.53 357.33 44.53 358.58 43.45 359.20 42.38 358.58 42.38 357.33 TH -48.37 356.70 49.45 357.33 49.45 358.58 48.37 359.20 47.30 358.58 47.30 357.33 TH -50.83 356.70 51.91 357.33 51.91 358.58 50.83 359.20 49.76 358.58 49.76 357.33 TH -72.97 356.70 74.05 357.33 74.05 358.58 72.97 359.20 71.90 358.58 71.90 357.33 TH -75.43 356.70 76.51 357.33 76.51 358.58 75.43 359.20 74.35 358.58 74.35 357.33 TH -82.81 356.70 83.88 357.33 83.88 358.58 82.81 359.20 81.73 358.58 81.73 357.33 TH -87.73 356.70 88.81 357.33 88.81 358.58 87.73 359.20 86.66 358.58 86.66 357.33 TH -92.65 356.70 93.73 357.33 93.73 358.58 92.65 359.20 91.58 358.58 91.58 357.33 TH -95.11 356.70 96.19 357.33 96.19 358.58 95.11 359.20 94.04 358.58 94.04 357.33 TH -42.22 354.57 43.30 355.19 43.30 356.44 42.22 357.07 41.14 356.44 41.14 355.19 TH -71.74 354.57 72.82 355.19 72.82 356.44 71.74 357.07 70.66 356.44 70.66 355.19 TH -74.20 354.57 75.28 355.19 75.28 356.44 74.20 357.07 73.13 356.44 73.13 355.19 TH -76.66 354.57 77.74 355.19 77.74 356.44 76.66 357.07 75.59 356.44 75.59 355.19 TH -79.12 354.57 80.20 355.19 80.20 356.44 79.12 357.07 78.04 356.44 78.04 355.19 TH -26.23 352.43 27.31 353.06 27.31 354.31 26.23 354.93 25.16 354.31 25.16 353.06 TH -31.15 352.43 32.23 353.06 32.23 354.31 31.15 354.93 30.08 354.31 30.08 353.06 TH -36.07 352.43 37.14 353.06 37.14 354.31 36.07 354.93 35.00 354.31 35.00 353.06 TH -40.99 352.43 42.07 353.06 42.07 354.31 40.99 354.93 39.92 354.31 39.92 353.06 TH -45.91 352.43 46.99 353.06 46.99 354.31 45.91 354.93 44.84 354.31 44.84 353.06 TH -75.43 352.43 76.51 353.06 76.51 354.31 75.43 354.93 74.35 354.31 74.35 353.06 TH -80.35 352.43 81.43 353.06 81.43 354.31 80.35 354.93 79.27 354.31 79.27 353.06 TH -85.27 352.43 86.35 353.06 86.35 354.31 85.27 354.93 84.20 354.31 84.20 353.06 TH -90.19 352.43 91.27 353.06 91.27 354.31 90.19 354.93 89.12 354.31 89.12 353.06 TH -29.92 350.30 31.00 350.92 31.00 352.17 29.92 352.80 28.85 352.17 28.85 350.92 TH -34.84 350.30 35.92 350.92 35.92 352.17 34.84 352.80 33.77 352.17 33.77 350.92 TH -39.76 350.30 40.84 350.92 40.84 352.17 39.76 352.80 38.69 352.17 38.69 350.92 TH -42.22 350.30 43.30 350.92 43.30 352.17 42.22 352.80 41.14 352.17 41.14 350.92 TH -44.68 350.30 45.75 350.92 45.75 352.17 44.68 352.80 43.61 352.17 43.61 350.92 TH -47.14 350.30 48.22 350.92 48.22 352.17 47.14 352.80 46.07 352.17 46.07 350.92 TH -76.66 350.30 77.74 350.92 77.74 352.17 76.66 352.80 75.59 352.17 75.59 350.92 TH -84.04 350.30 85.12 350.92 85.12 352.17 84.04 352.80 82.96 352.17 82.96 350.92 TH -88.96 350.30 90.04 350.92 90.04 352.17 88.96 352.80 87.88 352.17 87.88 350.92 TH -93.88 350.30 94.96 350.92 94.96 352.17 93.88 352.80 92.81 352.17 92.81 350.92 TH -96.34 350.30 97.42 350.92 97.42 352.17 96.34 352.80 95.27 352.17 95.27 350.92 TH -45.91 348.16 46.99 348.79 46.99 350.04 45.91 350.66 44.84 350.04 44.84 348.79 TH -75.43 348.16 76.51 348.79 76.51 350.04 75.43 350.66 74.35 350.04 74.35 348.79 TH -95.11 348.16 96.19 348.79 96.19 350.04 95.11 350.66 94.04 350.04 94.04 348.79 TH -27.46 346.03 28.54 346.65 28.54 347.90 27.46 348.53 26.39 347.90 26.39 346.65 TH -32.38 346.03 33.46 346.65 33.46 347.90 32.38 348.53 31.31 347.90 31.31 346.65 TH -37.30 346.03 38.38 346.65 38.38 347.90 37.30 348.53 36.23 347.90 36.23 346.65 TH -47.14 346.03 48.22 346.65 48.22 347.90 47.14 348.53 46.07 347.90 46.07 346.65 TH -76.66 346.03 77.74 346.65 77.74 347.90 76.66 348.53 75.59 347.90 75.59 346.65 TH -79.12 346.03 80.20 346.65 80.20 347.90 79.12 348.53 78.04 347.90 78.04 346.65 TH -81.58 346.03 82.66 346.65 82.66 347.90 81.58 348.53 80.51 347.90 80.51 346.65 TH -86.50 346.03 87.57 346.65 87.57 347.90 86.50 348.53 85.42 347.90 85.42 346.65 TH -91.42 346.03 92.50 346.65 92.50 347.90 91.42 348.53 90.35 347.90 90.35 346.65 TH -28.69 343.89 29.77 344.52 29.77 345.77 28.69 346.39 27.62 345.77 27.62 344.52 TH -33.61 343.89 34.69 344.52 34.69 345.77 33.61 346.39 32.54 345.77 32.54 344.52 TH -38.53 343.89 39.61 344.52 39.61 345.77 38.53 346.39 37.46 345.77 37.46 344.52 TH -43.45 343.89 44.53 344.52 44.53 345.77 43.45 346.39 42.38 345.77 42.38 344.52 TH -48.37 343.89 49.45 344.52 49.45 345.77 48.37 346.39 47.30 345.77 47.30 344.52 TH -72.97 343.89 74.05 344.52 74.05 345.77 72.97 346.39 71.90 345.77 71.90 344.52 TH -75.43 343.89 76.51 344.52 76.51 345.77 75.43 346.39 74.35 345.77 74.35 344.52 TH -77.89 343.89 78.97 344.52 78.97 345.77 77.89 346.39 76.82 345.77 76.82 344.52 TH -82.81 343.89 83.88 344.52 83.88 345.77 82.81 346.39 81.73 345.77 81.73 344.52 TH -87.73 343.89 88.81 344.52 88.81 345.77 87.73 346.39 86.66 345.77 86.66 344.52 TH -92.65 343.89 93.73 344.52 93.73 345.77 92.65 346.39 91.58 345.77 91.58 344.52 TH -95.11 343.89 96.19 344.52 96.19 345.77 95.11 346.39 94.04 345.77 94.04 344.52 TH -97.57 343.89 98.65 344.52 98.65 345.77 97.57 346.39 96.50 345.77 96.50 344.52 TH -42.22 341.76 43.30 342.38 43.30 343.63 42.22 344.26 41.14 343.63 41.14 342.38 TH -47.14 341.76 48.22 342.38 48.22 343.63 47.14 344.26 46.07 343.63 46.07 342.38 TH -49.60 341.76 50.68 342.38 50.68 343.63 49.60 344.26 48.53 343.63 48.53 342.38 TH -74.20 341.76 75.28 342.38 75.28 343.63 74.20 344.26 73.13 343.63 73.13 342.38 TH -96.34 341.76 97.42 342.38 97.42 343.63 96.34 344.26 95.27 343.63 95.27 342.38 TH -26.23 339.62 27.31 340.25 27.31 341.50 26.23 342.12 25.16 341.50 25.16 340.25 TH -31.15 339.62 32.23 340.25 32.23 341.50 31.15 342.12 30.08 341.50 30.08 340.25 TH -36.07 339.62 37.14 340.25 37.14 341.50 36.07 342.12 35.00 341.50 35.00 340.25 TH -43.45 339.62 44.53 340.25 44.53 341.50 43.45 342.12 42.38 341.50 42.38 340.25 TH -48.37 339.62 49.45 340.25 49.45 341.50 48.37 342.12 47.30 341.50 47.30 340.25 TH -50.83 339.62 51.91 340.25 51.91 341.50 50.83 342.12 49.76 341.50 49.76 340.25 TH -75.43 339.62 76.51 340.25 76.51 341.50 75.43 342.12 74.35 341.50 74.35 340.25 TH -77.89 339.62 78.97 340.25 78.97 341.50 77.89 342.12 76.82 341.50 76.82 340.25 TH -80.35 339.62 81.43 340.25 81.43 341.50 80.35 342.12 79.27 341.50 79.27 340.25 TH -85.27 339.62 86.35 340.25 86.35 341.50 85.27 342.12 84.20 341.50 84.20 340.25 TH -90.19 339.62 91.27 340.25 91.27 341.50 90.19 342.12 89.12 341.50 89.12 340.25 TH -95.11 339.62 96.19 340.25 96.19 341.50 95.11 342.12 94.04 341.50 94.04 340.25 TH -97.57 339.62 98.65 340.25 98.65 341.50 97.57 342.12 96.50 341.50 96.50 340.25 TH -29.92 337.49 31.00 338.11 31.00 339.36 29.92 339.99 28.85 339.36 28.85 338.11 TH -34.84 337.49 35.92 338.11 35.92 339.36 34.84 339.99 33.77 339.36 33.77 338.11 TH -39.76 337.49 40.84 338.11 40.84 339.36 39.76 339.99 38.69 339.36 38.69 338.11 TH -44.68 337.49 45.75 338.11 45.75 339.36 44.68 339.99 43.61 339.36 43.61 338.11 TH -49.60 337.49 50.68 338.11 50.68 339.36 49.60 339.99 48.53 339.36 48.53 338.11 TH -69.28 337.49 70.35 338.11 70.35 339.36 69.28 339.99 68.20 339.36 68.20 338.11 TH -71.74 337.49 72.82 338.11 72.82 339.36 71.74 339.99 70.66 339.36 70.66 338.11 TH -74.20 337.49 75.28 338.11 75.28 339.36 74.20 339.99 73.13 339.36 73.13 338.11 TH -76.66 337.49 77.74 338.11 77.74 339.36 76.66 339.99 75.59 339.36 75.59 338.11 TH -79.12 337.49 80.20 338.11 80.20 339.36 79.12 339.99 78.04 339.36 78.04 338.11 TH -84.04 337.49 85.12 338.11 85.12 339.36 84.04 339.99 82.96 339.36 82.96 338.11 TH -88.96 337.49 90.04 338.11 90.04 339.36 88.96 339.99 87.88 339.36 87.88 338.11 TH -93.88 337.49 94.96 338.11 94.96 339.36 93.88 339.99 92.81 339.36 92.81 338.11 TH -45.91 335.35 46.99 335.98 46.99 337.23 45.91 337.85 44.84 337.23 44.84 335.98 TH -48.37 335.35 49.45 335.98 49.45 337.23 48.37 337.85 47.30 337.23 47.30 335.98 TH -50.83 335.35 51.91 335.98 51.91 337.23 50.83 337.85 49.76 337.23 49.76 335.98 TH -55.75 335.35 56.83 335.98 56.83 337.23 55.75 337.85 54.68 337.23 54.68 335.98 TH -65.59 335.35 66.66 335.98 66.66 337.23 65.59 337.85 64.51 337.23 64.51 335.98 TH -68.05 335.35 69.13 335.98 69.13 337.23 68.05 337.85 66.98 337.23 66.98 335.98 TH -70.51 335.35 71.59 335.98 71.59 337.23 70.51 337.85 69.44 337.23 69.44 335.98 TH -75.43 335.35 76.51 335.98 76.51 337.23 75.43 337.85 74.35 337.23 74.35 335.98 TH -95.11 335.35 96.19 335.98 96.19 337.23 95.11 337.85 94.04 337.23 94.04 335.98 TH -97.57 335.35 98.65 335.98 98.65 337.23 97.57 337.85 96.50 337.23 96.50 335.98 TH -27.46 333.22 28.54 333.84 28.54 335.09 27.46 335.72 26.39 335.09 26.39 333.84 TH -32.38 333.22 33.46 333.84 33.46 335.09 32.38 335.72 31.31 335.09 31.31 333.84 TH -37.30 333.22 38.38 333.84 38.38 335.09 37.30 335.72 36.23 335.09 36.23 333.84 TH -42.22 333.22 43.30 333.84 43.30 335.09 42.22 335.72 41.14 335.09 41.14 333.84 TH -47.14 333.22 48.22 333.84 48.22 335.09 47.14 335.72 46.07 335.09 46.07 333.84 TH -52.06 333.22 53.14 333.84 53.14 335.09 52.06 335.72 50.99 335.09 50.99 333.84 TH -54.52 333.22 55.60 333.84 55.60 335.09 54.52 335.72 53.45 335.09 53.45 333.84 TH -56.98 333.22 58.06 333.84 58.06 335.09 56.98 335.72 55.91 335.09 55.91 333.84 TH -59.44 333.22 60.52 333.84 60.52 335.09 59.44 335.72 58.36 335.09 58.36 333.84 TH -61.90 333.22 62.97 333.84 62.97 335.09 61.90 335.72 60.82 335.09 60.82 333.84 TH -64.36 333.22 65.44 333.84 65.44 335.09 64.36 335.72 63.28 335.09 63.28 333.84 TH -69.28 333.22 70.35 333.84 70.35 335.09 69.28 335.72 68.20 335.09 68.20 333.84 TH -71.74 333.22 72.82 333.84 72.82 335.09 71.74 335.72 70.66 335.09 70.66 333.84 TH -81.58 333.22 82.66 333.84 82.66 335.09 81.58 335.72 80.51 335.09 80.51 333.84 TH -86.50 333.22 87.57 333.84 87.57 335.09 86.50 335.72 85.42 335.09 85.42 333.84 TH -91.42 333.22 92.50 333.84 92.50 335.09 91.42 335.72 90.35 335.09 90.35 333.84 TH -96.34 333.22 97.42 333.84 97.42 335.09 96.34 335.72 95.27 335.09 95.27 333.84 TH -28.69 331.08 29.77 331.71 29.77 332.96 28.69 333.58 27.62 332.96 27.62 331.71 TH -33.61 331.08 34.69 331.71 34.69 332.96 33.61 333.58 32.54 332.96 32.54 331.71 TH -38.53 331.08 39.61 331.71 39.61 332.96 38.53 333.58 37.46 332.96 37.46 331.71 TH -43.45 331.08 44.53 331.71 44.53 332.96 43.45 333.58 42.38 332.96 42.38 331.71 TH -48.37 331.08 49.45 331.71 49.45 332.96 48.37 333.58 47.30 332.96 47.30 331.71 TH -53.29 331.08 54.36 331.71 54.36 332.96 53.29 333.58 52.22 332.96 52.22 331.71 TH -58.21 331.08 59.29 331.71 59.29 332.96 58.21 333.58 57.14 332.96 57.14 331.71 TH -63.13 331.08 64.21 331.71 64.21 332.96 63.13 333.58 62.05 332.96 62.05 331.71 TH -68.05 331.08 69.13 331.71 69.13 332.96 68.05 333.58 66.98 332.96 66.98 331.71 TH -72.97 331.08 74.05 331.71 74.05 332.96 72.97 333.58 71.90 332.96 71.90 331.71 TH -75.43 331.08 76.51 331.71 76.51 332.96 75.43 333.58 74.35 332.96 74.35 331.71 TH -77.89 331.08 78.97 331.71 78.97 332.96 77.89 333.58 76.82 332.96 76.82 331.71 TH -80.35 331.08 81.43 331.71 81.43 332.96 80.35 333.58 79.27 332.96 79.27 331.71 TH -82.81 331.08 83.88 331.71 83.88 332.96 82.81 333.58 81.73 332.96 81.73 331.71 TH -87.73 331.08 88.81 331.71 88.81 332.96 87.73 333.58 86.66 332.96 86.66 331.71 TH -92.65 331.08 93.73 331.71 93.73 332.96 92.65 333.58 91.58 332.96 91.58 331.71 TH -95.11 331.08 96.19 331.71 96.19 332.96 95.11 333.58 94.04 332.96 94.04 331.71 TH -97.57 331.08 98.65 331.71 98.65 332.96 97.57 333.58 96.50 332.96 96.50 331.71 TH -76.66 328.95 77.74 329.57 77.74 330.82 76.66 331.45 75.59 330.82 75.59 329.57 TH -79.12 328.95 80.20 329.57 80.20 330.82 79.12 331.45 78.04 330.82 78.04 329.57 TH -81.58 328.95 82.66 329.57 82.66 330.82 81.58 331.45 80.51 330.82 80.51 329.57 TH -84.04 328.95 85.12 329.57 85.12 330.82 84.04 331.45 82.96 330.82 82.96 329.57 TH -88.96 328.95 90.04 329.57 90.04 330.82 88.96 331.45 87.88 330.82 87.88 329.57 TH -93.88 328.95 94.96 329.57 94.96 330.82 93.88 331.45 92.81 330.82 92.81 329.57 TH -96.34 328.95 97.42 329.57 97.42 330.82 96.34 331.45 95.27 330.82 95.27 329.57 TH -26.23 326.81 27.31 327.44 27.31 328.69 26.23 329.31 25.16 328.69 25.16 327.44 TH -31.15 326.81 32.23 327.44 32.23 328.69 31.15 329.31 30.08 328.69 30.08 327.44 TH -36.07 326.81 37.14 327.44 37.14 328.69 36.07 329.31 35.00 328.69 35.00 327.44 TH -40.99 326.81 42.07 327.44 42.07 328.69 40.99 329.31 39.92 328.69 39.92 327.44 TH -45.91 326.81 46.99 327.44 46.99 328.69 45.91 329.31 44.84 328.69 44.84 327.44 TH -50.83 326.81 51.91 327.44 51.91 328.69 50.83 329.31 49.76 328.69 49.76 327.44 TH -55.75 326.81 56.83 327.44 56.83 328.69 55.75 329.31 54.68 328.69 54.68 327.44 TH -60.67 326.81 61.75 327.44 61.75 328.69 60.67 329.31 59.59 328.69 59.59 327.44 TH -65.59 326.81 66.66 327.44 66.66 328.69 65.59 329.31 64.51 328.69 64.51 327.44 TH -70.51 326.81 71.59 327.44 71.59 328.69 70.51 329.31 69.44 328.69 69.44 327.44 TH -95.11 326.81 96.19 327.44 96.19 328.69 95.11 329.31 94.04 328.69 94.04 327.44 TH -27.46 324.68 28.54 325.30 28.54 326.55 27.46 327.18 26.39 326.55 26.39 325.30 TH -29.92 324.68 31.00 325.30 31.00 326.55 29.92 327.18 28.85 326.55 28.85 325.30 TH -32.38 324.68 33.46 325.30 33.46 326.55 32.38 327.18 31.31 326.55 31.31 325.30 TH -34.84 324.68 35.92 325.30 35.92 326.55 34.84 327.18 33.77 326.55 33.77 325.30 TH -37.30 324.68 38.38 325.30 38.38 326.55 37.30 327.18 36.23 326.55 36.23 325.30 TH -39.76 324.68 40.84 325.30 40.84 326.55 39.76 327.18 38.69 326.55 38.69 325.30 TH -42.22 324.68 43.30 325.30 43.30 326.55 42.22 327.18 41.14 326.55 41.14 325.30 TH -44.68 324.68 45.75 325.30 45.75 326.55 44.68 327.18 43.61 326.55 43.61 325.30 TH -56.98 324.68 58.06 325.30 58.06 326.55 56.98 327.18 55.91 326.55 55.91 325.30 TH -59.44 324.68 60.52 325.30 60.52 326.55 59.44 327.18 58.36 326.55 58.36 325.30 TH -61.90 324.68 62.97 325.30 62.97 326.55 61.90 327.18 60.82 326.55 60.82 325.30 TH -64.36 324.68 65.44 325.30 65.44 326.55 64.36 327.18 63.28 326.55 63.28 325.30 TH -79.12 324.68 80.20 325.30 80.20 326.55 79.12 327.18 78.04 326.55 78.04 325.30 TH -84.04 324.68 85.12 325.30 85.12 326.55 84.04 327.18 82.96 326.55 82.96 325.30 TH -28.69 322.54 29.77 323.17 29.77 324.42 28.69 325.04 27.62 324.42 27.62 323.17 TH -33.61 322.54 34.69 323.17 34.69 324.42 33.61 325.04 32.54 324.42 32.54 323.17 TH -36.07 322.54 37.14 323.17 37.14 324.42 36.07 325.04 35.00 324.42 35.00 323.17 TH -40.99 322.54 42.07 323.17 42.07 324.42 40.99 325.04 39.92 324.42 39.92 323.17 TH -45.91 322.54 46.99 323.17 46.99 324.42 45.91 325.04 44.84 324.42 44.84 323.17 TH -48.37 322.54 49.45 323.17 49.45 324.42 48.37 325.04 47.30 324.42 47.30 323.17 TH -50.83 322.54 51.91 323.17 51.91 324.42 50.83 325.04 49.76 324.42 49.76 323.17 TH -53.29 322.54 54.36 323.17 54.36 324.42 53.29 325.04 52.22 324.42 52.22 323.17 TH -65.59 322.54 66.66 323.17 66.66 324.42 65.59 325.04 64.51 324.42 64.51 323.17 TH -68.05 322.54 69.13 323.17 69.13 324.42 68.05 325.04 66.98 324.42 66.98 323.17 TH -70.51 322.54 71.59 323.17 71.59 324.42 70.51 325.04 69.44 324.42 69.44 323.17 TH -72.97 322.54 74.05 323.17 74.05 324.42 72.97 325.04 71.90 324.42 71.90 323.17 TH -77.89 322.54 78.97 323.17 78.97 324.42 77.89 325.04 76.82 324.42 76.82 323.17 TH -82.81 322.54 83.88 323.17 83.88 324.42 82.81 325.04 81.73 324.42 81.73 323.17 TH -87.73 322.54 88.81 323.17 88.81 324.42 87.73 325.04 86.66 324.42 86.66 323.17 TH -92.65 322.54 93.73 323.17 93.73 324.42 92.65 325.04 91.58 324.42 91.58 323.17 TH -27.46 320.41 28.54 321.03 28.54 322.28 27.46 322.91 26.39 322.28 26.39 321.03 TH -32.38 320.41 33.46 321.03 33.46 322.28 32.38 322.91 31.31 322.28 31.31 321.03 TH -37.30 320.41 38.38 321.03 38.38 322.28 37.30 322.91 36.23 322.28 36.23 321.03 TH -42.22 320.41 43.30 321.03 43.30 322.28 42.22 322.91 41.14 322.28 41.14 321.03 TH -59.44 320.41 60.52 321.03 60.52 322.28 59.44 322.91 58.36 322.28 58.36 321.03 TH -64.36 320.41 65.44 321.03 65.44 322.28 64.36 322.91 63.28 322.28 63.28 321.03 TH -69.28 320.41 70.35 321.03 70.35 322.28 69.28 322.91 68.20 322.28 68.20 321.03 TH -74.20 320.41 75.28 321.03 75.28 322.28 74.20 322.91 73.13 322.28 73.13 321.03 TH -76.66 320.41 77.74 321.03 77.74 322.28 76.66 322.91 75.59 322.28 75.59 321.03 TH -79.12 320.41 80.20 321.03 80.20 322.28 79.12 322.91 78.04 322.28 78.04 321.03 TH -81.58 320.41 82.66 321.03 82.66 322.28 81.58 322.91 80.51 322.28 80.51 321.03 TH -84.04 320.41 85.12 321.03 85.12 322.28 84.04 322.91 82.96 322.28 82.96 321.03 TH -86.50 320.41 87.57 321.03 87.57 322.28 86.50 322.91 85.42 322.28 85.42 321.03 TH -91.42 320.41 92.50 321.03 92.50 322.28 91.42 322.91 90.35 322.28 90.35 321.03 TH -96.34 320.41 97.42 321.03 97.42 322.28 96.34 322.91 95.27 322.28 95.27 321.03 TH -26.23 318.27 27.31 318.90 27.31 320.15 26.23 320.77 25.16 320.15 25.16 318.90 TH -28.69 318.27 29.77 318.90 29.77 320.15 28.69 320.77 27.62 320.15 27.62 318.90 TH -31.15 318.27 32.23 318.90 32.23 320.15 31.15 320.77 30.08 320.15 30.08 318.90 TH -33.61 318.27 34.69 318.90 34.69 320.15 33.61 320.77 32.54 320.15 32.54 318.90 TH -38.53 318.27 39.61 318.90 39.61 320.15 38.53 320.77 37.46 320.15 37.46 318.90 TH -43.45 318.27 44.53 318.90 44.53 320.15 43.45 320.77 42.38 320.15 42.38 318.90 TH -45.91 318.27 46.99 318.90 46.99 320.15 45.91 320.77 44.84 320.15 44.84 318.90 TH -50.83 318.27 51.91 318.90 51.91 320.15 50.83 320.77 49.76 320.15 49.76 318.90 TH -65.59 318.27 66.66 318.90 66.66 320.15 65.59 320.77 64.51 320.15 64.51 318.90 TH -68.05 318.27 69.13 318.90 69.13 320.15 68.05 320.77 66.98 320.15 66.98 318.90 TH -70.51 318.27 71.59 318.90 71.59 320.15 70.51 320.77 69.44 320.15 69.44 318.90 TH -72.97 318.27 74.05 318.90 74.05 320.15 72.97 320.77 71.90 320.15 71.90 318.90 TH -77.89 318.27 78.97 318.90 78.97 320.15 77.89 320.77 76.82 320.15 76.82 318.90 TH -82.81 318.27 83.88 318.90 83.88 320.15 82.81 320.77 81.73 320.15 81.73 318.90 TH -85.27 318.27 86.35 318.90 86.35 320.15 85.27 320.77 84.20 320.15 84.20 318.90 TH -90.19 318.27 91.27 318.90 91.27 320.15 90.19 320.77 89.12 320.15 89.12 318.90 TH -95.11 318.27 96.19 318.90 96.19 320.15 95.11 320.77 94.04 320.15 94.04 318.90 TH -29.92 316.14 31.00 316.76 31.00 318.01 29.92 318.64 28.85 318.01 28.85 316.76 TH -34.84 316.14 35.92 316.76 35.92 318.01 34.84 318.64 33.77 318.01 33.77 316.76 TH -37.30 316.14 38.38 316.76 38.38 318.01 37.30 318.64 36.23 318.01 36.23 316.76 TH -42.22 316.14 43.30 316.76 43.30 318.01 42.22 318.64 41.14 318.01 41.14 316.76 TH -47.14 316.14 48.22 316.76 48.22 318.01 47.14 318.64 46.07 318.01 46.07 316.76 TH -49.60 316.14 50.68 316.76 50.68 318.01 49.60 318.64 48.53 318.01 48.53 316.76 TH -52.06 316.14 53.14 316.76 53.14 318.01 52.06 318.64 50.99 318.01 50.99 316.76 TH -54.52 316.14 55.60 316.76 55.60 318.01 54.52 318.64 53.45 318.01 53.45 316.76 TH -59.44 316.14 60.52 316.76 60.52 318.01 59.44 318.64 58.36 318.01 58.36 316.76 TH -64.36 316.14 65.44 316.76 65.44 318.01 64.36 318.64 63.28 318.01 63.28 316.76 TH -66.82 316.14 67.90 316.76 67.90 318.01 66.82 318.64 65.74 318.01 65.74 316.76 TH -71.74 316.14 72.82 316.76 72.82 318.01 71.74 318.64 70.66 318.01 70.66 316.76 TH -76.66 316.14 77.74 316.76 77.74 318.01 76.66 318.64 75.59 318.01 75.59 316.76 TH -81.58 316.14 82.66 316.76 82.66 318.01 81.58 318.64 80.51 318.01 80.51 316.76 TH -86.50 316.14 87.57 316.76 87.57 318.01 86.50 318.64 85.42 318.01 85.42 316.76 TH -88.96 316.14 90.04 316.76 90.04 318.01 88.96 318.64 87.88 318.01 87.88 316.76 TH -91.42 316.14 92.50 316.76 92.50 318.01 91.42 318.64 90.35 318.01 90.35 316.76 TH -93.88 316.14 94.96 316.76 94.96 318.01 93.88 318.64 92.81 318.01 92.81 316.76 TH -28.69 314.00 29.77 314.63 29.77 315.88 28.69 316.50 27.62 315.88 27.62 314.63 TH -33.61 314.00 34.69 314.63 34.69 315.88 33.61 316.50 32.54 315.88 32.54 314.63 TH -58.21 314.00 59.29 314.63 59.29 315.88 58.21 316.50 57.14 315.88 57.14 314.63 TH -63.13 314.00 64.21 314.63 64.21 315.88 63.13 316.50 62.05 315.88 62.05 314.63 TH -65.59 314.00 66.66 314.63 66.66 315.88 65.59 316.50 64.51 315.88 64.51 314.63 TH -70.51 314.00 71.59 314.63 71.59 315.88 70.51 316.50 69.44 315.88 69.44 314.63 TH -75.43 314.00 76.51 314.63 76.51 315.88 75.43 316.50 74.35 315.88 74.35 314.63 TH -80.35 314.00 81.43 314.63 81.43 315.88 80.35 316.50 79.27 315.88 79.27 314.63 TH -87.73 314.00 88.81 314.63 88.81 315.88 87.73 316.50 86.66 315.88 86.66 314.63 TH -92.65 314.00 93.73 314.63 93.73 315.88 92.65 316.50 91.58 315.88 91.58 314.63 TH - -showpage +%%Page: 1 1 +/M /moveto load def +/L /lineto load def +/C /curveto load def +/Z /closepath load def +/RL /rlineto load def +/rgb /setrgbcolor load def +/rect { /height exch def /width exch def /y exch def /x exch def x y M width 0 RL 0 height RL width neg 0 RL } bind def +/ellipse { /endangle exch def /startangle exch def /ry exch def /rx exch def /y exch def /x exch def /savematrix matrix currentmatrix def x y translate rx ry scale 0 0 1 startangle endangle arcn savematrix setmatrix } bind def +/imgdict { /datastream exch def /hasdata exch def /decodeScale exch def /bits exch def /bands exch def /imgheight exch def /imgwidth exch def << /ImageType 1 /Width imgwidth /Height imgheight /BitsPerComponent bits /Decode [bands {0 decodeScale} repeat] +/ImageMatrix [imgwidth 0 0 imgheight 0 0] hasdata { /DataSource datastream } if >> } bind def +/latinize { /fontName exch def /fontNameNew exch def fontName findfont 0 dict copy begin /Encoding ISOLatin1Encoding def fontNameNew /FontName def currentdict end dup /FID undef fontNameNew exch definefont pop } bind def +/LucidaGrandeLat /LucidaGrande latinize /LucidaGrandeLat 12.0 selectfont +gsave +clipsave +/DeviceRGB setcolorspace +0 1162.204724409449 translate +2.834645669291339 -2.834645669291339 scale +/basematrix matrix currentmatrix def +gsave +0.0 0.0 0.0 rgb +1.0 setlinewidth 0 setlinejoin 0 setlinecap [] 0.0 setdash +1.0 1.0 1.0 rgb +newpath 0.0 0.0 1920.0 1200.0 rect Z fill +0.0 0.0 0.0 rgb +/HelveticaLat /Helvetica latinize /HelveticaLat 40.0 selectfont +/LucidaGrandeLat /LucidaGrande latinize /LucidaGrandeLat 12.0 selectfont +newpath 43.45 38.4 M 48.825 35.275 L 48.825 29.025 L 43.45 25.9 L 38.075 29.025 L 38.075 35.275 L Z fill +newpath 68.05 38.4 M 73.425 35.275 L 73.425 29.025 L 68.05 25.9 L 62.675 29.025 L 62.675 35.275 L Z fill +newpath 92.65 38.4 M 98.025 35.275 L 98.025 29.025 L 92.65 25.9 L 87.275 29.025 L 87.275 35.275 L Z fill +newpath 117.25 38.4 M 122.625 35.275 L 122.625 29.025 L 117.25 25.9 L 111.875 29.025 L 111.875 35.275 L Z fill +newpath 141.85000000000002 38.4 M 147.225 35.275 L 147.225 29.025 L 141.85000000000002 25.9 L 136.47500000000002 29.025 L 136.47500000000002 35.275 L Z fill +newpath 166.45 38.4 M 171.825 35.275 L 171.825 29.025 L 166.45 25.9 L 161.075 29.025 L 161.075 35.275 L Z fill +newpath 191.05 38.4 M 196.425 35.275 L 196.425 29.025 L 191.05 25.9 L 185.67499999999998 29.025 L 185.67499999999998 35.275 L Z fill +newpath 215.64999999999998 38.4 M 221.02499999999998 35.275 L 221.02499999999998 29.025 L 215.64999999999998 25.9 L 210.27499999999998 29.025 L 210.27499999999998 35.275 L Z fill +newpath 240.25 38.4 M 245.625 35.275 L 245.625 29.025 L 240.25 25.9 L 234.87499999999997 29.025 L 234.87499999999997 35.275 L Z fill +newpath 264.85 38.4 M 270.225 35.275 L 270.225 29.025 L 264.85 25.9 L 259.47499999999997 29.025 L 259.47499999999997 35.275 L Z fill +newpath 289.45 38.4 M 294.825 35.275 L 294.825 29.025 L 289.45 25.9 L 284.07499999999993 29.025 L 284.07499999999993 35.275 L Z fill +newpath 314.04999999999995 38.4 M 319.425 35.275 L 319.425 29.025 L 314.04999999999995 25.9 L 308.67499999999995 29.025 L 308.67499999999995 35.275 L Z fill +newpath 338.65 38.4 M 344.025 35.275 L 344.025 29.025 L 338.65 25.9 L 333.275 29.025 L 333.275 35.275 L Z fill +newpath 363.25 38.4 M 368.62500000000006 35.275 L 368.62500000000006 29.025 L 363.25 25.9 L 357.875 29.025 L 357.875 35.275 L Z fill +newpath 375.55 38.4 M 380.925 35.275 L 380.925 29.025 L 375.55 25.9 L 370.17499999999995 29.025 L 370.17499999999995 35.275 L Z fill +newpath 387.85 38.4 M 393.225 35.275 L 393.225 29.025 L 387.85 25.9 L 382.475 29.025 L 382.475 35.275 L Z fill +newpath 31.15 59.75 M 36.525 56.625 L 36.525 50.375 L 31.15 47.25 L 25.775 50.375 L 25.775 56.625 L Z fill +newpath 55.75 59.75 M 61.125 56.625 L 61.125 50.375 L 55.75 47.25 L 50.375 50.375 L 50.375 56.625 L Z fill +newpath 80.35 59.75 M 85.725 56.625 L 85.725 50.375 L 80.35 47.25 L 74.97500000000001 50.375 L 74.97500000000001 56.625 L Z fill +newpath 104.95 59.75 M 110.325 56.625 L 110.325 50.375 L 104.95 47.25 L 99.575 50.375 L 99.575 56.625 L Z fill +newpath 129.55 59.75 M 134.925 56.625 L 134.925 50.375 L 129.55 47.25 L 124.17500000000001 50.375 L 124.17500000000001 56.625 L Z fill +newpath 154.15 59.75 M 159.525 56.625 L 159.525 50.375 L 154.15 47.25 L 148.775 50.375 L 148.775 56.625 L Z fill +newpath 178.75 59.75 M 184.125 56.625 L 184.125 50.375 L 178.75 47.25 L 173.375 50.375 L 173.375 56.625 L Z fill +newpath 203.34999999999997 59.75 M 208.725 56.625 L 208.725 50.375 L 203.34999999999997 47.25 L 197.97499999999997 50.375 L 197.97499999999997 56.625 L Z fill +newpath 227.95 59.75 M 233.325 56.625 L 233.325 50.375 L 227.95 47.25 L 222.57499999999996 50.375 L 222.57499999999996 56.625 L Z fill +newpath 252.54999999999998 59.75 M 257.925 56.625 L 257.925 50.375 L 252.54999999999998 47.25 L 247.17499999999998 50.375 L 247.17499999999998 56.625 L Z fill +newpath 277.15 59.75 M 282.52500000000003 56.625 L 282.52500000000003 50.375 L 277.15 47.25 L 271.775 50.375 L 271.775 56.625 L Z fill +newpath 301.75 59.75 M 307.125 56.625 L 307.125 50.375 L 301.75 47.25 L 296.37499999999994 50.375 L 296.37499999999994 56.625 L Z fill +newpath 326.34999999999997 59.75 M 331.725 56.625 L 331.725 50.375 L 326.34999999999997 47.25 L 320.97499999999997 50.375 L 320.97499999999997 56.625 L Z fill +newpath 350.95 59.75 M 356.325 56.625 L 356.325 50.375 L 350.95 47.25 L 345.575 50.375 L 345.575 56.625 L Z fill +newpath 375.55 59.75 M 380.925 56.625 L 380.925 50.375 L 375.55 47.25 L 370.17499999999995 50.375 L 370.17499999999995 56.625 L Z fill +newpath 49.6 70.425 M 54.975 67.3 L 54.975 61.05 L 49.6 57.925 L 44.224999999999994 61.05 L 44.224999999999994 67.3 L Z fill +newpath 74.2 70.425 M 79.57499999999999 67.3 L 79.57499999999999 61.05 L 74.2 57.925 L 68.825 61.05 L 68.825 67.3 L Z fill +newpath 98.80000000000001 70.425 M 104.17500000000001 67.3 L 104.17500000000001 61.05 L 98.80000000000001 57.925 L 93.42500000000001 61.05 L 93.42500000000001 67.3 L Z fill +newpath 123.4 70.425 M 128.77499999999998 67.3 L 128.77499999999998 61.05 L 123.4 57.925 L 118.025 61.05 L 118.025 67.3 L Z fill +newpath 148.0 70.425 M 153.375 67.3 L 153.375 61.05 L 148.0 57.925 L 142.625 61.05 L 142.625 67.3 L Z fill +newpath 172.6 70.425 M 177.975 67.3 L 177.975 61.05 L 172.6 57.925 L 167.225 61.05 L 167.225 67.3 L Z fill +newpath 197.2 70.425 M 202.575 67.3 L 202.575 61.05 L 197.2 57.925 L 191.825 61.05 L 191.825 67.3 L Z fill +newpath 221.79999999999995 70.425 M 227.17499999999998 67.3 L 227.17499999999998 61.05 L 221.79999999999995 57.925 L 216.42499999999995 61.05 L 216.42499999999995 67.3 L Z fill +newpath 246.39999999999998 70.425 M 251.77499999999998 67.3 L 251.77499999999998 61.05 L 246.39999999999998 57.925 L 241.02499999999995 61.05 L 241.02499999999995 67.3 L Z fill +newpath 271.0 70.425 M 276.375 67.3 L 276.375 61.05 L 271.0 57.925 L 265.625 61.05 L 265.625 67.3 L Z fill +newpath 295.59999999999997 70.425 M 300.97499999999997 67.3 L 300.97499999999997 61.05 L 295.59999999999997 57.925 L 290.2249999999999 61.05 L 290.2249999999999 67.3 L Z fill +newpath 320.19999999999993 70.425 M 325.575 67.3 L 325.575 61.05 L 320.19999999999993 57.925 L 314.82499999999993 61.05 L 314.82499999999993 67.3 L Z fill +newpath 344.79999999999995 70.425 M 350.17499999999995 67.3 L 350.17499999999995 61.05 L 344.79999999999995 57.925 L 339.42499999999995 61.05 L 339.42499999999995 67.3 L Z fill +newpath 369.40000000000003 70.425 M 374.7750000000001 67.3 L 374.7750000000001 61.05 L 369.40000000000003 57.925 L 364.02500000000003 61.05 L 364.02500000000003 67.3 L Z fill +newpath 381.70000000000005 70.425 M 387.07500000000005 67.3 L 387.07500000000005 61.05 L 381.70000000000005 57.925 L 376.325 61.05 L 376.325 67.3 L Z fill +newpath 387.85 81.1 M 393.225 77.975 L 393.225 71.725 L 387.85 68.6 L 382.475 71.725 L 382.475 77.975 L Z fill +newpath 37.3 91.77499999999999 M 42.675 88.64999999999999 L 42.675 82.39999999999999 L 37.3 79.27499999999999 L 31.925 82.39999999999999 L 31.925 88.64999999999999 L Z fill +newpath 61.900000000000006 91.77499999999999 M 67.275 88.64999999999999 L 67.275 82.39999999999999 L 61.900000000000006 79.27499999999999 L 56.525000000000006 82.39999999999999 L 56.525000000000006 88.64999999999999 L Z fill +newpath 86.5 91.77499999999999 M 91.875 88.64999999999999 L 91.875 82.39999999999999 L 86.5 79.27499999999999 L 81.125 82.39999999999999 L 81.125 88.64999999999999 L Z fill +newpath 111.1 91.77499999999999 M 116.475 88.64999999999999 L 116.475 82.39999999999999 L 111.1 79.27499999999999 L 105.725 82.39999999999999 L 105.725 88.64999999999999 L Z fill +newpath 135.7 91.77499999999999 M 141.075 88.64999999999999 L 141.075 82.39999999999999 L 135.7 79.27499999999999 L 130.325 82.39999999999999 L 130.325 88.64999999999999 L Z fill +newpath 160.3 91.77499999999999 M 165.675 88.64999999999999 L 165.675 82.39999999999999 L 160.3 79.27499999999999 L 154.925 82.39999999999999 L 154.925 88.64999999999999 L Z fill +newpath 184.9 91.77499999999999 M 190.275 88.64999999999999 L 190.275 82.39999999999999 L 184.9 79.27499999999999 L 179.525 82.39999999999999 L 179.525 88.64999999999999 L Z fill +newpath 209.49999999999994 91.77499999999999 M 214.87499999999997 88.64999999999999 L 214.87499999999997 82.39999999999999 L 209.49999999999994 79.27499999999999 L 204.12499999999994 82.39999999999999 L 204.12499999999994 88.64999999999999 L Z fill +newpath 234.09999999999997 91.77499999999999 M 239.47499999999997 88.64999999999999 L 239.47499999999997 82.39999999999999 L 234.09999999999997 79.27499999999999 L 228.72499999999997 82.39999999999999 L 228.72499999999997 88.64999999999999 L Z fill +newpath 258.7 91.77499999999999 M 264.075 88.64999999999999 L 264.075 82.39999999999999 L 258.7 79.27499999999999 L 253.32499999999996 82.39999999999999 L 253.32499999999996 88.64999999999999 L Z fill +newpath 283.29999999999995 91.77499999999999 M 288.675 88.64999999999999 L 288.675 82.39999999999999 L 283.29999999999995 79.27499999999999 L 277.92499999999995 82.39999999999999 L 277.92499999999995 88.64999999999999 L Z fill +newpath 307.9 91.77499999999999 M 313.275 88.64999999999999 L 313.275 82.39999999999999 L 307.9 79.27499999999999 L 302.5249999999999 82.39999999999999 L 302.5249999999999 88.64999999999999 L Z fill +newpath 332.49999999999994 91.77499999999999 M 337.875 88.64999999999999 L 337.875 82.39999999999999 L 332.49999999999994 79.27499999999999 L 327.12499999999994 82.39999999999999 L 327.12499999999994 88.64999999999999 L Z fill +newpath 357.1 91.77499999999999 M 362.475 88.64999999999999 L 362.475 82.39999999999999 L 357.1 79.27499999999999 L 351.725 82.39999999999999 L 351.725 88.64999999999999 L Z fill +newpath 43.45 102.44999999999999 M 48.825 99.32499999999999 L 48.825 93.07499999999999 L 43.45 89.94999999999999 L 38.075 93.07499999999999 L 38.075 99.32499999999999 L Z fill +newpath 68.05 102.44999999999999 M 73.425 99.32499999999999 L 73.425 93.07499999999999 L 68.05 89.94999999999999 L 62.675 93.07499999999999 L 62.675 99.32499999999999 L Z fill +newpath 92.65 102.44999999999999 M 98.025 99.32499999999999 L 98.025 93.07499999999999 L 92.65 89.94999999999999 L 87.275 93.07499999999999 L 87.275 99.32499999999999 L Z fill +newpath 117.25 102.44999999999999 M 122.625 99.32499999999999 L 122.625 93.07499999999999 L 117.25 89.94999999999999 L 111.875 93.07499999999999 L 111.875 99.32499999999999 L Z fill +newpath 141.85000000000002 102.44999999999999 M 147.225 99.32499999999999 L 147.225 93.07499999999999 L 141.85000000000002 89.94999999999999 L 136.47500000000002 93.07499999999999 L 136.47500000000002 99.32499999999999 L Z fill +newpath 166.45 102.44999999999999 M 171.825 99.32499999999999 L 171.825 93.07499999999999 L 166.45 89.94999999999999 L 161.075 93.07499999999999 L 161.075 99.32499999999999 L Z fill +newpath 191.05 102.44999999999999 M 196.425 99.32499999999999 L 196.425 93.07499999999999 L 191.05 89.94999999999999 L 185.67499999999998 93.07499999999999 L 185.67499999999998 99.32499999999999 L Z fill +newpath 215.64999999999998 102.44999999999999 M 221.02499999999998 99.32499999999999 L 221.02499999999998 93.07499999999999 L 215.64999999999998 89.94999999999999 L 210.27499999999998 93.07499999999999 L 210.27499999999998 99.32499999999999 L Z fill +newpath 240.25 102.44999999999999 M 245.625 99.32499999999999 L 245.625 93.07499999999999 L 240.25 89.94999999999999 L 234.87499999999997 93.07499999999999 L 234.87499999999997 99.32499999999999 L Z fill +newpath 264.85 102.44999999999999 M 270.225 99.32499999999999 L 270.225 93.07499999999999 L 264.85 89.94999999999999 L 259.47499999999997 93.07499999999999 L 259.47499999999997 99.32499999999999 L Z fill +newpath 289.45 102.44999999999999 M 294.825 99.32499999999999 L 294.825 93.07499999999999 L 289.45 89.94999999999999 L 284.07499999999993 93.07499999999999 L 284.07499999999993 99.32499999999999 L Z fill +newpath 314.04999999999995 102.44999999999999 M 319.425 99.32499999999999 L 319.425 93.07499999999999 L 314.04999999999995 89.94999999999999 L 308.67499999999995 93.07499999999999 L 308.67499999999995 99.32499999999999 L Z fill +newpath 338.65 102.44999999999999 M 344.025 99.32499999999999 L 344.025 93.07499999999999 L 338.65 89.94999999999999 L 333.275 93.07499999999999 L 333.275 99.32499999999999 L Z fill +newpath 363.25 102.44999999999999 M 368.62500000000006 99.32499999999999 L 368.62500000000006 93.07499999999999 L 363.25 89.94999999999999 L 357.875 93.07499999999999 L 357.875 99.32499999999999 L Z fill +newpath 375.55 102.44999999999999 M 380.925 99.32499999999999 L 380.925 93.07499999999999 L 375.55 89.94999999999999 L 370.17499999999995 93.07499999999999 L 370.17499999999995 99.32499999999999 L Z fill +newpath 381.70000000000005 113.125 M 387.07500000000005 110.0 L 387.07500000000005 103.75 L 381.70000000000005 100.625 L 376.325 103.75 L 376.325 110.0 L Z fill +newpath 31.15 123.79999999999998 M 36.525 120.67499999999998 L 36.525 114.42499999999998 L 31.15 111.29999999999998 L 25.775 114.42499999999998 L 25.775 120.67499999999998 L Z fill +newpath 55.75 123.79999999999998 M 61.125 120.67499999999998 L 61.125 114.42499999999998 L 55.75 111.29999999999998 L 50.375 114.42499999999998 L 50.375 120.67499999999998 L Z fill +newpath 80.35 123.79999999999998 M 85.725 120.67499999999998 L 85.725 114.42499999999998 L 80.35 111.29999999999998 L 74.97500000000001 114.42499999999998 L 74.97500000000001 120.67499999999998 L Z fill +newpath 104.95 123.79999999999998 M 110.325 120.67499999999998 L 110.325 114.42499999999998 L 104.95 111.29999999999998 L 99.575 114.42499999999998 L 99.575 120.67499999999998 L Z fill +newpath 129.55 123.79999999999998 M 134.925 120.67499999999998 L 134.925 114.42499999999998 L 129.55 111.29999999999998 L 124.17500000000001 114.42499999999998 L 124.17500000000001 120.67499999999998 L Z fill +newpath 154.15 123.79999999999998 M 159.525 120.67499999999998 L 159.525 114.42499999999998 L 154.15 111.29999999999998 L 148.775 114.42499999999998 L 148.775 120.67499999999998 L Z fill +newpath 178.75 123.79999999999998 M 184.125 120.67499999999998 L 184.125 114.42499999999998 L 178.75 111.29999999999998 L 173.375 114.42499999999998 L 173.375 120.67499999999998 L Z fill +newpath 203.34999999999997 123.79999999999998 M 208.725 120.67499999999998 L 208.725 114.42499999999998 L 203.34999999999997 111.29999999999998 L 197.97499999999997 114.42499999999998 L 197.97499999999997 120.67499999999998 L Z fill +newpath 227.95 123.79999999999998 M 233.325 120.67499999999998 L 233.325 114.42499999999998 L 227.95 111.29999999999998 L 222.57499999999996 114.42499999999998 L 222.57499999999996 120.67499999999998 L Z fill +newpath 252.54999999999998 123.79999999999998 M 257.925 120.67499999999998 L 257.925 114.42499999999998 L 252.54999999999998 111.29999999999998 L 247.17499999999998 114.42499999999998 L 247.17499999999998 120.67499999999998 L Z fill +newpath 277.15 123.79999999999998 M 282.52500000000003 120.67499999999998 L 282.52500000000003 114.42499999999998 L 277.15 111.29999999999998 L 271.775 114.42499999999998 L 271.775 120.67499999999998 L Z fill +newpath 301.75 123.79999999999998 M 307.125 120.67499999999998 L 307.125 114.42499999999998 L 301.75 111.29999999999998 L 296.37499999999994 114.42499999999998 L 296.37499999999994 120.67499999999998 L Z fill +newpath 326.34999999999997 123.79999999999998 M 331.725 120.67499999999998 L 331.725 114.42499999999998 L 326.34999999999997 111.29999999999998 L 320.97499999999997 114.42499999999998 L 320.97499999999997 120.67499999999998 L Z fill +newpath 350.95 123.79999999999998 M 356.325 120.67499999999998 L 356.325 114.42499999999998 L 350.95 111.29999999999998 L 345.575 114.42499999999998 L 345.575 120.67499999999998 L Z fill +newpath 387.85 123.79999999999998 M 393.225 120.67499999999998 L 393.225 114.42499999999998 L 387.85 111.29999999999998 L 382.475 114.42499999999998 L 382.475 120.67499999999998 L Z fill +newpath 49.6 134.47499999999997 M 54.975 131.34999999999997 L 54.975 125.09999999999998 L 49.6 121.97499999999998 L 44.224999999999994 125.09999999999998 L 44.224999999999994 131.34999999999997 L Z fill +newpath 74.2 134.47499999999997 M 79.57499999999999 131.34999999999997 L 79.57499999999999 125.09999999999998 L 74.2 121.97499999999998 L 68.825 125.09999999999998 L 68.825 131.34999999999997 L Z fill +newpath 98.80000000000001 134.47499999999997 M 104.17500000000001 131.34999999999997 L 104.17500000000001 125.09999999999998 L 98.80000000000001 121.97499999999998 L 93.42500000000001 125.09999999999998 L 93.42500000000001 131.34999999999997 L Z fill +newpath 123.4 134.47499999999997 M 128.77499999999998 131.34999999999997 L 128.77499999999998 125.09999999999998 L 123.4 121.97499999999998 L 118.025 125.09999999999998 L 118.025 131.34999999999997 L Z fill +newpath 135.7 134.47499999999997 M 141.075 131.34999999999997 L 141.075 125.09999999999998 L 135.7 121.97499999999998 L 130.325 125.09999999999998 L 130.325 131.34999999999997 L Z fill +newpath 148.0 134.47499999999997 M 153.375 131.34999999999997 L 153.375 125.09999999999998 L 148.0 121.97499999999998 L 142.625 125.09999999999998 L 142.625 131.34999999999997 L Z fill +newpath 160.3 134.47499999999997 M 165.675 131.34999999999997 L 165.675 125.09999999999998 L 160.3 121.97499999999998 L 154.925 125.09999999999998 L 154.925 131.34999999999997 L Z fill +newpath 172.6 134.47499999999997 M 177.975 131.34999999999997 L 177.975 125.09999999999998 L 172.6 121.97499999999998 L 167.225 125.09999999999998 L 167.225 131.34999999999997 L Z fill +newpath 209.49999999999994 134.47499999999997 M 214.87499999999997 131.34999999999997 L 214.87499999999997 125.09999999999998 L 209.49999999999994 121.97499999999998 L 204.12499999999994 125.09999999999998 L 204.12499999999994 131.34999999999997 L Z fill +newpath 283.29999999999995 134.47499999999997 M 288.675 131.34999999999997 L 288.675 125.09999999999998 L 283.29999999999995 121.97499999999998 L 277.92499999999995 125.09999999999998 L 277.92499999999995 131.34999999999997 L Z fill +newpath 295.59999999999997 134.47499999999997 M 300.97499999999997 131.34999999999997 L 300.97499999999997 125.09999999999998 L 295.59999999999997 121.97499999999998 L 290.2249999999999 125.09999999999998 L 290.2249999999999 131.34999999999997 L Z fill +newpath 320.19999999999993 134.47499999999997 M 325.575 131.34999999999997 L 325.575 125.09999999999998 L 320.19999999999993 121.97499999999998 L 314.82499999999993 125.09999999999998 L 314.82499999999993 131.34999999999997 L Z fill +newpath 344.79999999999995 134.47499999999997 M 350.17499999999995 131.34999999999997 L 350.17499999999995 125.09999999999998 L 344.79999999999995 121.97499999999998 L 339.42499999999995 125.09999999999998 L 339.42499999999995 131.34999999999997 L Z fill +newpath 369.40000000000003 134.47499999999997 M 374.7750000000001 131.34999999999997 L 374.7750000000001 125.09999999999998 L 369.40000000000003 121.97499999999998 L 364.02500000000003 125.09999999999998 L 364.02500000000003 131.34999999999997 L Z fill +newpath 166.45 145.14999999999998 M 171.825 142.02499999999998 L 171.825 135.77499999999998 L 166.45 132.64999999999998 L 161.075 135.77499999999998 L 161.075 142.02499999999998 L Z fill +newpath 178.75 145.14999999999998 M 184.125 142.02499999999998 L 184.125 135.77499999999998 L 178.75 132.64999999999998 L 173.375 135.77499999999998 L 173.375 142.02499999999998 L Z fill +newpath 203.34999999999997 145.14999999999998 M 208.725 142.02499999999998 L 208.725 135.77499999999998 L 203.34999999999997 132.64999999999998 L 197.97499999999997 135.77499999999998 L 197.97499999999997 142.02499999999998 L Z fill +newpath 227.95 145.14999999999998 M 233.325 142.02499999999998 L 233.325 135.77499999999998 L 227.95 132.64999999999998 L 222.57499999999996 135.77499999999998 L 222.57499999999996 142.02499999999998 L Z fill +newpath 277.15 145.14999999999998 M 282.52500000000003 142.02499999999998 L 282.52500000000003 135.77499999999998 L 277.15 132.64999999999998 L 271.775 135.77499999999998 L 271.775 142.02499999999998 L Z fill +newpath 289.45 145.14999999999998 M 294.825 142.02499999999998 L 294.825 135.77499999999998 L 289.45 132.64999999999998 L 284.07499999999993 135.77499999999998 L 284.07499999999993 142.02499999999998 L Z fill +newpath 37.3 155.825 M 42.675 152.7 L 42.675 146.45 L 37.3 143.325 L 31.925 146.45 L 31.925 152.7 L Z fill +newpath 61.900000000000006 155.825 M 67.275 152.7 L 67.275 146.45 L 61.900000000000006 143.325 L 56.525000000000006 146.45 L 56.525000000000006 152.7 L Z fill +newpath 86.5 155.825 M 91.875 152.7 L 91.875 146.45 L 86.5 143.325 L 81.125 146.45 L 81.125 152.7 L Z fill +newpath 111.1 155.825 M 116.475 152.7 L 116.475 146.45 L 111.1 143.325 L 105.725 146.45 L 105.725 152.7 L Z fill +newpath 160.3 155.825 M 165.675 152.7 L 165.675 146.45 L 160.3 143.325 L 154.925 146.45 L 154.925 152.7 L Z fill +newpath 258.7 155.825 M 264.075 152.7 L 264.075 146.45 L 258.7 143.325 L 253.32499999999996 146.45 L 253.32499999999996 152.7 L Z fill +newpath 283.29999999999995 155.825 M 288.675 152.7 L 288.675 146.45 L 283.29999999999995 143.325 L 277.92499999999995 146.45 L 277.92499999999995 152.7 L Z fill +newpath 307.9 155.825 M 313.275 152.7 L 313.275 146.45 L 307.9 143.325 L 302.5249999999999 146.45 L 302.5249999999999 152.7 L Z fill +newpath 332.49999999999994 155.825 M 337.875 152.7 L 337.875 146.45 L 332.49999999999994 143.325 L 327.12499999999994 146.45 L 327.12499999999994 152.7 L Z fill +newpath 357.1 155.825 M 362.475 152.7 L 362.475 146.45 L 357.1 143.325 L 351.725 146.45 L 351.725 152.7 L Z fill +newpath 381.70000000000005 155.825 M 387.07500000000005 152.7 L 387.07500000000005 146.45 L 381.70000000000005 143.325 L 376.325 146.45 L 376.325 152.7 L Z fill +newpath 43.45 166.5 M 48.825 163.375 L 48.825 157.125 L 43.45 154.0 L 38.075 157.125 L 38.075 163.375 L Z fill +newpath 68.05 166.5 M 73.425 163.375 L 73.425 157.125 L 68.05 154.0 L 62.675 157.125 L 62.675 163.375 L Z fill +newpath 92.65 166.5 M 98.025 163.375 L 98.025 157.125 L 92.65 154.0 L 87.275 157.125 L 87.275 163.375 L Z fill +newpath 117.25 166.5 M 122.625 163.375 L 122.625 157.125 L 117.25 154.0 L 111.875 157.125 L 111.875 163.375 L Z fill +newpath 141.85000000000002 166.5 M 147.225 163.375 L 147.225 157.125 L 141.85000000000002 154.0 L 136.47500000000002 157.125 L 136.47500000000002 163.375 L Z fill +newpath 154.15 166.5 M 159.525 163.375 L 159.525 157.125 L 154.15 154.0 L 148.775 157.125 L 148.775 163.375 L Z fill +newpath 264.85 166.5 M 270.225 163.375 L 270.225 157.125 L 264.85 154.0 L 259.47499999999997 157.125 L 259.47499999999997 163.375 L Z fill +newpath 277.15 166.5 M 282.52500000000003 163.375 L 282.52500000000003 157.125 L 277.15 154.0 L 271.775 157.125 L 271.775 163.375 L Z fill +newpath 314.04999999999995 166.5 M 319.425 163.375 L 319.425 157.125 L 314.04999999999995 154.0 L 308.67499999999995 157.125 L 308.67499999999995 163.375 L Z fill +newpath 338.65 166.5 M 344.025 163.375 L 344.025 157.125 L 338.65 154.0 L 333.275 157.125 L 333.275 163.375 L Z fill +newpath 363.25 166.5 M 368.62500000000006 163.375 L 368.62500000000006 157.125 L 363.25 154.0 L 357.875 157.125 L 357.875 163.375 L Z fill +newpath 375.55 166.5 M 380.925 163.375 L 380.925 157.125 L 375.55 154.0 L 370.17499999999995 157.125 L 370.17499999999995 163.375 L Z fill +newpath 111.1 177.17499999999998 M 116.475 174.04999999999998 L 116.475 167.79999999999998 L 111.1 164.67499999999998 L 105.725 167.79999999999998 L 105.725 174.04999999999998 L Z fill +newpath 258.7 177.17499999999998 M 264.075 174.04999999999998 L 264.075 167.79999999999998 L 258.7 164.67499999999998 L 253.32499999999996 167.79999999999998 L 253.32499999999996 174.04999999999998 L Z fill +newpath 271.0 177.17499999999998 M 276.375 174.04999999999998 L 276.375 167.79999999999998 L 271.0 164.67499999999998 L 265.625 167.79999999999998 L 265.625 174.04999999999998 L Z fill +newpath 283.29999999999995 177.17499999999998 M 288.675 174.04999999999998 L 288.675 167.79999999999998 L 283.29999999999995 164.67499999999998 L 277.92499999999995 167.79999999999998 L 277.92499999999995 174.04999999999998 L Z fill +newpath 295.59999999999997 177.17499999999998 M 300.97499999999997 174.04999999999998 L 300.97499999999997 167.79999999999998 L 295.59999999999997 164.67499999999998 L 290.2249999999999 167.79999999999998 L 290.2249999999999 174.04999999999998 L Z fill +newpath 31.15 187.84999999999997 M 36.525 184.725 L 36.525 178.475 L 31.15 175.35 L 25.775 178.475 L 25.775 184.725 L Z fill +newpath 55.75 187.84999999999997 M 61.125 184.725 L 61.125 178.475 L 55.75 175.35 L 50.375 178.475 L 50.375 184.725 L Z fill +newpath 80.35 187.84999999999997 M 85.725 184.725 L 85.725 178.475 L 80.35 175.35 L 74.97500000000001 178.475 L 74.97500000000001 184.725 L Z fill +newpath 104.95 187.84999999999997 M 110.325 184.725 L 110.325 178.475 L 104.95 175.35 L 99.575 178.475 L 99.575 184.725 L Z fill +newpath 129.55 187.84999999999997 M 134.925 184.725 L 134.925 178.475 L 129.55 175.35 L 124.17500000000001 178.475 L 124.17500000000001 184.725 L Z fill +newpath 277.15 187.84999999999997 M 282.52500000000003 184.725 L 282.52500000000003 178.475 L 277.15 175.35 L 271.775 178.475 L 271.775 184.725 L Z fill +newpath 301.75 187.84999999999997 M 307.125 184.725 L 307.125 178.475 L 301.75 175.35 L 296.37499999999994 178.475 L 296.37499999999994 184.725 L Z fill +newpath 326.34999999999997 187.84999999999997 M 331.725 184.725 L 331.725 178.475 L 326.34999999999997 175.35 L 320.97499999999997 178.475 L 320.97499999999997 184.725 L Z fill +newpath 350.95 187.84999999999997 M 356.325 184.725 L 356.325 178.475 L 350.95 175.35 L 345.575 178.475 L 345.575 184.725 L Z fill +newpath 49.6 198.52499999999998 M 54.975 195.39999999999998 L 54.975 189.14999999999998 L 49.6 186.02499999999998 L 44.224999999999994 189.14999999999998 L 44.224999999999994 195.39999999999998 L Z fill +newpath 74.2 198.52499999999998 M 79.57499999999999 195.39999999999998 L 79.57499999999999 189.14999999999998 L 74.2 186.02499999999998 L 68.825 189.14999999999998 L 68.825 195.39999999999998 L Z fill +newpath 98.80000000000001 198.52499999999998 M 104.17500000000001 195.39999999999998 L 104.17500000000001 189.14999999999998 L 98.80000000000001 186.02499999999998 L 93.42500000000001 189.14999999999998 L 93.42500000000001 195.39999999999998 L Z fill +newpath 111.1 198.52499999999998 M 116.475 195.39999999999998 L 116.475 189.14999999999998 L 111.1 186.02499999999998 L 105.725 189.14999999999998 L 105.725 195.39999999999998 L Z fill +newpath 123.4 198.52499999999998 M 128.77499999999998 195.39999999999998 L 128.77499999999998 189.14999999999998 L 123.4 186.02499999999998 L 118.025 189.14999999999998 L 118.025 195.39999999999998 L Z fill +newpath 135.7 198.52499999999998 M 141.075 195.39999999999998 L 141.075 189.14999999999998 L 135.7 186.02499999999998 L 130.325 189.14999999999998 L 130.325 195.39999999999998 L Z fill +newpath 283.29999999999995 198.52499999999998 M 288.675 195.39999999999998 L 288.675 189.14999999999998 L 283.29999999999995 186.02499999999998 L 277.92499999999995 189.14999999999998 L 277.92499999999995 195.39999999999998 L Z fill +newpath 320.19999999999993 198.52499999999998 M 325.575 195.39999999999998 L 325.575 189.14999999999998 L 320.19999999999993 186.02499999999998 L 314.82499999999993 189.14999999999998 L 314.82499999999993 195.39999999999998 L Z fill +newpath 344.79999999999995 198.52499999999998 M 350.17499999999995 195.39999999999998 L 350.17499999999995 189.14999999999998 L 344.79999999999995 186.02499999999998 L 339.42499999999995 189.14999999999998 L 339.42499999999995 195.39999999999998 L Z fill +newpath 369.40000000000003 198.52499999999998 M 374.7750000000001 195.39999999999998 L 374.7750000000001 189.14999999999998 L 369.40000000000003 186.02499999999998 L 364.02500000000003 189.14999999999998 L 364.02500000000003 195.39999999999998 L Z fill +newpath 381.70000000000005 198.52499999999998 M 387.07500000000005 195.39999999999998 L 387.07500000000005 189.14999999999998 L 381.70000000000005 186.02499999999998 L 376.325 189.14999999999998 L 376.325 195.39999999999998 L Z fill +newpath 129.55 209.2 M 134.925 206.075 L 134.925 199.825 L 129.55 196.7 L 124.17500000000001 199.825 L 124.17500000000001 206.075 L Z fill +newpath 277.15 209.2 M 282.52500000000003 206.075 L 282.52500000000003 199.825 L 277.15 196.7 L 271.775 199.825 L 271.775 206.075 L Z fill +newpath 375.55 209.2 M 380.925 206.075 L 380.925 199.825 L 375.55 196.7 L 370.17499999999995 199.825 L 370.17499999999995 206.075 L Z fill +newpath 37.3 219.87499999999997 M 42.675 216.74999999999997 L 42.675 210.49999999999997 L 37.3 207.37499999999997 L 31.925 210.49999999999997 L 31.925 216.74999999999997 L Z fill +newpath 61.900000000000006 219.87499999999997 M 67.275 216.74999999999997 L 67.275 210.49999999999997 L 61.900000000000006 207.37499999999997 L 56.525000000000006 210.49999999999997 L 56.525000000000006 216.74999999999997 L Z fill +newpath 86.5 219.87499999999997 M 91.875 216.74999999999997 L 91.875 210.49999999999997 L 86.5 207.37499999999997 L 81.125 210.49999999999997 L 81.125 216.74999999999997 L Z fill +newpath 135.7 219.87499999999997 M 141.075 216.74999999999997 L 141.075 210.49999999999997 L 135.7 207.37499999999997 L 130.325 210.49999999999997 L 130.325 216.74999999999997 L Z fill +newpath 283.29999999999995 219.87499999999997 M 288.675 216.74999999999997 L 288.675 210.49999999999997 L 283.29999999999995 207.37499999999997 L 277.92499999999995 210.49999999999997 L 277.92499999999995 216.74999999999997 L Z fill +newpath 295.59999999999997 219.87499999999997 M 300.97499999999997 216.74999999999997 L 300.97499999999997 210.49999999999997 L 295.59999999999997 207.37499999999997 L 290.2249999999999 210.49999999999997 L 290.2249999999999 216.74999999999997 L Z fill +newpath 307.9 219.87499999999997 M 313.275 216.74999999999997 L 313.275 210.49999999999997 L 307.9 207.37499999999997 L 302.5249999999999 210.49999999999997 L 302.5249999999999 216.74999999999997 L Z fill +newpath 332.49999999999994 219.87499999999997 M 337.875 216.74999999999997 L 337.875 210.49999999999997 L 332.49999999999994 207.37499999999997 L 327.12499999999994 210.49999999999997 L 327.12499999999994 216.74999999999997 L Z fill +newpath 357.1 219.87499999999997 M 362.475 216.74999999999997 L 362.475 210.49999999999997 L 357.1 207.37499999999997 L 351.725 210.49999999999997 L 351.725 216.74999999999997 L Z fill +newpath 43.45 230.54999999999995 M 48.825 227.42499999999995 L 48.825 221.17499999999995 L 43.45 218.04999999999995 L 38.075 221.17499999999995 L 38.075 227.42499999999995 L Z fill +newpath 68.05 230.54999999999995 M 73.425 227.42499999999995 L 73.425 221.17499999999995 L 68.05 218.04999999999995 L 62.675 221.17499999999995 L 62.675 227.42499999999995 L Z fill +newpath 92.65 230.54999999999995 M 98.025 227.42499999999995 L 98.025 221.17499999999995 L 92.65 218.04999999999995 L 87.275 221.17499999999995 L 87.275 227.42499999999995 L Z fill +newpath 117.25 230.54999999999995 M 122.625 227.42499999999995 L 122.625 221.17499999999995 L 117.25 218.04999999999995 L 111.875 221.17499999999995 L 111.875 227.42499999999995 L Z fill +newpath 141.85000000000002 230.54999999999995 M 147.225 227.42499999999995 L 147.225 221.17499999999995 L 141.85000000000002 218.04999999999995 L 136.47500000000002 221.17499999999995 L 136.47500000000002 227.42499999999995 L Z fill +newpath 264.85 230.54999999999995 M 270.225 227.42499999999995 L 270.225 221.17499999999995 L 264.85 218.04999999999995 L 259.47499999999997 221.17499999999995 L 259.47499999999997 227.42499999999995 L Z fill +newpath 277.15 230.54999999999995 M 282.52500000000003 227.42499999999995 L 282.52500000000003 221.17499999999995 L 277.15 218.04999999999995 L 271.775 221.17499999999995 L 271.775 227.42499999999995 L Z fill +newpath 289.45 230.54999999999995 M 294.825 227.42499999999995 L 294.825 221.17499999999995 L 289.45 218.04999999999995 L 284.07499999999993 221.17499999999995 L 284.07499999999993 227.42499999999995 L Z fill +newpath 314.04999999999995 230.54999999999995 M 319.425 227.42499999999995 L 319.425 221.17499999999995 L 314.04999999999995 218.04999999999995 L 308.67499999999995 221.17499999999995 L 308.67499999999995 227.42499999999995 L Z fill +newpath 338.65 230.54999999999995 M 344.025 227.42499999999995 L 344.025 221.17499999999995 L 338.65 218.04999999999995 L 333.275 221.17499999999995 L 333.275 227.42499999999995 L Z fill +newpath 363.25 230.54999999999995 M 368.62500000000006 227.42499999999995 L 368.62500000000006 221.17499999999995 L 363.25 218.04999999999995 L 357.875 221.17499999999995 L 357.875 227.42499999999995 L Z fill +newpath 375.55 230.54999999999995 M 380.925 227.42499999999995 L 380.925 221.17499999999995 L 375.55 218.04999999999995 L 370.17499999999995 221.17499999999995 L 370.17499999999995 227.42499999999995 L Z fill +newpath 387.85 230.54999999999995 M 393.225 227.42499999999995 L 393.225 221.17499999999995 L 387.85 218.04999999999995 L 382.475 221.17499999999995 L 382.475 227.42499999999995 L Z fill +newpath 111.1 241.225 M 116.475 238.1 L 116.475 231.85 L 111.1 228.725 L 105.725 231.85 L 105.725 238.1 L Z fill +newpath 135.7 241.225 M 141.075 238.1 L 141.075 231.85 L 135.7 228.725 L 130.325 231.85 L 130.325 238.1 L Z fill +newpath 148.0 241.225 M 153.375 238.1 L 153.375 231.85 L 148.0 228.725 L 142.625 231.85 L 142.625 238.1 L Z fill +newpath 271.0 241.225 M 276.375 238.1 L 276.375 231.85 L 271.0 228.725 L 265.625 231.85 L 265.625 238.1 L Z fill +newpath 381.70000000000005 241.225 M 387.07500000000005 238.1 L 387.07500000000005 231.85 L 381.70000000000005 228.725 L 376.325 231.85 L 376.325 238.1 L Z fill +newpath 31.15 251.89999999999998 M 36.525 248.77499999999998 L 36.525 242.52499999999998 L 31.15 239.39999999999998 L 25.775 242.52499999999998 L 25.775 248.77499999999998 L Z fill +newpath 55.75 251.89999999999998 M 61.125 248.77499999999998 L 61.125 242.52499999999998 L 55.75 239.39999999999998 L 50.375 242.52499999999998 L 50.375 248.77499999999998 L Z fill +newpath 80.35 251.89999999999998 M 85.725 248.77499999999998 L 85.725 242.52499999999998 L 80.35 239.39999999999998 L 74.97500000000001 242.52499999999998 L 74.97500000000001 248.77499999999998 L Z fill +newpath 117.25 251.89999999999998 M 122.625 248.77499999999998 L 122.625 242.52499999999998 L 117.25 239.39999999999998 L 111.875 242.52499999999998 L 111.875 248.77499999999998 L Z fill +newpath 141.85000000000002 251.89999999999998 M 147.225 248.77499999999998 L 147.225 242.52499999999998 L 141.85000000000002 239.39999999999998 L 136.47500000000002 242.52499999999998 L 136.47500000000002 248.77499999999998 L Z fill +newpath 154.15 251.89999999999998 M 159.525 248.77499999999998 L 159.525 242.52499999999998 L 154.15 239.39999999999998 L 148.775 242.52499999999998 L 148.775 248.77499999999998 L Z fill +newpath 277.15 251.89999999999998 M 282.52500000000003 248.77499999999998 L 282.52500000000003 242.52499999999998 L 277.15 239.39999999999998 L 271.775 242.52499999999998 L 271.775 248.77499999999998 L Z fill +newpath 289.45 251.89999999999998 M 294.825 248.77499999999998 L 294.825 242.52499999999998 L 289.45 239.39999999999998 L 284.07499999999993 242.52499999999998 L 284.07499999999993 248.77499999999998 L Z fill +newpath 301.75 251.89999999999998 M 307.125 248.77499999999998 L 307.125 242.52499999999998 L 301.75 239.39999999999998 L 296.37499999999994 242.52499999999998 L 296.37499999999994 248.77499999999998 L Z fill +newpath 326.34999999999997 251.89999999999998 M 331.725 248.77499999999998 L 331.725 242.52499999999998 L 326.34999999999997 239.39999999999998 L 320.97499999999997 242.52499999999998 L 320.97499999999997 248.77499999999998 L Z fill +newpath 350.95 251.89999999999998 M 356.325 248.77499999999998 L 356.325 242.52499999999998 L 350.95 239.39999999999998 L 345.575 242.52499999999998 L 345.575 248.77499999999998 L Z fill +newpath 375.55 251.89999999999998 M 380.925 248.77499999999998 L 380.925 242.52499999999998 L 375.55 239.39999999999998 L 370.17499999999995 242.52499999999998 L 370.17499999999995 248.77499999999998 L Z fill +newpath 387.85 251.89999999999998 M 393.225 248.77499999999998 L 393.225 242.52499999999998 L 387.85 239.39999999999998 L 382.475 242.52499999999998 L 382.475 248.77499999999998 L Z fill +newpath 49.6 262.57499999999993 M 54.975 259.44999999999993 L 54.975 253.19999999999996 L 49.6 250.07499999999996 L 44.224999999999994 253.19999999999996 L 44.224999999999994 259.44999999999993 L Z fill +newpath 74.2 262.57499999999993 M 79.57499999999999 259.44999999999993 L 79.57499999999999 253.19999999999996 L 74.2 250.07499999999996 L 68.825 253.19999999999996 L 68.825 259.44999999999993 L Z fill +newpath 98.80000000000001 262.57499999999993 M 104.17500000000001 259.44999999999993 L 104.17500000000001 253.19999999999996 L 98.80000000000001 250.07499999999996 L 93.42500000000001 253.19999999999996 L 93.42500000000001 259.44999999999993 L Z fill +newpath 123.4 262.57499999999993 M 128.77499999999998 259.44999999999993 L 128.77499999999998 253.19999999999996 L 123.4 250.07499999999996 L 118.025 253.19999999999996 L 118.025 259.44999999999993 L Z fill +newpath 148.0 262.57499999999993 M 153.375 259.44999999999993 L 153.375 253.19999999999996 L 148.0 250.07499999999996 L 142.625 253.19999999999996 L 142.625 259.44999999999993 L Z fill +newpath 246.39999999999998 262.57499999999993 M 251.77499999999998 259.44999999999993 L 251.77499999999998 253.19999999999996 L 246.39999999999998 250.07499999999996 L 241.02499999999995 253.19999999999996 L 241.02499999999995 259.44999999999993 L Z fill +newpath 258.7 262.57499999999993 M 264.075 259.44999999999993 L 264.075 253.19999999999996 L 258.7 250.07499999999996 L 253.32499999999996 253.19999999999996 L 253.32499999999996 259.44999999999993 L Z fill +newpath 271.0 262.57499999999993 M 276.375 259.44999999999993 L 276.375 253.19999999999996 L 271.0 250.07499999999996 L 265.625 253.19999999999996 L 265.625 259.44999999999993 L Z fill +newpath 283.29999999999995 262.57499999999993 M 288.675 259.44999999999993 L 288.675 253.19999999999996 L 283.29999999999995 250.07499999999996 L 277.92499999999995 253.19999999999996 L 277.92499999999995 259.44999999999993 L Z fill +newpath 295.59999999999997 262.57499999999993 M 300.97499999999997 259.44999999999993 L 300.97499999999997 253.19999999999996 L 295.59999999999997 250.07499999999996 L 290.2249999999999 253.19999999999996 L 290.2249999999999 259.44999999999993 L Z fill +newpath 320.19999999999993 262.57499999999993 M 325.575 259.44999999999993 L 325.575 253.19999999999996 L 320.19999999999993 250.07499999999996 L 314.82499999999993 253.19999999999996 L 314.82499999999993 259.44999999999993 L Z fill +newpath 344.79999999999995 262.57499999999993 M 350.17499999999995 259.44999999999993 L 350.17499999999995 253.19999999999996 L 344.79999999999995 250.07499999999996 L 339.42499999999995 253.19999999999996 L 339.42499999999995 259.44999999999993 L Z fill +newpath 369.40000000000003 262.57499999999993 M 374.7750000000001 259.44999999999993 L 374.7750000000001 253.19999999999996 L 369.40000000000003 250.07499999999996 L 364.02500000000003 253.19999999999996 L 364.02500000000003 259.44999999999993 L Z fill +newpath 129.55 273.25 M 134.925 270.125 L 134.925 263.875 L 129.55 260.75 L 124.17500000000001 263.875 L 124.17500000000001 270.125 L Z fill +newpath 141.85000000000002 273.25 M 147.225 270.125 L 147.225 263.875 L 141.85000000000002 260.75 L 136.47500000000002 263.875 L 136.47500000000002 270.125 L Z fill +newpath 154.15 273.25 M 159.525 270.125 L 159.525 263.875 L 154.15 260.75 L 148.775 263.875 L 148.775 270.125 L Z fill +newpath 178.75 273.25 M 184.125 270.125 L 184.125 263.875 L 178.75 260.75 L 173.375 263.875 L 173.375 270.125 L Z fill +newpath 227.95 273.25 M 233.325 270.125 L 233.325 263.875 L 227.95 260.75 L 222.57499999999996 263.875 L 222.57499999999996 270.125 L Z fill +newpath 240.25 273.25 M 245.625 270.125 L 245.625 263.875 L 240.25 260.75 L 234.87499999999997 263.875 L 234.87499999999997 270.125 L Z fill +newpath 252.54999999999998 273.25 M 257.925 270.125 L 257.925 263.875 L 252.54999999999998 260.75 L 247.17499999999998 263.875 L 247.17499999999998 270.125 L Z fill +newpath 277.15 273.25 M 282.52500000000003 270.125 L 282.52500000000003 263.875 L 277.15 260.75 L 271.775 263.875 L 271.775 270.125 L Z fill +newpath 375.55 273.25 M 380.925 270.125 L 380.925 263.875 L 375.55 260.75 L 370.17499999999995 263.875 L 370.17499999999995 270.125 L Z fill +newpath 387.85 273.25 M 393.225 270.125 L 393.225 263.875 L 387.85 260.75 L 382.475 263.875 L 382.475 270.125 L Z fill +newpath 37.3 283.92499999999995 M 42.675 280.79999999999995 L 42.675 274.54999999999995 L 37.3 271.42499999999995 L 31.925 274.54999999999995 L 31.925 280.79999999999995 L Z fill +newpath 61.900000000000006 283.92499999999995 M 67.275 280.79999999999995 L 67.275 274.54999999999995 L 61.900000000000006 271.42499999999995 L 56.525000000000006 274.54999999999995 L 56.525000000000006 280.79999999999995 L Z fill +newpath 86.5 283.92499999999995 M 91.875 280.79999999999995 L 91.875 274.54999999999995 L 86.5 271.42499999999995 L 81.125 274.54999999999995 L 81.125 280.79999999999995 L Z fill +newpath 111.1 283.92499999999995 M 116.475 280.79999999999995 L 116.475 274.54999999999995 L 111.1 271.42499999999995 L 105.725 274.54999999999995 L 105.725 280.79999999999995 L Z fill +newpath 135.7 283.92499999999995 M 141.075 280.79999999999995 L 141.075 274.54999999999995 L 135.7 271.42499999999995 L 130.325 274.54999999999995 L 130.325 280.79999999999995 L Z fill +newpath 160.3 283.92499999999995 M 165.675 280.79999999999995 L 165.675 274.54999999999995 L 160.3 271.42499999999995 L 154.925 274.54999999999995 L 154.925 280.79999999999995 L Z fill +newpath 172.6 283.92499999999995 M 177.975 280.79999999999995 L 177.975 274.54999999999995 L 172.6 271.42499999999995 L 167.225 274.54999999999995 L 167.225 280.79999999999995 L Z fill +newpath 184.9 283.92499999999995 M 190.275 280.79999999999995 L 190.275 274.54999999999995 L 184.9 271.42499999999995 L 179.525 274.54999999999995 L 179.525 280.79999999999995 L Z fill +newpath 197.2 283.92499999999995 M 202.575 280.79999999999995 L 202.575 274.54999999999995 L 197.2 271.42499999999995 L 191.825 274.54999999999995 L 191.825 280.79999999999995 L Z fill +newpath 209.49999999999994 283.92499999999995 M 214.87499999999997 280.79999999999995 L 214.87499999999997 274.54999999999995 L 209.49999999999994 271.42499999999995 L 204.12499999999994 274.54999999999995 L 204.12499999999994 280.79999999999995 L Z fill +newpath 221.79999999999995 283.92499999999995 M 227.17499999999998 280.79999999999995 L 227.17499999999998 274.54999999999995 L 221.79999999999995 271.42499999999995 L 216.42499999999995 274.54999999999995 L 216.42499999999995 280.79999999999995 L Z fill +newpath 246.39999999999998 283.92499999999995 M 251.77499999999998 280.79999999999995 L 251.77499999999998 274.54999999999995 L 246.39999999999998 271.42499999999995 L 241.02499999999995 274.54999999999995 L 241.02499999999995 280.79999999999995 L Z fill +newpath 258.7 283.92499999999995 M 264.075 280.79999999999995 L 264.075 274.54999999999995 L 258.7 271.42499999999995 L 253.32499999999996 274.54999999999995 L 253.32499999999996 280.79999999999995 L Z fill +newpath 307.9 283.92499999999995 M 313.275 280.79999999999995 L 313.275 274.54999999999995 L 307.9 271.42499999999995 L 302.5249999999999 274.54999999999995 L 302.5249999999999 280.79999999999995 L Z fill +newpath 332.49999999999994 283.92499999999995 M 337.875 280.79999999999995 L 337.875 274.54999999999995 L 332.49999999999994 271.42499999999995 L 327.12499999999994 274.54999999999995 L 327.12499999999994 280.79999999999995 L Z fill +newpath 357.1 283.92499999999995 M 362.475 280.79999999999995 L 362.475 274.54999999999995 L 357.1 271.42499999999995 L 351.725 274.54999999999995 L 351.725 280.79999999999995 L Z fill +newpath 381.70000000000005 283.92499999999995 M 387.07500000000005 280.79999999999995 L 387.07500000000005 274.54999999999995 L 381.70000000000005 271.42499999999995 L 376.325 274.54999999999995 L 376.325 280.79999999999995 L Z fill +newpath 43.45 294.59999999999997 M 48.825 291.47499999999997 L 48.825 285.22499999999997 L 43.45 282.09999999999997 L 38.075 285.22499999999997 L 38.075 291.47499999999997 L Z fill +newpath 68.05 294.59999999999997 M 73.425 291.47499999999997 L 73.425 285.22499999999997 L 68.05 282.09999999999997 L 62.675 285.22499999999997 L 62.675 291.47499999999997 L Z fill +newpath 92.65 294.59999999999997 M 98.025 291.47499999999997 L 98.025 285.22499999999997 L 92.65 282.09999999999997 L 87.275 285.22499999999997 L 87.275 291.47499999999997 L Z fill +newpath 117.25 294.59999999999997 M 122.625 291.47499999999997 L 122.625 285.22499999999997 L 117.25 282.09999999999997 L 111.875 285.22499999999997 L 111.875 291.47499999999997 L Z fill +newpath 141.85000000000002 294.59999999999997 M 147.225 291.47499999999997 L 147.225 285.22499999999997 L 141.85000000000002 282.09999999999997 L 136.47500000000002 285.22499999999997 L 136.47500000000002 291.47499999999997 L Z fill +newpath 166.45 294.59999999999997 M 171.825 291.47499999999997 L 171.825 285.22499999999997 L 166.45 282.09999999999997 L 161.075 285.22499999999997 L 161.075 291.47499999999997 L Z fill +newpath 191.05 294.59999999999997 M 196.425 291.47499999999997 L 196.425 285.22499999999997 L 191.05 282.09999999999997 L 185.67499999999998 285.22499999999997 L 185.67499999999998 291.47499999999997 L Z fill +newpath 215.64999999999998 294.59999999999997 M 221.02499999999998 291.47499999999997 L 221.02499999999998 285.22499999999997 L 215.64999999999998 282.09999999999997 L 210.27499999999998 285.22499999999997 L 210.27499999999998 291.47499999999997 L Z fill +newpath 240.25 294.59999999999997 M 245.625 291.47499999999997 L 245.625 285.22499999999997 L 240.25 282.09999999999997 L 234.87499999999997 285.22499999999997 L 234.87499999999997 291.47499999999997 L Z fill +newpath 264.85 294.59999999999997 M 270.225 291.47499999999997 L 270.225 285.22499999999997 L 264.85 282.09999999999997 L 259.47499999999997 285.22499999999997 L 259.47499999999997 291.47499999999997 L Z fill +newpath 277.15 294.59999999999997 M 282.52500000000003 291.47499999999997 L 282.52500000000003 285.22499999999997 L 277.15 282.09999999999997 L 271.775 285.22499999999997 L 271.775 291.47499999999997 L Z fill +newpath 289.45 294.59999999999997 M 294.825 291.47499999999997 L 294.825 285.22499999999997 L 289.45 282.09999999999997 L 284.07499999999993 285.22499999999997 L 284.07499999999993 291.47499999999997 L Z fill +newpath 301.75 294.59999999999997 M 307.125 291.47499999999997 L 307.125 285.22499999999997 L 301.75 282.09999999999997 L 296.37499999999994 285.22499999999997 L 296.37499999999994 291.47499999999997 L Z fill +newpath 314.04999999999995 294.59999999999997 M 319.425 291.47499999999997 L 319.425 285.22499999999997 L 314.04999999999995 282.09999999999997 L 308.67499999999995 285.22499999999997 L 308.67499999999995 291.47499999999997 L Z fill +newpath 338.65 294.59999999999997 M 344.025 291.47499999999997 L 344.025 285.22499999999997 L 338.65 282.09999999999997 L 333.275 285.22499999999997 L 333.275 291.47499999999997 L Z fill +newpath 363.25 294.59999999999997 M 368.62500000000006 291.47499999999997 L 368.62500000000006 285.22499999999997 L 363.25 282.09999999999997 L 357.875 285.22499999999997 L 357.875 291.47499999999997 L Z fill +newpath 375.55 294.59999999999997 M 380.925 291.47499999999997 L 380.925 285.22499999999997 L 375.55 282.09999999999997 L 370.17499999999995 285.22499999999997 L 370.17499999999995 291.47499999999997 L Z fill +newpath 387.85 294.59999999999997 M 393.225 291.47499999999997 L 393.225 285.22499999999997 L 387.85 282.09999999999997 L 382.475 285.22499999999997 L 382.475 291.47499999999997 L Z fill +newpath 283.29999999999995 305.275 M 288.675 302.15 L 288.675 295.9 L 283.29999999999995 292.775 L 277.92499999999995 295.9 L 277.92499999999995 302.15 L Z fill +newpath 295.59999999999997 305.275 M 300.97499999999997 302.15 L 300.97499999999997 295.9 L 295.59999999999997 292.775 L 290.2249999999999 295.9 L 290.2249999999999 302.15 L Z fill +newpath 307.9 305.275 M 313.275 302.15 L 313.275 295.9 L 307.9 292.775 L 302.5249999999999 295.9 L 302.5249999999999 302.15 L Z fill +newpath 320.19999999999993 305.275 M 325.575 302.15 L 325.575 295.9 L 320.19999999999993 292.775 L 314.82499999999993 295.9 L 314.82499999999993 302.15 L Z fill +newpath 344.79999999999995 305.275 M 350.17499999999995 302.15 L 350.17499999999995 295.9 L 344.79999999999995 292.775 L 339.42499999999995 295.9 L 339.42499999999995 302.15 L Z fill +newpath 369.40000000000003 305.275 M 374.7750000000001 302.15 L 374.7750000000001 295.9 L 369.40000000000003 292.775 L 364.02500000000003 295.9 L 364.02500000000003 302.15 L Z fill +newpath 381.70000000000005 305.275 M 387.07500000000005 302.15 L 387.07500000000005 295.9 L 381.70000000000005 292.775 L 376.325 295.9 L 376.325 302.15 L Z fill +newpath 31.15 315.94999999999993 M 36.525 312.82499999999993 L 36.525 306.57499999999993 L 31.15 303.44999999999993 L 25.775 306.57499999999993 L 25.775 312.82499999999993 L Z fill +newpath 55.75 315.94999999999993 M 61.125 312.82499999999993 L 61.125 306.57499999999993 L 55.75 303.44999999999993 L 50.375 306.57499999999993 L 50.375 312.82499999999993 L Z fill +newpath 80.35 315.94999999999993 M 85.725 312.82499999999993 L 85.725 306.57499999999993 L 80.35 303.44999999999993 L 74.97500000000001 306.57499999999993 L 74.97500000000001 312.82499999999993 L Z fill +newpath 104.95 315.94999999999993 M 110.325 312.82499999999993 L 110.325 306.57499999999993 L 104.95 303.44999999999993 L 99.575 306.57499999999993 L 99.575 312.82499999999993 L Z fill +newpath 129.55 315.94999999999993 M 134.925 312.82499999999993 L 134.925 306.57499999999993 L 129.55 303.44999999999993 L 124.17500000000001 306.57499999999993 L 124.17500000000001 312.82499999999993 L Z fill +newpath 154.15 315.94999999999993 M 159.525 312.82499999999993 L 159.525 306.57499999999993 L 154.15 303.44999999999993 L 148.775 306.57499999999993 L 148.775 312.82499999999993 L Z fill +newpath 178.75 315.94999999999993 M 184.125 312.82499999999993 L 184.125 306.57499999999993 L 178.75 303.44999999999993 L 173.375 306.57499999999993 L 173.375 312.82499999999993 L Z fill +newpath 203.34999999999997 315.94999999999993 M 208.725 312.82499999999993 L 208.725 306.57499999999993 L 203.34999999999997 303.44999999999993 L 197.97499999999997 306.57499999999993 L 197.97499999999997 312.82499999999993 L Z fill +newpath 227.95 315.94999999999993 M 233.325 312.82499999999993 L 233.325 306.57499999999993 L 227.95 303.44999999999993 L 222.57499999999996 306.57499999999993 L 222.57499999999996 312.82499999999993 L Z fill +newpath 252.54999999999998 315.94999999999993 M 257.925 312.82499999999993 L 257.925 306.57499999999993 L 252.54999999999998 303.44999999999993 L 247.17499999999998 306.57499999999993 L 247.17499999999998 312.82499999999993 L Z fill +newpath 375.55 315.94999999999993 M 380.925 312.82499999999993 L 380.925 306.57499999999993 L 375.55 303.44999999999993 L 370.17499999999995 306.57499999999993 L 370.17499999999995 312.82499999999993 L Z fill +newpath 37.3 326.625 M 42.675 323.5 L 42.675 317.25 L 37.3 314.125 L 31.925 317.25 L 31.925 323.5 L Z fill +newpath 49.6 326.625 M 54.975 323.5 L 54.975 317.25 L 49.6 314.125 L 44.224999999999994 317.25 L 44.224999999999994 323.5 L Z fill +newpath 61.900000000000006 326.625 M 67.275 323.5 L 67.275 317.25 L 61.900000000000006 314.125 L 56.525000000000006 317.25 L 56.525000000000006 323.5 L Z fill +newpath 74.2 326.625 M 79.57499999999999 323.5 L 79.57499999999999 317.25 L 74.2 314.125 L 68.825 317.25 L 68.825 323.5 L Z fill +newpath 86.5 326.625 M 91.875 323.5 L 91.875 317.25 L 86.5 314.125 L 81.125 317.25 L 81.125 323.5 L Z fill +newpath 98.80000000000001 326.625 M 104.17500000000001 323.5 L 104.17500000000001 317.25 L 98.80000000000001 314.125 L 93.42500000000001 317.25 L 93.42500000000001 323.5 L Z fill +newpath 111.1 326.625 M 116.475 323.5 L 116.475 317.25 L 111.1 314.125 L 105.725 317.25 L 105.725 323.5 L Z fill +newpath 123.4 326.625 M 128.77499999999998 323.5 L 128.77499999999998 317.25 L 123.4 314.125 L 118.025 317.25 L 118.025 323.5 L Z fill +newpath 184.9 326.625 M 190.275 323.5 L 190.275 317.25 L 184.9 314.125 L 179.525 317.25 L 179.525 323.5 L Z fill +newpath 197.2 326.625 M 202.575 323.5 L 202.575 317.25 L 197.2 314.125 L 191.825 317.25 L 191.825 323.5 L Z fill +newpath 209.49999999999994 326.625 M 214.87499999999997 323.5 L 214.87499999999997 317.25 L 209.49999999999994 314.125 L 204.12499999999994 317.25 L 204.12499999999994 323.5 L Z fill +newpath 221.79999999999995 326.625 M 227.17499999999998 323.5 L 227.17499999999998 317.25 L 221.79999999999995 314.125 L 216.42499999999995 317.25 L 216.42499999999995 323.5 L Z fill +newpath 295.59999999999997 326.625 M 300.97499999999997 323.5 L 300.97499999999997 317.25 L 295.59999999999997 314.125 L 290.2249999999999 317.25 L 290.2249999999999 323.5 L Z fill +newpath 320.19999999999993 326.625 M 325.575 323.5 L 325.575 317.25 L 320.19999999999993 314.125 L 314.82499999999993 317.25 L 314.82499999999993 323.5 L Z fill +newpath 43.45 337.29999999999995 M 48.825 334.17499999999995 L 48.825 327.92499999999995 L 43.45 324.79999999999995 L 38.075 327.92499999999995 L 38.075 334.17499999999995 L Z fill +newpath 68.05 337.29999999999995 M 73.425 334.17499999999995 L 73.425 327.92499999999995 L 68.05 324.79999999999995 L 62.675 327.92499999999995 L 62.675 334.17499999999995 L Z fill +newpath 80.35 337.29999999999995 M 85.725 334.17499999999995 L 85.725 327.92499999999995 L 80.35 324.79999999999995 L 74.97500000000001 327.92499999999995 L 74.97500000000001 334.17499999999995 L Z fill +newpath 104.95 337.29999999999995 M 110.325 334.17499999999995 L 110.325 327.92499999999995 L 104.95 324.79999999999995 L 99.575 327.92499999999995 L 99.575 334.17499999999995 L Z fill +newpath 129.55 337.29999999999995 M 134.925 334.17499999999995 L 134.925 327.92499999999995 L 129.55 324.79999999999995 L 124.17500000000001 327.92499999999995 L 124.17500000000001 334.17499999999995 L Z fill +newpath 141.85000000000002 337.29999999999995 M 147.225 334.17499999999995 L 147.225 327.92499999999995 L 141.85000000000002 324.79999999999995 L 136.47500000000002 327.92499999999995 L 136.47500000000002 334.17499999999995 L Z fill +newpath 154.15 337.29999999999995 M 159.525 334.17499999999995 L 159.525 327.92499999999995 L 154.15 324.79999999999995 L 148.775 327.92499999999995 L 148.775 334.17499999999995 L Z fill +newpath 166.45 337.29999999999995 M 171.825 334.17499999999995 L 171.825 327.92499999999995 L 166.45 324.79999999999995 L 161.075 327.92499999999995 L 161.075 334.17499999999995 L Z fill +newpath 227.95 337.29999999999995 M 233.325 334.17499999999995 L 233.325 327.92499999999995 L 227.95 324.79999999999995 L 222.57499999999996 327.92499999999995 L 222.57499999999996 334.17499999999995 L Z fill +newpath 240.25 337.29999999999995 M 245.625 334.17499999999995 L 245.625 327.92499999999995 L 240.25 324.79999999999995 L 234.87499999999997 327.92499999999995 L 234.87499999999997 334.17499999999995 L Z fill +newpath 252.54999999999998 337.29999999999995 M 257.925 334.17499999999995 L 257.925 327.92499999999995 L 252.54999999999998 324.79999999999995 L 247.17499999999998 327.92499999999995 L 247.17499999999998 334.17499999999995 L Z fill +newpath 264.85 337.29999999999995 M 270.225 334.17499999999995 L 270.225 327.92499999999995 L 264.85 324.79999999999995 L 259.47499999999997 327.92499999999995 L 259.47499999999997 334.17499999999995 L Z fill +newpath 289.45 337.29999999999995 M 294.825 334.17499999999995 L 294.825 327.92499999999995 L 289.45 324.79999999999995 L 284.07499999999993 327.92499999999995 L 284.07499999999993 334.17499999999995 L Z fill +newpath 314.04999999999995 337.29999999999995 M 319.425 334.17499999999995 L 319.425 327.92499999999995 L 314.04999999999995 324.79999999999995 L 308.67499999999995 327.92499999999995 L 308.67499999999995 334.17499999999995 L Z fill +newpath 338.65 337.29999999999995 M 344.025 334.17499999999995 L 344.025 327.92499999999995 L 338.65 324.79999999999995 L 333.275 327.92499999999995 L 333.275 334.17499999999995 L Z fill +newpath 363.25 337.29999999999995 M 368.62500000000006 334.17499999999995 L 368.62500000000006 327.92499999999995 L 363.25 324.79999999999995 L 357.875 327.92499999999995 L 357.875 334.17499999999995 L Z fill +newpath 37.3 347.975 M 42.675 344.84999999999997 L 42.675 338.59999999999997 L 37.3 335.47499999999997 L 31.925 338.59999999999997 L 31.925 344.84999999999997 L Z fill +newpath 61.900000000000006 347.975 M 67.275 344.84999999999997 L 67.275 338.59999999999997 L 61.900000000000006 335.47499999999997 L 56.525000000000006 338.59999999999997 L 56.525000000000006 344.84999999999997 L Z fill +newpath 86.5 347.975 M 91.875 344.84999999999997 L 91.875 338.59999999999997 L 86.5 335.47499999999997 L 81.125 338.59999999999997 L 81.125 344.84999999999997 L Z fill +newpath 111.1 347.975 M 116.475 344.84999999999997 L 116.475 338.59999999999997 L 111.1 335.47499999999997 L 105.725 338.59999999999997 L 105.725 344.84999999999997 L Z fill +newpath 197.2 347.975 M 202.575 344.84999999999997 L 202.575 338.59999999999997 L 197.2 335.47499999999997 L 191.825 338.59999999999997 L 191.825 344.84999999999997 L Z fill +newpath 221.79999999999995 347.975 M 227.17499999999998 344.84999999999997 L 227.17499999999998 338.59999999999997 L 221.79999999999995 335.47499999999997 L 216.42499999999995 338.59999999999997 L 216.42499999999995 344.84999999999997 L Z fill +newpath 246.39999999999998 347.975 M 251.77499999999998 344.84999999999997 L 251.77499999999998 338.59999999999997 L 246.39999999999998 335.47499999999997 L 241.02499999999995 338.59999999999997 L 241.02499999999995 344.84999999999997 L Z fill +newpath 271.0 347.975 M 276.375 344.84999999999997 L 276.375 338.59999999999997 L 271.0 335.47499999999997 L 265.625 338.59999999999997 L 265.625 344.84999999999997 L Z fill +newpath 283.29999999999995 347.975 M 288.675 344.84999999999997 L 288.675 338.59999999999997 L 283.29999999999995 335.47499999999997 L 277.92499999999995 338.59999999999997 L 277.92499999999995 344.84999999999997 L Z fill +newpath 295.59999999999997 347.975 M 300.97499999999997 344.84999999999997 L 300.97499999999997 338.59999999999997 L 295.59999999999997 335.47499999999997 L 290.2249999999999 338.59999999999997 L 290.2249999999999 344.84999999999997 L Z fill +newpath 307.9 347.975 M 313.275 344.84999999999997 L 313.275 338.59999999999997 L 307.9 335.47499999999997 L 302.5249999999999 338.59999999999997 L 302.5249999999999 344.84999999999997 L Z fill +newpath 320.19999999999993 347.975 M 325.575 344.84999999999997 L 325.575 338.59999999999997 L 320.19999999999993 335.47499999999997 L 314.82499999999993 338.59999999999997 L 314.82499999999993 344.84999999999997 L Z fill +newpath 332.49999999999994 347.975 M 337.875 344.84999999999997 L 337.875 338.59999999999997 L 332.49999999999994 335.47499999999997 L 327.12499999999994 338.59999999999997 L 327.12499999999994 344.84999999999997 L Z fill +newpath 357.1 347.975 M 362.475 344.84999999999997 L 362.475 338.59999999999997 L 357.1 335.47499999999997 L 351.725 338.59999999999997 L 351.725 344.84999999999997 L Z fill +newpath 381.70000000000005 347.975 M 387.07500000000005 344.84999999999997 L 387.07500000000005 338.59999999999997 L 381.70000000000005 335.47499999999997 L 376.325 338.59999999999997 L 376.325 344.84999999999997 L Z fill +newpath 31.15 358.65000000000003 M 36.525 355.52500000000003 L 36.525 349.27500000000003 L 31.15 346.15000000000003 L 25.775 349.27500000000003 L 25.775 355.52500000000003 L Z fill +newpath 43.45 358.65000000000003 M 48.825 355.52500000000003 L 48.825 349.27500000000003 L 43.45 346.15000000000003 L 38.075 349.27500000000003 L 38.075 355.52500000000003 L Z fill +newpath 55.75 358.65000000000003 M 61.125 355.52500000000003 L 61.125 349.27500000000003 L 55.75 346.15000000000003 L 50.375 349.27500000000003 L 50.375 355.52500000000003 L Z fill +newpath 68.05 358.65000000000003 M 73.425 355.52500000000003 L 73.425 349.27500000000003 L 68.05 346.15000000000003 L 62.675 349.27500000000003 L 62.675 355.52500000000003 L Z fill +newpath 92.65 358.65000000000003 M 98.025 355.52500000000003 L 98.025 349.27500000000003 L 92.65 346.15000000000003 L 87.275 349.27500000000003 L 87.275 355.52500000000003 L Z fill +newpath 117.25 358.65000000000003 M 122.625 355.52500000000003 L 122.625 349.27500000000003 L 117.25 346.15000000000003 L 111.875 349.27500000000003 L 111.875 355.52500000000003 L Z fill +newpath 129.55 358.65000000000003 M 134.925 355.52500000000003 L 134.925 349.27500000000003 L 129.55 346.15000000000003 L 124.17500000000001 349.27500000000003 L 124.17500000000001 355.52500000000003 L Z fill +newpath 154.15 358.65000000000003 M 159.525 355.52500000000003 L 159.525 349.27500000000003 L 154.15 346.15000000000003 L 148.775 349.27500000000003 L 148.775 355.52500000000003 L Z fill +newpath 227.95 358.65000000000003 M 233.325 355.52500000000003 L 233.325 349.27500000000003 L 227.95 346.15000000000003 L 222.57499999999996 349.27500000000003 L 222.57499999999996 355.52500000000003 L Z fill +newpath 240.25 358.65000000000003 M 245.625 355.52500000000003 L 245.625 349.27500000000003 L 240.25 346.15000000000003 L 234.87499999999997 349.27500000000003 L 234.87499999999997 355.52500000000003 L Z fill +newpath 252.54999999999998 358.65000000000003 M 257.925 355.52500000000003 L 257.925 349.27500000000003 L 252.54999999999998 346.15000000000003 L 247.17499999999998 349.27500000000003 L 247.17499999999998 355.52500000000003 L Z fill +newpath 264.85 358.65000000000003 M 270.225 355.52500000000003 L 270.225 349.27500000000003 L 264.85 346.15000000000003 L 259.47499999999997 349.27500000000003 L 259.47499999999997 355.52500000000003 L Z fill +newpath 289.45 358.65000000000003 M 294.825 355.52500000000003 L 294.825 349.27500000000003 L 289.45 346.15000000000003 L 284.07499999999993 349.27500000000003 L 284.07499999999993 355.52500000000003 L Z fill +newpath 314.04999999999995 358.65000000000003 M 319.425 355.52500000000003 L 319.425 349.27500000000003 L 314.04999999999995 346.15000000000003 L 308.67499999999995 349.27500000000003 L 308.67499999999995 355.52500000000003 L Z fill +newpath 326.34999999999997 358.65000000000003 M 331.725 355.52500000000003 L 331.725 349.27500000000003 L 326.34999999999997 346.15000000000003 L 320.97499999999997 349.27500000000003 L 320.97499999999997 355.52500000000003 L Z fill +newpath 350.95 358.65000000000003 M 356.325 355.52500000000003 L 356.325 349.27500000000003 L 350.95 346.15000000000003 L 345.575 349.27500000000003 L 345.575 355.52500000000003 L Z fill +newpath 375.55 358.65000000000003 M 380.925 355.52500000000003 L 380.925 349.27500000000003 L 375.55 346.15000000000003 L 370.17499999999995 349.27500000000003 L 370.17499999999995 355.52500000000003 L Z fill +newpath 49.6 369.325 M 54.975 366.2 L 54.975 359.95 L 49.6 356.825 L 44.224999999999994 359.95 L 44.224999999999994 366.2 L Z fill +newpath 74.2 369.325 M 79.57499999999999 366.2 L 79.57499999999999 359.95 L 74.2 356.825 L 68.825 359.95 L 68.825 366.2 L Z fill +newpath 86.5 369.325 M 91.875 366.2 L 91.875 359.95 L 86.5 356.825 L 81.125 359.95 L 81.125 366.2 L Z fill +newpath 111.1 369.325 M 116.475 366.2 L 116.475 359.95 L 111.1 356.825 L 105.725 359.95 L 105.725 366.2 L Z fill +newpath 135.7 369.325 M 141.075 366.2 L 141.075 359.95 L 135.7 356.825 L 130.325 359.95 L 130.325 366.2 L Z fill +newpath 148.0 369.325 M 153.375 366.2 L 153.375 359.95 L 148.0 356.825 L 142.625 359.95 L 142.625 366.2 L Z fill +newpath 160.3 369.325 M 165.675 366.2 L 165.675 359.95 L 160.3 356.825 L 154.925 359.95 L 154.925 366.2 L Z fill +newpath 172.6 369.325 M 177.975 366.2 L 177.975 359.95 L 172.6 356.825 L 167.225 359.95 L 167.225 366.2 L Z fill +newpath 197.2 369.325 M 202.575 366.2 L 202.575 359.95 L 197.2 356.825 L 191.825 359.95 L 191.825 366.2 L Z fill +newpath 221.79999999999995 369.325 M 227.17499999999998 366.2 L 227.17499999999998 359.95 L 221.79999999999995 356.825 L 216.42499999999995 359.95 L 216.42499999999995 366.2 L Z fill +newpath 234.09999999999997 369.325 M 239.47499999999997 366.2 L 239.47499999999997 359.95 L 234.09999999999997 356.825 L 228.72499999999997 359.95 L 228.72499999999997 366.2 L Z fill +newpath 258.7 369.325 M 264.075 366.2 L 264.075 359.95 L 258.7 356.825 L 253.32499999999996 359.95 L 253.32499999999996 366.2 L Z fill +newpath 283.29999999999995 369.325 M 288.675 366.2 L 288.675 359.95 L 283.29999999999995 356.825 L 277.92499999999995 359.95 L 277.92499999999995 366.2 L Z fill +newpath 307.9 369.325 M 313.275 366.2 L 313.275 359.95 L 307.9 356.825 L 302.5249999999999 359.95 L 302.5249999999999 366.2 L Z fill +newpath 332.49999999999994 369.325 M 337.875 366.2 L 337.875 359.95 L 332.49999999999994 356.825 L 327.12499999999994 359.95 L 327.12499999999994 366.2 L Z fill +newpath 344.79999999999995 369.325 M 350.17499999999995 366.2 L 350.17499999999995 359.95 L 344.79999999999995 356.825 L 339.42499999999995 359.95 L 339.42499999999995 366.2 L Z fill +newpath 357.1 369.325 M 362.475 366.2 L 362.475 359.95 L 357.1 356.825 L 351.725 359.95 L 351.725 366.2 L Z fill +newpath 369.40000000000003 369.325 M 374.7750000000001 366.2 L 374.7750000000001 359.95 L 369.40000000000003 356.825 L 364.02500000000003 359.95 L 364.02500000000003 366.2 L Z fill +newpath 43.45 380.0 M 48.825 376.875 L 48.825 370.625 L 43.45 367.5 L 38.075 370.625 L 38.075 376.875 L Z fill +newpath 68.05 380.0 M 73.425 376.875 L 73.425 370.625 L 68.05 367.5 L 62.675 370.625 L 62.675 376.875 L Z fill +newpath 191.05 380.0 M 196.425 376.875 L 196.425 370.625 L 191.05 367.5 L 185.67499999999998 370.625 L 185.67499999999998 376.875 L Z fill +newpath 215.64999999999998 380.0 M 221.02499999999998 376.875 L 221.02499999999998 370.625 L 215.64999999999998 367.5 L 210.27499999999998 370.625 L 210.27499999999998 376.875 L Z fill +newpath 227.95 380.0 M 233.325 376.875 L 233.325 370.625 L 227.95 367.5 L 222.57499999999996 370.625 L 222.57499999999996 376.875 L Z fill +newpath 252.54999999999998 380.0 M 257.925 376.875 L 257.925 370.625 L 252.54999999999998 367.5 L 247.17499999999998 370.625 L 247.17499999999998 376.875 L Z fill +newpath 277.15 380.0 M 282.52500000000003 376.875 L 282.52500000000003 370.625 L 277.15 367.5 L 271.775 370.625 L 271.775 376.875 L Z fill +newpath 301.75 380.0 M 307.125 376.875 L 307.125 370.625 L 301.75 367.5 L 296.37499999999994 370.625 L 296.37499999999994 376.875 L Z fill +newpath 338.65 380.0 M 344.025 376.875 L 344.025 370.625 L 338.65 367.5 L 333.275 370.625 L 333.275 376.875 L Z fill +newpath 363.25 380.0 M 368.62500000000006 376.875 L 368.62500000000006 370.625 L 363.25 367.5 L 357.875 370.625 L 357.875 376.875 L Z fill +newpath 203.79999999999998 203.0 54.25000000000001 54.25000000000001 360.0 0.0 ellipse Z fill +1.0 1.0 1.0 rgb +newpath 203.79999999999998 203.0 44.849999999999994 44.849999999999994 360.0 0.0 ellipse Z fill +0.0 0.0 0.0 rgb +newpath 203.79999999999998 203.0 35.50000000000001 35.50000000000001 360.0 0.0 ellipse Z fill +1.0 1.0 1.0 rgb +newpath 203.79999999999998 203.0 26.099999999999994 26.099999999999994 360.0 0.0 ellipse Z fill +0.0 0.0 0.0 rgb +newpath 203.79999999999998 203.0 16.55000000000001 16.55000000000001 360.0 0.0 ellipse Z fill +1.0 1.0 1.0 rgb +newpath 203.79999999999998 203.00000000000003 7.149999999999999 7.149999999999999 360.0 0.0 ellipse Z fill +0.0 0.0 0.0 rgb +grestore +%%EOF \ No newline at end of file diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/output/maxicode-basic.svg b/barcode/src/test/resources/org/xbib/graphics/barcode/output/maxicode-basic.svg old mode 100755 new mode 100644 index 40be49c..0963a3e --- a/barcode/src/test/resources/org/xbib/graphics/barcode/output/maxicode-basic.svg +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/output/maxicode-basic.svg @@ -1,384 +1,380 @@ - - - - 123456789 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/pdf417/normal-basic-ecc-level-9.error b/barcode/src/test/resources/org/xbib/graphics/barcode/pdf417/normal-basic-ecc-level-9.error index 3aba9d2..b87f9ef 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/pdf417/normal-basic-ecc-level-9.error +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/pdf417/normal-basic-ecc-level-9.error @@ -1 +1 @@ -ECC level must be between 0 and 8. +ECC level must be between 0 and 8 \ No newline at end of file diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/pdf417/truncated-basic-ecc-level-9.error b/barcode/src/test/resources/org/xbib/graphics/barcode/pdf417/truncated-basic-ecc-level-9.error index 3aba9d2..30cb66b 100755 --- a/barcode/src/test/resources/org/xbib/graphics/barcode/pdf417/truncated-basic-ecc-level-9.error +++ b/barcode/src/test/resources/org/xbib/graphics/barcode/pdf417/truncated-basic-ecc-level-9.error @@ -1 +1 @@ -ECC level must be between 0 and 8. +ECC level must be between 0 and 8 diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/uspsonecode/usps-one-code-length-20.png b/barcode/src/test/resources/org/xbib/graphics/barcode/uspsonecode/usps-one-code-length-20.png index 761f00b..fa4d563 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/uspsonecode/usps-one-code-length-20.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/uspsonecode/usps-one-code-length-20.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/uspsonecode/usps-one-code-length-25.png b/barcode/src/test/resources/org/xbib/graphics/barcode/uspsonecode/usps-one-code-length-25.png index 0386710..9ea113d 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/uspsonecode/usps-one-code-length-25.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/uspsonecode/usps-one-code-length-25.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/uspsonecode/usps-one-code-length-29.png b/barcode/src/test/resources/org/xbib/graphics/barcode/uspsonecode/usps-one-code-length-29.png index 49c94f6..d2461fb 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/uspsonecode/usps-one-code-length-29.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/uspsonecode/usps-one-code-length-29.png differ diff --git a/barcode/src/test/resources/org/xbib/graphics/barcode/uspsonecode/usps-one-code-length-31.png b/barcode/src/test/resources/org/xbib/graphics/barcode/uspsonecode/usps-one-code-length-31.png index 19ed30f..a70b44f 100644 Binary files a/barcode/src/test/resources/org/xbib/graphics/barcode/uspsonecode/usps-one-code-length-31.png and b/barcode/src/test/resources/org/xbib/graphics/barcode/uspsonecode/usps-one-code-length-31.png differ diff --git a/chart/build.gradle b/chart/build.gradle index de21c53..bbe7e4b 100644 --- a/chart/build.gradle +++ b/chart/build.gradle @@ -1,3 +1,6 @@ dependencies { implementation project(':io-vector') + implementation project(':io-vector-eps') + implementation project(':io-vector-pdf') + implementation project(':io-vector-svg') } \ No newline at end of file diff --git a/chart/src/main/java/module-info.java b/chart/src/main/java/module-info.java index a02d3cb..3e1e1dc 100644 --- a/chart/src/main/java/module-info.java +++ b/chart/src/main/java/module-info.java @@ -14,5 +14,8 @@ module org.xbib.graphics.chart { exports org.xbib.graphics.chart.theme; exports org.xbib.graphics.chart.xy; requires org.xbib.graphics.io.vector; + 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; } diff --git a/chart/src/test/java/org/xbib/graphics/chart/MatlabTest.java b/chart/src/test/java/org/xbib/graphics/chart/MatlabTest.java index c321f9c..be4c979 100644 --- a/chart/src/test/java/org/xbib/graphics/chart/MatlabTest.java +++ b/chart/src/test/java/org/xbib/graphics/chart/MatlabTest.java @@ -62,6 +62,6 @@ public class MatlabTest { chart.addSeries("price", xData, y2Data); chart.write(Files.newOutputStream(Paths.get("build/matlab.svg")), - VectorGraphicsFormat.SVG ); + VectorGraphicsFormat.SVG); } } diff --git a/gradle/test/junit5.gradle b/gradle/test/junit5.gradle index 188ea0d..fff776d 100644 --- a/gradle/test/junit5.gradle +++ b/gradle/test/junit5.gradle @@ -12,6 +12,8 @@ dependencies { test { useJUnitPlatform() failFast = false + systemProperty 'java.awt.headless', 'true' + //-Dawt.toolkit=sun.awt.HToolkit testLogging { events 'STARTED', 'PASSED', 'FAILED', 'SKIPPED' showStandardStreams = true diff --git a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultFontTextDrawerDefaultFonts.java b/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultFontTextDrawerDefaultFonts.java deleted file mode 100644 index a3cc07b..0000000 --- a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultFontTextDrawerDefaultFonts.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.xbib.graphics.graphics2d.pdfbox; - -import org.apache.pdfbox.pdmodel.font.PDFont; -import org.apache.pdfbox.pdmodel.font.PDType1Font; - -import java.awt.Font; -import java.awt.FontFormatException; -import java.io.IOException; - -/** - * Like {@link DefaultFontTextDrawer}, but tries to use default fonts - * whenever possible. Default fonts are not embedded. You can register - * additional font files. If no font mapping is found, Helvetica is used. - * This will fallback to vectorized text if any kind of RTL text is rendered - * and/or any other not supported feature is used. - */ -public class DefaultFontTextDrawerDefaultFonts extends DefaultFontTextDrawer { - @Override - protected PDFont mapFont(Font font, IFontTextDrawerEnv env) throws IOException, FontFormatException { - PDFont pdFont = mapDefaultFonts(font); - if (pdFont != null) - return pdFont; - - /* - * Do we have a manual registered mapping with a font file? - */ - pdFont = super.mapFont(font, env); - if (pdFont != null) - return pdFont; - return chooseMatchingHelvetica(font); - } - - /** - * Find a PDFont for the given font object, which does not need to be embedded. - * - * @param font font for which to find a suitable default font - * @return null if no default font is found or a default font which does not - * need to be embedded. - */ - public static PDFont mapDefaultFonts(Font font) { - /* - * Map default font names to the matching families. - */ - if (fontNameEqualsAnyOf(font, Font.SANS_SERIF, Font.DIALOG, Font.DIALOG_INPUT, "Arial", "Helvetica")) - return chooseMatchingHelvetica(font); - if (fontNameEqualsAnyOf(font, Font.MONOSPACED, "courier", "courier new")) - return chooseMatchingCourier(font); - if (fontNameEqualsAnyOf(font, Font.SERIF, "Times", "Times New Roman", "Times Roman")) - return chooseMatchingTimes(font); - if (fontNameEqualsAnyOf(font, "Symbol")) - return PDType1Font.SYMBOL; - if (fontNameEqualsAnyOf(font, "ZapfDingbats", "Dingbats")) - return PDType1Font.ZAPF_DINGBATS; - return null; - } - - private static boolean fontNameEqualsAnyOf(Font font, String... names) { - String name = font.getName(); - for (String fontName : names) { - if (fontName.equalsIgnoreCase(name)) - return true; - } - return false; - } - - /** - * Get a PDType1Font.TIMES-variant, which matches the given font - * - * @param font Font to get the styles from - * @return a PDFont Times variant which matches the style in the given Font - * object. - */ - public static PDFont chooseMatchingTimes(Font font) { - if ((font.getStyle() & (Font.ITALIC | Font.BOLD)) == (Font.ITALIC | Font.BOLD)) - return PDType1Font.TIMES_BOLD_ITALIC; - if ((font.getStyle() & Font.ITALIC) == Font.ITALIC) - return PDType1Font.TIMES_ITALIC; - if ((font.getStyle() & Font.BOLD) == Font.BOLD) - return PDType1Font.TIMES_BOLD; - return PDType1Font.TIMES_ROMAN; - } - - /** - * Get a PDType1Font.COURIER-variant, which matches the given font - * - * @param font Font to get the styles from - * @return a PDFont Courier variant which matches the style in the given Font - * object. - */ - public static PDFont chooseMatchingCourier(Font font) { - if ((font.getStyle() & (Font.ITALIC | Font.BOLD)) == (Font.ITALIC | Font.BOLD)) - return PDType1Font.COURIER_BOLD_OBLIQUE; - if ((font.getStyle() & Font.ITALIC) == Font.ITALIC) - return PDType1Font.COURIER_OBLIQUE; - if ((font.getStyle() & Font.BOLD) == Font.BOLD) - return PDType1Font.COURIER_BOLD; - return PDType1Font.COURIER; - } - - /** - * Get a PDType1Font.HELVETICA-variant, which matches the given font - * - * @param font Font to get the styles from - * @return a PDFont Helvetica variant which matches the style in the given Font - * object. - */ - public static PDFont chooseMatchingHelvetica(Font font) { - if ((font.getStyle() & (Font.ITALIC | Font.BOLD)) == (Font.ITALIC | Font.BOLD)) - return PDType1Font.HELVETICA_BOLD_OBLIQUE; - if ((font.getStyle() & Font.ITALIC) == Font.ITALIC) - return PDType1Font.HELVETICA_OBLIQUE; - if ((font.getStyle() & Font.BOLD) == Font.BOLD) - return PDType1Font.HELVETICA_BOLD; - return PDType1Font.HELVETICA; - } -} diff --git a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/FontTest.java b/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/FontTest.java deleted file mode 100644 index b61e6eb..0000000 --- a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/FontTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.xbib.graphics.graphics2d.pdfbox; - -import org.junit.jupiter.api.Test; - -import java.awt.Color; -import java.awt.Font; -import java.awt.FontFormatException; -import java.awt.Graphics2D; -import java.io.IOException; - -public class FontTest extends PdfBoxGraphics2DTestBase { - - @Test - public void testAntonioFont() throws IOException, FontFormatException { - final Font antonioRegular = Font - .createFont(Font.TRUETYPE_FONT, - PdfBoxGraphics2dTest.class.getResourceAsStream("antonio/Antonio-Regular.ttf")) - .deriveFont(15f); - exportGraphic("fonts", "antonio", new GraphicsExporter() { - @Override - public void draw(Graphics2D gfx) throws IOException, FontFormatException { - gfx.setColor(Color.BLACK); - gfx.setFont(antonioRegular); - gfx.drawString("Für älter österlich, Umlauts are not always fun.", 10, 50); - } - }); - } -} diff --git a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/PdfBoxGraphics2DFontTextDrawerDefaultFontsTest.java b/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/PdfBoxGraphics2DFontTextDrawerDefaultFontsTest.java deleted file mode 100644 index d1ab7b9..0000000 --- a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/PdfBoxGraphics2DFontTextDrawerDefaultFontsTest.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.xbib.graphics.graphics2d.pdfbox; - -import org.apache.pdfbox.pdmodel.font.PDType1Font; -import org.junit.jupiter.api.Test; - -import java.awt.Font; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -public class PdfBoxGraphics2DFontTextDrawerDefaultFontsTest { - - @Test - public void testFontStyleMatching() { - Font anyFont = Font.decode("Dialog"); - Font anyFontBold = anyFont.deriveFont(Font.BOLD); - Font anyFontItalic = anyFont.deriveFont(Font.ITALIC); - Font anyFontBoldItalic = anyFont.deriveFont(Font.BOLD | Font.ITALIC); - - assertEquals(PDType1Font.COURIER, DefaultFontTextDrawerDefaultFonts.chooseMatchingCourier(anyFont)); - assertEquals(PDType1Font.COURIER_BOLD, - DefaultFontTextDrawerDefaultFonts.chooseMatchingCourier(anyFontBold)); - assertEquals(PDType1Font.COURIER_OBLIQUE, - DefaultFontTextDrawerDefaultFonts.chooseMatchingCourier(anyFontItalic)); - assertEquals(PDType1Font.COURIER_BOLD_OBLIQUE, - DefaultFontTextDrawerDefaultFonts.chooseMatchingCourier(anyFontBoldItalic)); - - assertEquals(PDType1Font.HELVETICA, - DefaultFontTextDrawerDefaultFonts.chooseMatchingHelvetica(anyFont)); - assertEquals(PDType1Font.HELVETICA_BOLD, - DefaultFontTextDrawerDefaultFonts.chooseMatchingHelvetica(anyFontBold)); - assertEquals(PDType1Font.HELVETICA_OBLIQUE, - DefaultFontTextDrawerDefaultFonts.chooseMatchingHelvetica(anyFontItalic)); - assertEquals(PDType1Font.HELVETICA_BOLD_OBLIQUE, - DefaultFontTextDrawerDefaultFonts.chooseMatchingHelvetica(anyFontBoldItalic)); - - assertEquals(PDType1Font.TIMES_ROMAN, DefaultFontTextDrawerDefaultFonts.chooseMatchingTimes(anyFont)); - assertEquals(PDType1Font.TIMES_BOLD, - DefaultFontTextDrawerDefaultFonts.chooseMatchingTimes(anyFontBold)); - assertEquals(PDType1Font.TIMES_ITALIC, - DefaultFontTextDrawerDefaultFonts.chooseMatchingTimes(anyFontItalic)); - assertEquals(PDType1Font.TIMES_BOLD_ITALIC, - DefaultFontTextDrawerDefaultFonts.chooseMatchingTimes(anyFontBoldItalic)); - } - - @Test - public void testDefaultFontMapping() { - assertEquals(PDType1Font.HELVETICA, - DefaultFontTextDrawerDefaultFonts.mapDefaultFonts(Font.decode(Font.DIALOG))); - assertEquals(PDType1Font.HELVETICA, - DefaultFontTextDrawerDefaultFonts.mapDefaultFonts(Font.decode(Font.DIALOG_INPUT))); - assertEquals(PDType1Font.HELVETICA, - DefaultFontTextDrawerDefaultFonts.mapDefaultFonts(Font.decode("Arial"))); - - assertEquals(PDType1Font.COURIER, - DefaultFontTextDrawerDefaultFonts.mapDefaultFonts(Font.decode(Font.MONOSPACED))); - - assertEquals(PDType1Font.TIMES_ROMAN, - DefaultFontTextDrawerDefaultFonts.mapDefaultFonts(Font.decode(Font.SERIF))); - - assertEquals(PDType1Font.ZAPF_DINGBATS, - DefaultFontTextDrawerDefaultFonts.mapDefaultFonts(Font.decode("Dingbats"))); - - assertEquals(PDType1Font.SYMBOL, - DefaultFontTextDrawerDefaultFonts.mapDefaultFonts(Font.decode("Symbol"))); - - assertNull(DefaultFontTextDrawerDefaultFonts.mapDefaultFonts(Font.decode("Georgia"))); - } - -} \ No newline at end of file diff --git a/graphics2d-pdfbox/build.gradle b/io-pdfbox/build.gradle similarity index 100% rename from graphics2d-pdfbox/build.gradle rename to io-pdfbox/build.gradle diff --git a/graphics2d-pdfbox/src/main/java/module-info.java b/io-pdfbox/src/main/java/module-info.java similarity index 67% rename from graphics2d-pdfbox/src/main/java/module-info.java rename to io-pdfbox/src/main/java/module-info.java index cc83995..55c9899 100644 --- a/graphics2d-pdfbox/src/main/java/module-info.java +++ b/io-pdfbox/src/main/java/module-info.java @@ -1,6 +1,7 @@ module org.xbib.graphics.graphics2d.pdfbox { - exports org.xbib.graphics.graphics2d.pdfbox; + exports org.xbib.graphics.io.pdfbox; requires transitive org.apache.pdfbox; + requires org.apache.fontbox; requires transitive java.desktop; requires java.logging; } \ No newline at end of file diff --git a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/CMYKColor.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/CMYKColor.java similarity index 97% rename from graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/CMYKColor.java rename to io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/CMYKColor.java index e10c76f..7f2b04c 100644 --- a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/CMYKColor.java +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/CMYKColor.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import org.apache.pdfbox.pdmodel.graphics.color.PDColor; import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; diff --git a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/ColorMapper.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/ColorMapper.java similarity index 91% rename from graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/ColorMapper.java rename to io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/ColorMapper.java index 2d32a60..3d4ee0d 100644 --- a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/ColorMapper.java +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/ColorMapper.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.graphics.color.PDColor; diff --git a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultColorMapper.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultColorMapper.java similarity index 94% rename from graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultColorMapper.java rename to io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultColorMapper.java index a3c975c..306a7a0 100644 --- a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultColorMapper.java +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultColorMapper.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.graphics.color.PDColor; @@ -21,7 +21,6 @@ public class DefaultColorMapper implements ColorMapper { float k = DefaultPaintApplier.getPropertyValue(color, "getK"); return new PDColor(new float[]{c, m, y, k}, PDDeviceCMYK.INSTANCE); } - // Our own CMYK Color class if (color instanceof CMYKColor) { return ((CMYKColor) color).toPDColor(); } diff --git a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultDrawControl.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultDrawControl.java similarity index 57% rename from graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultDrawControl.java rename to io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultDrawControl.java index 5460f08..cd68e06 100644 --- a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultDrawControl.java +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultDrawControl.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import java.awt.Shape; @@ -14,20 +14,20 @@ public class DefaultDrawControl implements DrawControl { } @Override - public Shape transformShapeBeforeFill(Shape shape, IDrawControlEnv env) { + public Shape transformShapeBeforeFill(Shape shape, DrawControlEnv env) { return shape; } @Override - public Shape transformShapeBeforeDraw(Shape shape, IDrawControlEnv env) { + public Shape transformShapeBeforeDraw(Shape shape, DrawControlEnv env) { return shape; } @Override - public void afterShapeFill(Shape shape, IDrawControlEnv env) { + public void afterShapeFill(Shape shape, DrawControlEnv env) { } @Override - public void afterShapeDraw(Shape shape, IDrawControlEnv env) { + public void afterShapeDraw(Shape shape, DrawControlEnv env) { } } diff --git a/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultFontMetrics.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultFontMetrics.java new file mode 100644 index 0000000..4ce2586 --- /dev/null +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultFontMetrics.java @@ -0,0 +1,174 @@ +package org.xbib.graphics.io.pdfbox; + +import org.apache.pdfbox.pdmodel.font.PDFont; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.font.FontRenderContext; +import java.awt.font.LineMetrics; +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.text.CharacterIterator; + +@SuppressWarnings("serial") +public class DefaultFontMetrics extends FontMetrics { + + private final FontMetrics defaultMetrics; + + private final PDFont pdFont; + + /** + * Creates a new {@code FontMetrics} object for finding out + * height and width information about the specified {@code Font} + * and specific character glyphs in that {@code Font}. + * + * @param font the {@code Font} + * @see Font + */ + protected DefaultFontMetrics(Font font, FontMetrics defaultMetrics, PDFont pdFont) { + super(font); + this.defaultMetrics = defaultMetrics; + this.pdFont = pdFont; + } + + @Override + public int getDescent() { + return defaultMetrics.getDescent(); + } + + @Override + public int getHeight() { + return defaultMetrics.getHeight(); + } + + @Override + public int getMaxAscent() { + return defaultMetrics.getMaxAscent(); + } + + @Override + public int getMaxDescent() { + return defaultMetrics.getMaxDescent(); + } + + @Override + public boolean hasUniformLineMetrics() { + return defaultMetrics.hasUniformLineMetrics(); + } + + @Override + public LineMetrics getLineMetrics(String str, Graphics context) { + return defaultMetrics.getLineMetrics(str, context); + } + + @Override + public LineMetrics getLineMetrics(String str, int beginIndex, int limit, + Graphics context) { + return defaultMetrics.getLineMetrics(str, beginIndex, limit, context); + } + + @Override + public LineMetrics getLineMetrics(char[] chars, int beginIndex, int limit, + Graphics context) { + return defaultMetrics.getLineMetrics(chars, beginIndex, limit, context); + } + + @Override + public LineMetrics getLineMetrics(CharacterIterator ci, int beginIndex, int limit, + Graphics context) { + return defaultMetrics.getLineMetrics(ci, beginIndex, limit, context); + } + + @Override + public Rectangle2D getStringBounds(String str, Graphics context) { + return defaultMetrics.getStringBounds(str, context); + } + + @Override + public Rectangle2D getStringBounds(String str, int beginIndex, int limit, + Graphics context) { + return defaultMetrics.getStringBounds(str, beginIndex, limit, context); + } + + @Override + public Rectangle2D getStringBounds(char[] chars, int beginIndex, int limit, + Graphics context) { + return defaultMetrics.getStringBounds(chars, beginIndex, limit, context); + } + + @Override + public Rectangle2D getStringBounds(CharacterIterator ci, int beginIndex, int limit, + Graphics context) { + return defaultMetrics.getStringBounds(ci, beginIndex, limit, context); + } + + @Override + public Rectangle2D getMaxCharBounds(Graphics context) { + return defaultMetrics.getMaxCharBounds(context); + } + + @Override + public int getAscent() { + return defaultMetrics.getAscent(); + } + + @Override + public int getMaxAdvance() { + return defaultMetrics.getMaxAdvance(); + } + + @Override + public int getLeading() { + return defaultMetrics.getLeading(); + } + + @Override + public FontRenderContext getFontRenderContext() { + return defaultMetrics.getFontRenderContext(); + } + + @Override + public int charWidth(char ch) { + char[] chars = {ch}; + return charsWidth(chars, 0, chars.length); + } + + @Override + public int charWidth(int codePoint) { + char[] data = Character.toChars(codePoint); + return charsWidth(data, 0, data.length); + } + + @Override + public int charsWidth(char[] data, int off, int len) { + return stringWidth(new String(data, off, len)); + } + + @Override + public int stringWidth(String str) { + try { + return (int) (pdFont.getStringWidth(str) / 1000 * font.getSize()); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (IllegalArgumentException e) { + /* + * We let unknown chars be handled with + */ + return defaultMetrics.stringWidth(str); + } + } + + @Override + public int[] getWidths() { + try { + int[] first256Widths = new int[256]; + for (int i = 0; i < first256Widths.length; i++) { + first256Widths[i] = (int) (pdFont.getWidth(i) / 1000 * font.getSize()); + } + return first256Widths; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultFontTextDrawer.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultFontTextDrawer.java similarity index 69% rename from graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultFontTextDrawer.java rename to io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultFontTextDrawer.java index 838628c..1f78eb2 100644 --- a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultFontTextDrawer.java +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultFontTextDrawer.java @@ -1,7 +1,6 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import org.apache.fontbox.ttf.TrueTypeCollection; -import org.apache.fontbox.ttf.TrueTypeFont; import org.apache.pdfbox.io.IOUtils; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.font.PDFont; @@ -12,19 +11,14 @@ import org.apache.pdfbox.util.Matrix; import java.awt.Font; import java.awt.FontFormatException; import java.awt.FontMetrics; -import java.awt.Graphics; import java.awt.Paint; -import java.awt.font.FontRenderContext; -import java.awt.font.LineMetrics; import java.awt.font.TextAttribute; -import java.awt.geom.Rectangle2D; import java.io.Closeable; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.text.AttributedCharacterIterator; -import java.text.CharacterIterator; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -36,7 +30,6 @@ import java.util.logging.Logger; /** * 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 * temporary files. */ @@ -47,7 +40,9 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable { @Override public void close() { for (File tempFile : tempFiles) { - tempFile.delete(); + if (!tempFile.delete()) { + logger.log(Level.WARNING, "could not delete " + tempFile); + } } tempFiles.clear(); fontFiles.clear(); @@ -59,9 +54,11 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable { File file; } - private final List fontFiles = new ArrayList(); - private final List tempFiles = new ArrayList(); - private final Map fontMap = new HashMap(); + private final List fontFiles = new ArrayList<>(); + + private final List tempFiles = new ArrayList<>(); + + private final Map fontMap = new HashMap<>(); /** * Register a font. If possible, try to use a font file, i.e. @@ -121,7 +118,6 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable { * @throws IOException when something goes wrong with reading the font or writing the * font to the content stream of the PDF: */ - @SuppressWarnings("WeakerAccess") public void registerFont(InputStream fontStream) throws IOException { registerFont(null, fontStream); } @@ -151,7 +147,7 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable { } @Override - public boolean canDrawText(AttributedCharacterIterator iterator, IFontTextDrawerEnv env) + public boolean canDrawText(AttributedCharacterIterator iterator, FontTextDrawerEnv env) throws IOException, FontFormatException { /* * When no font is registered we can not display the text using a font... @@ -232,7 +228,7 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable { } @Override - public void drawText(AttributedCharacterIterator iterator, IFontTextDrawerEnv env) + public void drawText(AttributedCharacterIterator iterator, FontTextDrawerEnv env) throws IOException, FontFormatException { PDPageContentStream contentStream = env.getContentStream(); @@ -313,7 +309,7 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable { } @Override - public FontMetrics getFontMetrics(final Font f, IFontTextDrawerEnv env) + public FontMetrics getFontMetrics(final Font f, FontTextDrawerEnv env) throws IOException, FontFormatException { final FontMetrics defaultMetrics = env.getCalculationGraphics().getFontMetrics(f); final PDFont pdFont = mapFont(f, env); @@ -323,140 +319,15 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable { * * But it is correct and fine as long as we use vector shapes. */ - if (pdFont == null) + if (pdFont == null) { return defaultMetrics; - return new FontMetrics(f) { - public int getDescent() { - return defaultMetrics.getDescent(); - } - - public int getHeight() { - return defaultMetrics.getHeight(); - } - - public int getMaxAscent() { - return defaultMetrics.getMaxAscent(); - } - - public int getMaxDescent() { - return defaultMetrics.getMaxDescent(); - } - - public boolean hasUniformLineMetrics() { - return defaultMetrics.hasUniformLineMetrics(); - } - - public LineMetrics getLineMetrics(String str, Graphics context) { - return defaultMetrics.getLineMetrics(str, context); - } - - public LineMetrics getLineMetrics(String str, int beginIndex, int limit, - Graphics context) { - return defaultMetrics.getLineMetrics(str, beginIndex, limit, context); - } - - public LineMetrics getLineMetrics(char[] chars, int beginIndex, int limit, - Graphics context) { - return defaultMetrics.getLineMetrics(chars, beginIndex, limit, context); - } - - public LineMetrics getLineMetrics(CharacterIterator ci, int beginIndex, int limit, - Graphics context) { - return defaultMetrics.getLineMetrics(ci, beginIndex, limit, context); - } - - public Rectangle2D getStringBounds(String str, Graphics context) { - return defaultMetrics.getStringBounds(str, context); - } - - public Rectangle2D getStringBounds(String str, int beginIndex, int limit, - Graphics context) { - return defaultMetrics.getStringBounds(str, beginIndex, limit, context); - } - - public Rectangle2D getStringBounds(char[] chars, int beginIndex, int limit, - Graphics context) { - return defaultMetrics.getStringBounds(chars, beginIndex, limit, context); - } - - public Rectangle2D getStringBounds(CharacterIterator ci, int beginIndex, int limit, - Graphics context) { - return defaultMetrics.getStringBounds(ci, beginIndex, limit, context); - } - - public Rectangle2D getMaxCharBounds(Graphics context) { - return defaultMetrics.getMaxCharBounds(context); - } - - @Override - public int getAscent() { - return defaultMetrics.getAscent(); - } - - @Override - public int getMaxAdvance() { - return defaultMetrics.getMaxAdvance(); - } - - @Override - public int getLeading() { - return defaultMetrics.getLeading(); - } - - @Override - public FontRenderContext getFontRenderContext() { - return defaultMetrics.getFontRenderContext(); - } - - @Override - public int charWidth(char ch) { - char[] chars = {ch}; - return charsWidth(chars, 0, chars.length); - } - - @Override - public int charWidth(int codePoint) { - char[] data = Character.toChars(codePoint); - return charsWidth(data, 0, data.length); - } - - @Override - public int charsWidth(char[] data, int off, int len) { - return stringWidth(new String(data, off, len)); - } - - @Override - public int stringWidth(String str) { - try { - return (int) (pdFont.getStringWidth(str) / 1000 * f.getSize()); - } catch (IOException e) { - throw new RuntimeException(e); - } catch (IllegalArgumentException e) { - /* - * We let unknown chars be handled with - */ - return defaultMetrics.stringWidth(str); - } - } - - @Override - public int[] getWidths() { - try { - int[] first256Widths = new int[256]; - for (int i = 0; i < first256Widths.length; i++) - first256Widths[i] = (int) (pdFont.getWidth(i) / 1000 * f.getSize()); - return first256Widths; - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - }; + } + return new DefaultFontMetrics(f, defaultMetrics, pdFont); } private PDFont fallbackFontUnknownEncodings; - private PDFont findFallbackFont(IFontTextDrawerEnv env) throws IOException { + private PDFont findFallbackFont(FontTextDrawerEnv env) throws IOException { /* * We search for the right font in the folders... We try to use * LucidaSansRegular and if not found Arial, because this fonts often exists. We @@ -494,7 +365,7 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable { return null; } - private PDType0Font tryToLoadFont(IFontTextDrawerEnv env, File foundFontFile) throws IOException { + private PDType0Font tryToLoadFont(FontTextDrawerEnv env, File foundFontFile) { try { return PDType0Font.load(env.getDocument(), foundFontFile); } catch (IOException e) { @@ -503,38 +374,22 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable { } } - private void showTextOnStream(IFontTextDrawerEnv env, PDPageContentStream contentStream, - Font attributeFont, PDFont font, boolean isStrikeThrough, boolean isUnderline, - boolean isLigatures, String text) throws IOException { - if (isStrikeThrough || isUnderline) { - // noinspection unused - float stringWidth = font.getStringWidth(text); - // noinspection unused - LineMetrics lineMetrics = attributeFont - .getLineMetrics(text, env.getFontRenderContext()); - /* - * TODO: We can not draw that yet, we must do that later. While in textmode its - * not possible to draw lines... - */ - } - // noinspection StatementWithEmptyBody - if (isLigatures) { - /* - * No idea how to map this ... - */ - } + private void showTextOnStream(FontTextDrawerEnv env, + PDPageContentStream contentStream, + Font attributeFont, + PDFont font, + boolean isStrikeThrough, + boolean isUnderline, + boolean isLigatures, + String text) throws IOException { contentStream.showText(text); } - private PDFont applyFont(Font font, IFontTextDrawerEnv env) + private PDFont applyFont(Font font, FontTextDrawerEnv env) throws IOException, FontFormatException { PDFont fontToUse = mapFont(font, env); if (fontToUse == null) { - /* - * If we have no font but are forced to apply a font, we just use the default - * builtin PDF font... - */ - fontToUse = DefaultFontTextDrawerDefaultFonts.chooseMatchingHelvetica(font); + fontToUse = DefaultFontTextDrawerFonts.chooseMatchingHelvetica(font); } env.getContentStream().setFont(fontToUse, font.getSize2D()); return fontToUse; @@ -550,7 +405,7 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable { * @throws FontFormatException when the font file can not be loaded */ @SuppressWarnings("WeakerAccess") - protected PDFont mapFont(final Font font, final IFontTextDrawerEnv env) + protected PDFont mapFont(final Font font, final FontTextDrawerEnv env) throws IOException, FontFormatException { /* * If we have any font registering's, we must perform them now @@ -562,24 +417,17 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable { } if (fontEntry.file.getName().toLowerCase(Locale.US).endsWith(".ttc")) { TrueTypeCollection collection = new TrueTypeCollection(fontEntry.file); - collection.processAllFonts(new TrueTypeCollection.TrueTypeFontProcessor() { - @Override - public void process(TrueTypeFont ttf) throws IOException { - PDFont pdFont = PDType0Font.load(env.getDocument(), ttf, true); - fontMap.put(fontEntry.overrideName, pdFont); - fontMap.put(pdFont.getName(), pdFont); - } + collection.processAllFonts(ttf -> { + PDFont pdFont = PDType0Font.load(env.getDocument(), ttf, true); + fontMap.put(fontEntry.overrideName, pdFont); + fontMap.put(pdFont.getName(), pdFont); }); } else { - /* - * We load the font using the file. - */ PDFont pdFont = PDType0Font.load(env.getDocument(), fontEntry.file); fontMap.put(fontEntry.overrideName, pdFont); } } fontFiles.clear(); - return fontMap.get(font.getFontName()); } @@ -598,4 +446,100 @@ public class DefaultFontTextDrawer implements FontTextDrawer, Closeable { return true; } + /** + * Find a PDFont for the given font object, which does not need to be embedded. + * + * @param font font for which to find a suitable default font + * @return null if no default font is found or a default font which does not + * need to be embedded. + */ + protected static PDFont mapDefaultFonts(Font font) { + if (fontNameEqualsAnyOf(font, Font.SANS_SERIF, Font.DIALOG, Font.DIALOG_INPUT, "Arial", "Helvetica")) { + return chooseMatchingHelvetica(font); + } + if (fontNameEqualsAnyOf(font, Font.MONOSPACED, "courier", "courier new")) { + return chooseMatchingCourier(font); + } + if (fontNameEqualsAnyOf(font, Font.SERIF, "Times", "Times New Roman", "Times Roman")) { + return chooseMatchingTimes(font); + } + if (fontNameEqualsAnyOf(font, "Symbol")) { + return PDType1Font.SYMBOL; + } + if (fontNameEqualsAnyOf(font, "ZapfDingbats", "Dingbats")) { + return PDType1Font.ZAPF_DINGBATS; + } + return null; + } + + /** + * Get a PDType1Font.HELVETICA-variant, which matches the given font + * + * @param font Font to get the styles from + * @return a PDFont Helvetica variant which matches the style in the given Font + * object. + */ + protected static PDFont chooseMatchingHelvetica(Font font) { + if ((font.getStyle() & (Font.ITALIC | Font.BOLD)) == (Font.ITALIC | Font.BOLD)) { + return PDType1Font.HELVETICA_BOLD_OBLIQUE; + } + if ((font.getStyle() & Font.ITALIC) == Font.ITALIC) { + return PDType1Font.HELVETICA_OBLIQUE; + } + if ((font.getStyle() & Font.BOLD) == Font.BOLD) { + return PDType1Font.HELVETICA_BOLD; + } + return PDType1Font.HELVETICA; + } + + + /** + * Get a PDType1Font.COURIER-variant, which matches the given font + * + * @param font Font to get the styles from + * @return a PDFont Courier variant which matches the style in the given Font + * object. + */ + protected static PDFont chooseMatchingCourier(Font font) { + if ((font.getStyle() & (Font.ITALIC | Font.BOLD)) == (Font.ITALIC | Font.BOLD)) { + return PDType1Font.COURIER_BOLD_OBLIQUE; + } + if ((font.getStyle() & Font.ITALIC) == Font.ITALIC) { + return PDType1Font.COURIER_OBLIQUE; + } + if ((font.getStyle() & Font.BOLD) == Font.BOLD) { + return PDType1Font.COURIER_BOLD; + } + return PDType1Font.COURIER; + } + + /** + * Get a PDType1Font.TIMES-variant, which matches the given font + * + * @param font Font to get the styles from + * @return a PDFont Times variant which matches the style in the given Font + * object. + */ + protected static PDFont chooseMatchingTimes(Font font) { + if ((font.getStyle() & (Font.ITALIC | Font.BOLD)) == (Font.ITALIC | Font.BOLD)) { + return PDType1Font.TIMES_BOLD_ITALIC; + } + if ((font.getStyle() & Font.ITALIC) == Font.ITALIC) { + return PDType1Font.TIMES_ITALIC; + } + if ((font.getStyle() & Font.BOLD) == Font.BOLD) { + return PDType1Font.TIMES_BOLD; + } + return PDType1Font.TIMES_ROMAN; + } + + private static boolean fontNameEqualsAnyOf(Font font, String... names) { + String name = font.getName(); + for (String fontName : names) { + if (fontName.equalsIgnoreCase(name)) { + return true; + } + } + return false; + } } diff --git a/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultFontTextDrawerFonts.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultFontTextDrawerFonts.java new file mode 100644 index 0000000..0b1b9cb --- /dev/null +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultFontTextDrawerFonts.java @@ -0,0 +1,31 @@ +package org.xbib.graphics.io.pdfbox; + +import org.apache.pdfbox.pdmodel.font.PDFont; + +import java.awt.Font; +import java.awt.FontFormatException; +import java.io.IOException; + +/** + * Like {@link DefaultFontTextDrawer}, but tries to use default fonts + * whenever possible. Default fonts are not embedded. You can register + * additional font files. If no font mapping is found, Helvetica is used. + * This will fallback to vectorized text if any kind of RTL text is rendered + * and/or any other not supported feature is used. + */ +public class DefaultFontTextDrawerFonts extends DefaultFontTextDrawer { + + @Override + protected PDFont mapFont(Font font, FontTextDrawerEnv env) throws IOException, FontFormatException { + PDFont pdFont = mapDefaultFonts(font); + if (pdFont != null) { + return pdFont; + } + pdFont = super.mapFont(font, env); + if (pdFont != null) { + return pdFont; + } + return chooseMatchingHelvetica(font); + } + +} diff --git a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultFontTextForcedDrawer.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultFontTextDrawerForce.java similarity index 56% rename from graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultFontTextForcedDrawer.java rename to io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultFontTextDrawerForce.java index fcfcadc..3c40048 100644 --- a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultFontTextForcedDrawer.java +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultFontTextDrawerForce.java @@ -1,13 +1,14 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import java.text.AttributedCharacterIterator; /** - * Always draw using text, even if we know that we can not map the text correct + * Always draw using text, even if we know that we can not map the text correctly. */ -public class DefaultFontTextForcedDrawer extends DefaultFontTextDrawerDefaultFonts { +public class DefaultFontTextDrawerForce extends DefaultFontTextDrawerFonts { + @Override - public boolean canDrawText(AttributedCharacterIterator iterator, IFontTextDrawerEnv env) { + public boolean canDrawText(AttributedCharacterIterator iterator, FontTextDrawerEnv env) { return true; } } diff --git a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultPaintApplier.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultPaintApplier.java similarity index 90% rename from graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultPaintApplier.java rename to io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultPaintApplier.java index fb2597a..44d9ef6 100644 --- a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DefaultPaintApplier.java +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DefaultPaintApplier.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; @@ -51,50 +51,19 @@ import java.util.logging.Level; import java.util.logging.Logger; /** - * Default paint mapper. + * Default paint applier. */ public class DefaultPaintApplier implements PaintApplier { private static final Logger logger = Logger.getLogger(DefaultPaintApplier.class.getName()); - @SuppressWarnings("WeakerAccess") - protected static class PaintApplierState { - protected PDDocument document; - protected PDPageContentStream contentStream; - @SuppressWarnings("WeakerAccess") - protected ColorMapper colorMapper; - @SuppressWarnings("WeakerAccess") - protected ImageEncoder imageEncoder; - @SuppressWarnings("WeakerAccess") - protected PDResources resources; - @SuppressWarnings("WeakerAccess") - protected PDExtendedGraphicsState pdExtendedGraphicsState; - @SuppressWarnings("WeakerAccess") - protected Composite composite; - private COSDictionary dictExtendedState; - private IPaintEnv env; - public AffineTransform tf; - /** - * This transform is only set, when we apply a nested - * paint (e.g. a TilingPattern's paint) - */ - protected AffineTransform nestedTransform; - - private void ensureExtendedState() { - if (pdExtendedGraphicsState == null) { - this.dictExtendedState = new COSDictionary(); - this.dictExtendedState.setItem(COSName.TYPE, COSName.EXT_G_STATE); - pdExtendedGraphicsState = new PDExtendedGraphicsState(this.dictExtendedState); - } - } - } - private final ExtGStateCache extGStateCache = new ExtGStateCache(); + private final PDShadingCache shadingCache = new PDShadingCache(); @Override public PDShading applyPaint(Paint paint, PDPageContentStream contentStream, AffineTransform tf, - IPaintEnv env) throws IOException { + PaintApplierEnv env) throws IOException { PaintApplierState state = new PaintApplierState(); state.document = env.getDocument(); state.resources = env.getResources(); @@ -107,9 +76,9 @@ public class DefaultPaintApplier implements PaintApplier { state.tf = tf; state.nestedTransform = null; PDShading shading = applyPaint(paint, state); - if (state.pdExtendedGraphicsState != null) - contentStream.setGraphicsStateParameters( - extGStateCache.makeUnqiue(state.pdExtendedGraphicsState)); + if (state.pdExtendedGraphicsState != null) { + contentStream.setGraphicsStateParameters(extGStateCache.makeUnqiue(state.pdExtendedGraphicsState)); + } return shading; } @@ -119,29 +88,27 @@ public class DefaultPaintApplier implements PaintApplier { ColorMapper colorMapper = state.colorMapper; contentStream.setStrokingColor(colorMapper.mapColor(contentStream, color)); contentStream.setNonStrokingColor(colorMapper.mapColor(contentStream, color)); - int alpha = color.getAlpha(); if (alpha < 255) { state.ensureExtendedState(); Float strokingAlphaConstant = state.pdExtendedGraphicsState.getStrokingAlphaConstant(); - if (strokingAlphaConstant == null) + if (strokingAlphaConstant == null) { strokingAlphaConstant = 1f; - state.pdExtendedGraphicsState - .setStrokingAlphaConstant(strokingAlphaConstant * (alpha / 255f)); - Float nonStrokingAlphaConstant = state.pdExtendedGraphicsState - .getNonStrokingAlphaConstant(); - if (nonStrokingAlphaConstant == null) + } + state.pdExtendedGraphicsState.setStrokingAlphaConstant(strokingAlphaConstant * (alpha / 255f)); + Float nonStrokingAlphaConstant = state.pdExtendedGraphicsState.getNonStrokingAlphaConstant(); + if (nonStrokingAlphaConstant == null) { nonStrokingAlphaConstant = 1f; - state.pdExtendedGraphicsState - .setNonStrokingAlphaConstant(nonStrokingAlphaConstant * (alpha / 255f)); + } + state.pdExtendedGraphicsState.setNonStrokingAlphaConstant(nonStrokingAlphaConstant * (alpha / 255f)); } } private PDShading applyPaint(Paint paint, PaintApplierState state) throws IOException { applyComposite(state); - if (paint == null) + if (paint == null) { return null; - + } String simpleName = paint.getClass().getSimpleName(); if (paint instanceof Color) { applyAsStrokingColor((Color) paint, state); @@ -152,29 +119,24 @@ public class DefaultPaintApplier implements PaintApplier { } else if (simpleName.equals("PatternPaint")) { applyPatternPaint(paint, state); } else if (simpleName.equals("TilingPaint")) { - //applyPdfBoxTilingPaint(paint, state); + logger.log(Level.WARNING, "no tiling paint available"); } else if (paint instanceof GradientPaint) { return shadingCache.makeUnqiue(buildGradientShading((GradientPaint) paint, state)); } else if (paint instanceof TexturePaint) { applyTexturePaint((TexturePaint) paint, state); } else if (paint instanceof ShadingPaint) { - // PDFBox paint, we can import the shading directly - return shadingCache - .makeUnqiue(importPDFBoxShadingPaint((ShadingPaint) paint, state)); + return shadingCache.makeUnqiue(importPDFBoxShadingPaint((ShadingPaint) paint, state)); } else { logger.log(Level.WARNING, "Don't know paint " + paint.getClass().getName()); } - return null; } private PDShading importPDFBoxShadingPaint(ShadingPaint paint, PaintApplierState state) throws IOException { PDFCloneUtility pdfCloneUtility = new PDFCloneUtility(state.document); - Matrix matrix = paint.getMatrix(); PDShading shading = paint.getShading(); - state.contentStream.transform(matrix); return PDShading.create((COSDictionary) pdfCloneUtility .cloneForNewDocument(shading.getCOSObject())); @@ -197,18 +159,17 @@ public class DefaultPaintApplier implements PaintApplier { paintPatternTransform = new AffineTransform(paintPatternTransform); paintPatternTransform.preConcatenate(state.tf); patternTransform.concatenate(paintPatternTransform); - } else + } else { patternTransform.concatenate(state.tf); + } patternTransform.scale(1f, -1f); pattern.setMatrix(patternTransform); - PDAppearanceStream appearance = new PDAppearanceStream(state.document); appearance.setResources(pattern.getResources()); appearance.setBBox(pattern.getBBox()); - Object graphicsNode = getPropertyValue(paint, "getGraphicsNode"); - PdfBoxGraphics2D pdfBoxGraphics2D = new PdfBoxGraphics2D(state.document, pattern.getBBox(), - state.env.getGraphics2D()); + PdfBoxGraphics2D pdfBoxGraphics2D = + new PdfBoxGraphics2D(state.document, pattern.getBBox(), state.env.getGraphics2D()); try { Method paintMethod = graphicsNode.getClass().getMethod("paint", Graphics2D.class); paintMethod.invoke(graphicsNode, pdfBoxGraphics2D); @@ -218,37 +179,24 @@ public class DefaultPaintApplier implements PaintApplier { } pdfBoxGraphics2D.dispose(); PDFormXObject xFormObject = pdfBoxGraphics2D.getXFormObject(); - PDPageContentStream imageContentStream = new PDPageContentStream(state.document, appearance, ((COSStream) pattern.getCOSObject()).createOutputStream()); imageContentStream.drawForm(xFormObject); imageContentStream.close(); - PDColorSpace patternCS1 = new PDPattern(null); COSName tilingPatternName = state.resources.add(pattern); PDColor patternColor = new PDColor(tilingPatternName, patternCS1); - state.contentStream.setNonStrokingColor(patternColor); state.contentStream.setStrokingColor(patternColor); } - - /*private void applyPdfBoxTilingPaint(Paint paint, PaintApplierState state) { - Paint tilingPaint = PrivateFieldAccessor.getPrivateField(paint, "paint"); - Matrix patternMatrix = PrivateFieldAccessor.getPrivateField(paint, "patternMatrix"); - state.nestedTransform = patternMatrix.createAffineTransform(); - applyPaint(tilingPaint, state); - }*/ - private void applyComposite(PaintApplierState state) { - if (state.composite == null) + if (state.composite == null) { return; - - // Possibly set the alpha constant + } float alpha = 1; COSName blendMode = COSName.COMPATIBLE; int rule = AlphaComposite.SRC; - if (state.composite instanceof AlphaComposite) { AlphaComposite composite = (AlphaComposite) state.composite; alpha = composite.getAlpha(); @@ -259,45 +207,31 @@ public class DefaultPaintApplier implements PaintApplier { } else { logger.log(Level.WARNING, "Unknown composite " + state.composite.getClass().getSimpleName()); } - state.ensureExtendedState(); if (alpha < 1) { - assert state.pdExtendedGraphicsState != null; state.pdExtendedGraphicsState.setStrokingAlphaConstant(alpha); state.pdExtendedGraphicsState.setNonStrokingAlphaConstant(alpha); } - /* - * Try to map the alpha rule into blend modes - */ switch (rule) { case AlphaComposite.CLEAR: + case AlphaComposite.DST_ATOP: + case AlphaComposite.DST: + case AlphaComposite.DST_IN: + case AlphaComposite.DST_OUT: + case AlphaComposite.SRC_IN: + case AlphaComposite.SRC_OUT: + case AlphaComposite.DST_OVER: break; case AlphaComposite.SRC: blendMode = COSName.NORMAL; break; case AlphaComposite.SRC_OVER: + case AlphaComposite.SRC_ATOP: blendMode = COSName.COMPATIBLE; break; case AlphaComposite.XOR: blendMode = COSName.EXCLUSION; break; - case AlphaComposite.DST: - break; - case AlphaComposite.DST_ATOP: - break; - case AlphaComposite.SRC_ATOP: - blendMode = COSName.COMPATIBLE; - break; - case AlphaComposite.DST_IN: - break; - case AlphaComposite.DST_OUT: - break; - case AlphaComposite.SRC_IN: - break; - case AlphaComposite.SRC_OUT: - break; - case AlphaComposite.DST_OVER: - break; } state.dictExtendedState.setItem(COSName.BM, blendMode); } @@ -663,44 +597,28 @@ public class DefaultPaintApplier implements PaintApplier { COSArray domain = new COSArray(); domain.add(new COSFloat(0)); domain.add(new COSFloat(1)); - COSArray encode = new COSArray(); - COSArray range = new COSArray(); range.add(new COSFloat(0)); range.add(new COSFloat(1)); - - List colorList = new ArrayList(Arrays.asList(colors)); + List colorList = new ArrayList<>(Arrays.asList(colors)); COSArray bounds = new COSArray(); if (Math.abs(fractions[0]) > EPSILON) { - /* - * We need to insert a "keyframe" for fraction 0. See also java.awt.LinearGradientPaint for future information - */ colorList.add(0, colors[0]); bounds.add(new COSFloat(fractions[0])); } - - /* - * We always add the inner fractions - */ for (int i = 1; i < fractions.length - 1; i++) { float fraction = fractions[i]; bounds.add(new COSFloat(fraction)); } if (Math.abs(fractions[fractions.length - 1] - 1f) > EPSILON) { - /* - * We also need to insert a "keyframe" at the end for fraction 1 - */ colorList.add(colors[colors.length - 1]); bounds.add(new COSFloat(fractions[fractions.length - 1])); } - COSArray type2Functions = buildType2Functions(colorList, domain, encode, state); - function.setItem(COSName.FUNCTIONS, type2Functions); function.setItem(COSName.BOUNDS, bounds); function.setItem(COSName.ENCODE, encode); - PDFunctionType3 type3 = new PDFunctionType3(function); type3.setDomainValues(domain); return type3; @@ -718,7 +636,6 @@ public class DefaultPaintApplier implements PaintApplier { private COSArray buildType2Functions(List colors, COSArray domain, COSArray encode, PaintApplierState state) { Color prevColor = colors.get(0); - COSArray functions = new COSArray(); for (int i = 1; i < colors.size(); i++) { Color color = colors.get(i); @@ -726,11 +643,12 @@ public class DefaultPaintApplier implements PaintApplier { PDColor pdColor = state.colorMapper.mapColor(state.contentStream, color); COSArray c0 = new COSArray(); COSArray c1 = new COSArray(); - for (float component : prevPdColor.getComponents()) + for (float component : prevPdColor.getComponents()) { c0.add(new COSFloat(component)); - for (float component : pdColor.getComponents()) + } + for (float component : pdColor.getComponents()) { c1.add(new COSFloat(component)); - + } COSDictionary type2Function = new COSDictionary(); type2Function.setInt(COSName.FUNCTION_TYPE, 2); type2Function.setItem(COSName.C0, c0); @@ -738,7 +656,6 @@ public class DefaultPaintApplier implements PaintApplier { type2Function.setInt(COSName.N, 1); type2Function.setItem(COSName.DOMAIN, domain); functions.add(type2Function); - encode.add(new COSFloat(0)); encode.add(new COSFloat(1)); prevColor = color; @@ -769,7 +686,29 @@ public class DefaultPaintApplier implements PaintApplier { } c = c.getSuperclass(); } - throw new NullPointerException("Method " + propertyGetter + " not found on object " + obj.getClass().getName()); + throw new NullPointerException("Method " + propertyGetter + " not found on object " + obj); + } + + protected static class PaintApplierState { + protected PDDocument document; + protected PDPageContentStream contentStream; + protected ColorMapper colorMapper; + protected ImageEncoder imageEncoder; + protected PDResources resources; + protected PDExtendedGraphicsState pdExtendedGraphicsState; + protected Composite composite; + private COSDictionary dictExtendedState; + private PaintApplierEnv env; + public AffineTransform tf; + protected AffineTransform nestedTransform; + + private void ensureExtendedState() { + if (pdExtendedGraphicsState == null) { + this.dictExtendedState = new COSDictionary(); + this.dictExtendedState.setItem(COSName.TYPE, COSName.EXT_G_STATE); + pdExtendedGraphicsState = new PDExtendedGraphicsState(this.dictExtendedState); + } + } } private static abstract class COSResourceCacheBase { @@ -777,8 +716,9 @@ public class DefaultPaintApplier implements PaintApplier { private static boolean equalsCOSDictionary(COSDictionary cosDictionary, COSDictionary cosDictionary1) { - if (cosDictionary.size() != cosDictionary1.size()) + if (cosDictionary.size() != cosDictionary1.size()) { return false; + } for (COSName name : cosDictionary.keySet()) { COSBase item = cosDictionary.getItem(name); COSBase item2 = cosDictionary1.getItem(name); @@ -789,36 +729,37 @@ public class DefaultPaintApplier implements PaintApplier { } private static boolean equalsCOSBase(COSBase item, COSBase item2) { - if (item == item2) + if (item == item2) { return true; - if (item == null) + } + if (item == null) { return false; - if (item2 == null) + } + if (item2 == null) { return false; - /* - * Can the items be compared directly? - */ - if (item.equals(item2)) + } + if (item.equals(item2)) { return true; - - if (item instanceof COSDictionary && item2 instanceof COSDictionary) + } + if (item instanceof COSDictionary && item2 instanceof COSDictionary) { return equalsCOSDictionary((COSDictionary) item, (COSDictionary) item2); - - // noinspection SimplifiableIfStatement - if (item instanceof COSArray && item2 instanceof COSArray) + } + if (item instanceof COSArray && item2 instanceof COSArray) { return equalsCOSArray((COSArray) item, (COSArray) item2); - + } return false; } private static boolean equalsCOSArray(COSArray item, COSArray item2) { - if (item.size() != item2.size()) + if (item.size() != item2.size()) { return false; + } for (int i = 0; i < item.size(); i++) { COSBase i1 = item.getObject(i); COSBase i2 = item2.getObject(i); - if (!equalsCOSBase(i1, i2)) + if (!equalsCOSBase(i1, i2)) { return false; + } } return true; } @@ -827,14 +768,11 @@ public class DefaultPaintApplier implements PaintApplier { TObject makeUnqiue(TObject state) { int key = getKey(state); - List pdExtendedGraphicsStates = states.get(key); - if (pdExtendedGraphicsStates == null) { - pdExtendedGraphicsStates = new ArrayList(); - states.put(key, pdExtendedGraphicsStates); - } + List pdExtendedGraphicsStates = states.computeIfAbsent(key, k -> new ArrayList<>()); for (TObject s : pdExtendedGraphicsStates) { - if (stateEquals(s, state)) + if (stateEquals(s, state)) { return s; + } } pdExtendedGraphicsStates.add(state); return state; @@ -860,5 +798,4 @@ public class DefaultPaintApplier implements PaintApplier { return obj.getCOSObject().size(); } } - } diff --git a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DrawControl.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DrawControl.java similarity index 74% rename from graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DrawControl.java rename to io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DrawControl.java index e7ff0ce..c94b9be 100644 --- a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/DrawControl.java +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/DrawControl.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import java.awt.Paint; import java.awt.Shape; @@ -18,7 +18,7 @@ public interface DrawControl { * @param env Environment * @return the shape to be filled. If you return null, nothing will be filled */ - Shape transformShapeBeforeFill(Shape shape, IDrawControlEnv env); + Shape transformShapeBeforeFill(Shape shape, DrawControlEnv env); /** * You may optional change the shape that is going to be drawn. You can also do @@ -28,36 +28,36 @@ public interface DrawControl { * @param env Environment * @return the shape to be filled. If you return null, nothing will be drawn */ - Shape transformShapeBeforeDraw(Shape shape, IDrawControlEnv env); + Shape transformShapeBeforeDraw(Shape shape, DrawControlEnv env); /** * Called after shape was filled. This method is always called, even if - * {@link #transformShapeBeforeFill(Shape, IDrawControlEnv)} returns + * {@link #transformShapeBeforeFill(Shape, DrawControlEnv)} returns * null. * * @param shape the shape that was filled. This is the original shape, not the one * transformed by - * {@link #transformShapeBeforeFill(Shape, IDrawControlEnv)}. + * {@link #transformShapeBeforeFill(Shape, DrawControlEnv)}. * @param env Environment */ - void afterShapeFill(Shape shape, IDrawControlEnv env); + void afterShapeFill(Shape shape, DrawControlEnv env); /** * Called after shape was drawn. This method is always called, even if - * {@link #transformShapeBeforeDraw(Shape, IDrawControlEnv)} returns + * {@link #transformShapeBeforeDraw(Shape, DrawControlEnv)} returns * null. * * @param shape the shape that was drawn. This is the original shape, not the one * transformed by - * {@link #transformShapeBeforeDraw(Shape, IDrawControlEnv)}. + * {@link #transformShapeBeforeDraw(Shape, DrawControlEnv)}. * @param env Environment */ - void afterShapeDraw(Shape shape, IDrawControlEnv env); + void afterShapeDraw(Shape shape, DrawControlEnv env); /** * The environment of the draw operation */ - interface IDrawControlEnv { + interface DrawControlEnv { /** * @return the current paint set on the graphics. */ diff --git a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/FontTextDrawer.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/FontTextDrawer.java similarity index 89% rename from graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/FontTextDrawer.java rename to io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/FontTextDrawer.java index f84c455..75dbaa5 100644 --- a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/FontTextDrawer.java +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/FontTextDrawer.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPageContentStream; @@ -20,10 +20,33 @@ import java.text.AttributedCharacterIterator; */ public interface FontTextDrawer { + /** + * @param iterator Has the text and all its properties + * @param env Environment + * @return true when the given text can be fully drawn using fonts. return false + * to have the text drawn as vector shapes + * @throws IOException when a font can not be loaded or a paint can't be applied. + * @throws FontFormatException when the font file can not be loaded + */ + boolean canDrawText(AttributedCharacterIterator iterator, FontTextDrawerEnv env) + throws IOException, FontFormatException; + + /** + * @param iterator The text with all properties + * @param env Environment + * @throws IOException when a font can not be loaded or a paint can't be applied. + * @throws FontFormatException when the font file can not be loaded + */ + void drawText(AttributedCharacterIterator iterator, FontTextDrawerEnv env) + throws IOException, FontFormatException; + + FontMetrics getFontMetrics(Font f, FontTextDrawerEnv env) + throws IOException, FontFormatException; + /** * Enviroment for font based drawing of text */ - interface IFontTextDrawerEnv { + interface FontTextDrawerEnv { /** * @return the document we are writing to */ @@ -79,32 +102,4 @@ public interface FontTextDrawer { */ Graphics2D getCalculationGraphics(); } - - /** - * @param iterator Has the text and all its properties - * @param env Environment - * @return true when the given text can be fully drawn using fonts. return false - * to have the text drawn as vector shapes - * @throws IOException when a font can not be loaded or a paint can't be applied. - * @throws FontFormatException when the font file can not be loaded - */ - boolean canDrawText(AttributedCharacterIterator iterator, IFontTextDrawerEnv env) - throws IOException, FontFormatException; - - /** - * @param iterator The text with all properties - * @param env Environment - * @throws IOException when a font can not be loaded or a paint can't be applied. - * @throws FontFormatException when the font file can not be loaded - */ - void drawText(AttributedCharacterIterator iterator, IFontTextDrawerEnv env) - throws IOException, FontFormatException; - - /** - * @param f - * @param env - * @return - */ - FontMetrics getFontMetrics(Font f, IFontTextDrawerEnv env) - throws IOException, FontFormatException; } diff --git a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/ImageEncoder.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/ImageEncoder.java similarity index 93% rename from graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/ImageEncoder.java rename to io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/ImageEncoder.java index d74e081..52fce6a 100644 --- a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/ImageEncoder.java +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/ImageEncoder.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPageContentStream; diff --git a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/LosslessImageEncoder.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/LosslessImageEncoder.java similarity index 94% rename from graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/LosslessImageEncoder.java rename to io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/LosslessImageEncoder.java index c88dd62..5a38743 100644 --- a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/LosslessImageEncoder.java +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/LosslessImageEncoder.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPageContentStream; @@ -24,8 +24,11 @@ import java.util.Map; * PdfBoxGraphics2D objects. */ public class LosslessImageEncoder implements ImageEncoder { + private Map> imageMap = new HashMap<>(); + private Map> profileMap = new HashMap<>(); + private SoftReference doc; @Override @@ -87,17 +90,18 @@ public class LosslessImageEncoder implements ImageEncoder { @Override public boolean equals(Object obj) { - if (obj == null) + if (obj == null) { return false; - assert obj instanceof ImageSoftReference; + } return ((ImageSoftReference) obj).get() == get(); } @Override public int hashCode() { Image image = get(); - if (image == null) + if (image == null) { return 0; + } return image.hashCode(); } } @@ -109,17 +113,18 @@ public class LosslessImageEncoder implements ImageEncoder { @Override public boolean equals(Object obj) { - if (obj == null) + if (obj == null) { return false; - assert obj instanceof ProfileSoftReference; + } return ((ProfileSoftReference) obj).get() == get(); } @Override public int hashCode() { ICC_Profile image = get(); - if (image == null) + if (image == null) { return 0; + } return image.hashCode(); } } diff --git a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/PaintApplier.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/PaintApplier.java similarity index 93% rename from graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/PaintApplier.java rename to io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/PaintApplier.java index def14f8..ff86e51 100644 --- a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/PaintApplier.java +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/PaintApplier.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPageContentStream; @@ -30,13 +30,13 @@ public interface PaintApplier { * @throws IOException if its not possible to write the paint into the contentStream */ PDShading applyPaint(Paint paint, PDPageContentStream contentStream, - AffineTransform currentTransform, IPaintEnv env) throws IOException; + AffineTransform currentTransform, PaintApplierEnv env) throws IOException; /** * The different mappers used by the paint applier. This interface is * implemented internally by {@link PdfBoxGraphics2D} */ - interface IPaintEnv { + interface PaintApplierEnv { /** * @return the color mapper */ diff --git a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/PdfBoxGraphics2D.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/PdfBoxGraphics2D.java similarity index 82% rename from graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/PdfBoxGraphics2D.java rename to io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/PdfBoxGraphics2D.java index bce50a7..b69a038 100644 --- a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/PdfBoxGraphics2D.java +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/PdfBoxGraphics2D.java @@ -1,8 +1,8 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; -import org.xbib.graphics.graphics2d.pdfbox.DrawControl.IDrawControlEnv; -import org.xbib.graphics.graphics2d.pdfbox.FontTextDrawer.IFontTextDrawerEnv; -import org.xbib.graphics.graphics2d.pdfbox.PaintApplier.IPaintEnv; +import org.xbib.graphics.io.pdfbox.DrawControl.DrawControlEnv; +import org.xbib.graphics.io.pdfbox.FontTextDrawer.FontTextDrawerEnv; +import org.xbib.graphics.io.pdfbox.PaintApplier.PaintApplierEnv; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdmodel.PDDocument; @@ -110,306 +110,24 @@ public class PdfBoxGraphics2D extends Graphics2D { private final PDRectangle bbox; - /** - * Set a new color mapper. - * - * @param colorMapper the color mapper which maps Color to PDColor. - */ - public void setColorMapper(ColorMapper colorMapper) { - this.colorMapper = colorMapper; - } - - /** - * Set a new image encoder - * - * @param imageEncoder the image encoder, which encodes a image as PDImageXForm. - */ - public void setImageEncoder(ImageEncoder imageEncoder) { - this.imageEncoder = imageEncoder; - } - - /** - * Set a new paint applier. You should always derive your custom paint applier - * from the {@link PaintApplier} and just extend the paint - * mapping for custom paint. - *

- * If the paint you map is a paint from a standard library and you can implement - * the mapping using reflection please feel free to send a pull request to - * extend the default paint mapper. - * - * @param paintApplier the paint applier responsible for mapping the paint correctly - */ - public void setPaintApplier(PaintApplier paintApplier) { - this.paintApplier = paintApplier; - } - - /** - * Set a new draw control. This allows you to influence fill() and draw() - * operations. drawString() is only influence if the text is drawn as vector - * shape. - * - * @param drawControl the draw control - */ - public void setDrawControl(DrawControl drawControl) { - this.drawControl = drawControl; - } - - /** - * Create a PDfBox Graphics2D. This size is used for the BBox of the XForm. So - * everything drawn outside the rectangle (0x0)-(pixelWidth,pixelHeight) will be - * clipped. - *

- * Note: pixelWidth and pixelHeight only define the size of the coordinate space - * within this Graphics2D. They do not affect how big the XForm is finally - * displayed in the PDF. - * - * @param document The document the graphics should be used to create a XForm in. - * @param pixelWidth the width in pixel of the drawing area. - * @param pixelHeight the height in pixel of the drawing area. - * @throws IOException if something goes wrong with writing into the content stream of - * the {@link PDDocument}. - */ - public PdfBoxGraphics2D(PDDocument document, int pixelWidth, int pixelHeight) throws IOException { - this(document, new PDRectangle(pixelWidth, pixelHeight)); - } - - /** - * Create a PDfBox Graphics2D. This size is used for the BBox of the XForm. So - * everything drawn outside the rectangle (0x0)-(pixelWidth,pixelHeight) will be - * clipped. - *

- * Note: pixelWidth and pixelHeight only define the size of the coordinate space - * within this Graphics2D. They do not affect how big the XForm is finally - * displayed in the PDF. - * - * @param document The document the graphics should be used to create a XForm in. - * @param pixelWidth the width in pixel of the drawing area. - * @param pixelHeight the height in pixel of the drawing area. - * @throws IOException if something goes wrong with writing into the content stream of - * the {@link PDDocument}. - */ - public PdfBoxGraphics2D(PDDocument document, float pixelWidth, float pixelHeight) - throws IOException { - this(document, new PDRectangle(pixelWidth, pixelHeight)); - } - - /** - * Set an optional text drawer. By default, all text is vectorized and drawn - * using vector shapes. To embed fonts into a PDF file it is necessary to have - * the underlying TTF file. The java.awt.Font class does not provide that. The - * FontTextDrawer must perform the java.awt.Font <=> PDFont mapping and - * also must perform the text layout. If it can not map the text or font - * correctly, the font drawing falls back to vectoring the text. - * - * @param fontTextDrawer The text drawer, which can draw text using fonts - */ - @SuppressWarnings("WeakerAccess") - public void setFontTextDrawer(FontTextDrawer fontTextDrawer) { - this.fontTextDrawer = fontTextDrawer; - } - private int saveCounter = 0; - private final List copyList = new ArrayList(); + private final List copyList = new ArrayList<>(); - private static class CopyInfo { - PdfBoxGraphics2D sourceGfx; - PdfBoxGraphics2D copy; - String creatingContextInfo; - - @Override - public String toString() { - return "CopyInfo{creatingContextInfo='" + creatingContextInfo + '\'' + '}'; - } - } + private final PaintApplierEnvImpl paintEnv = new PaintApplierEnvImpl(); /** - * @param document The document the graphics should be used to create a XForm in. - * @param bbox Bounding Box of the graphics - * @throws IOException when something goes wrong with writing into the content stream of - * the {@link PDDocument}. + * Do we currently have an active path on the content stream, which has not been + * closed? + * We need this flag to avoid to clip twice if both the plaint applyer needs to + * clip and we have some clipping. If at the end we try to clip with an empty + * path, then Acrobat Reader does not like that and draws nothing. */ - public PdfBoxGraphics2D(PDDocument document, PDRectangle bbox) throws IOException { - this(document, bbox, null); - } + private boolean hasPathOnStream = false; - /* - * @internal - */ - PdfBoxGraphics2D(PDDocument document, PDRectangle bbox, PdfBoxGraphics2D parentGfx) - throws IOException { - this.document = document; - this.bbox = bbox; + private Map renderingHints = new HashMap<>(); - PDAppearanceStream appearance = new PDAppearanceStream(document); - xFormObject = appearance; - xFormObject.setResources(new PDResources()); - xFormObject.setBBox(bbox); - contentStream = new PDPageContentStream(document, appearance, - xFormObject.getStream().createOutputStream(COSName.FLATE_DECODE)); - contentStreamSaveState(); - - if (parentGfx != null) { - this.colorMapper = parentGfx.colorMapper; - this.fontTextDrawer = parentGfx.fontTextDrawer; - this.imageEncoder = parentGfx.imageEncoder; - this.paintApplier = parentGfx.paintApplier; - } - - baseTransform = new AffineTransform(); - baseTransform.translate(0, bbox.getHeight()); - baseTransform.scale(1, -1); - - calcImage = new BufferedImage(100, 100, BufferedImage.TYPE_4BYTE_ABGR); - calcGfx = calcImage.createGraphics(); - font = calcGfx.getFont(); - copyInfo = null; - - } - - /** - * @return the PDAppearanceStream which resulted in this graphics - */ - @SuppressWarnings("WeakerAccess") - public PDFormXObject getXFormObject() { - if (document != null) - throw new IllegalStateException( - "You can only get the XformObject after you disposed the Graphics2D!"); - if (copyInfo != null) - throw new IllegalStateException("You can not get the Xform stream from the copy"); - return xFormObject; - } - - private PdfBoxGraphics2D(PdfBoxGraphics2D gfx) throws IOException { - CopyInfo info = new CopyInfo(); - info.creatingContextInfo = gatherContext(); - info.copy = this; - info.sourceGfx = gfx; - gfx.copyList.add(info); - this.copyInfo = info; - this.hasPathOnStream = false; - this.document = gfx.document; - this.bbox = gfx.bbox; - this.xFormObject = gfx.xFormObject; - this.contentStream = gfx.contentStream; - this.baseTransform = gfx.baseTransform; - this.transform = (AffineTransform) gfx.transform.clone(); - this.calcGfx = gfx.calcGfx; - this.calcImage = gfx.calcImage; - this.font = gfx.font; - this.stroke = gfx.stroke; - this.paint = gfx.paint; - this.clipShape = gfx.clipShape; - this.backgroundColor = gfx.backgroundColor; - this.colorMapper = gfx.colorMapper; - this.fontTextDrawer = gfx.fontTextDrawer; - this.imageEncoder = gfx.imageEncoder; - this.paintApplier = gfx.paintApplier; - this.drawControl = gfx.drawControl; - this.composite = gfx.composite; - this.renderingHints = new HashMap(gfx.renderingHints); - this.xorColor = gfx.xorColor; - this.saveCounter = 0; - - contentStreamSaveState(); - } - - /** - * Global Flag: If set to true the Callstack when creating a - * context is recorded. - *

- * Note: Setting this to true will slow down the library. Use this only for - * debugging. - */ - public static boolean ENABLE_CHILD_CREATING_DEBUG = false; - - private String gatherContext() { - if (!ENABLE_CHILD_CREATING_DEBUG) - return null; - StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - StringBuilder sb = new StringBuilder(); - for (StackTraceElement stackTraceElement : stackTrace) { - if (stackTraceElement.getClassName().startsWith("de.rototor.pdfbox")) - continue; - if (stackTraceElement.getClassName().startsWith("org.junit")) - continue; - if (stackTraceElement.getClassName().startsWith("com.intellij.rt")) - continue; - if (stackTraceElement.getClassName().startsWith("java.lang")) - continue; - sb.append(" at ").append(stackTraceElement.getClassName()).append(".") - .append(stackTraceElement.getMethodName()).append("(") - .append(stackTraceElement.getFileName()).append(":") - .append(stackTraceElement.getLineNumber()).append(")").append("\n"); - } - return sb.toString(); - } - - /** - * Sometimes the users of {@link #create()} don't correctly {@link #dispose()} - * the child graphics they create. And you may not always be able to fix this - * uses, as it may be in some 3rdparty library. In this case this method can - * help you. It will cleanup all dangling child graphics. The child graphics can - * not be used after that. This method is a workaround for a buggy old code. You - * should only use it if you have to.
- *

- * Note: You can only call this method on the "main" graphics, not on a child - * created with {@link #create()} - */ - @SuppressWarnings("WeakerAccess") - public void disposeDanglingChildGraphics() { - if (copyInfo != null) - throw new IllegalStateException( - "Don't call disposeDanglingChildGraphics() on a child!"); - disposeCopies(copyList); - } - - private static void disposeCopies(List cl) { - while (cl.size() > 0) { - CopyInfo copyInfo = cl.get(0); - disposeCopies(copyInfo.copy.copyList); - copyInfo.copy.dispose(); - } - } - - public void dispose() { - if (copyInfo != null) { - copyInfo.sourceGfx.copyList.remove(copyInfo); - try { - contentStreamRestoreState(); - } catch (IOException e) { - throwException(e); - } - if (this.saveCounter != 0) - throw new IllegalStateException( - "Copy - SaveCounter should be 0, but is " + this.saveCounter); - return; - } - if (copyList.size() > 0) - /* - * When not all copies created by create() are disposed(), the resulting PDF - * content stream will be invalid, as the save/restore context commands (q/Q) - * are not balanced. You should always dispose() a graphics context when you are - * done with it. - */ - throw new IllegalStateException( - "Not all PdfGraphics2D copies were destroyed! Please ensure that all create() calls get a matching dispose() on the returned copies. Also consider using disposeDanglingChildGraphics()"); - try { - contentStreamRestoreState(); - contentStream.close(); - } catch (IOException e) { - throwException(e); - } - if (this.saveCounter != 0) - throw new IllegalStateException("SaveCounter should be 0, but is " + this.saveCounter); - - document = null; - calcGfx.dispose(); - calcImage.flush(); - calcImage = null; - } - - private final IDrawControlEnv drawControlEnv = new IDrawControlEnv() { + private final DrawControlEnv drawControlEnv = new DrawControlEnv() { @Override public Paint getPaint() { return paint; @@ -421,274 +139,7 @@ public class PdfBoxGraphics2D extends Graphics2D { } }; - public void draw(Shape s) { - checkNoCopyActive(); - /* - * Don't try to draw with no paint, just ignore that. - */ - if (paint == null) - return; - try { - contentStreamSaveState(); - - Shape shapeToDraw = drawControl.transformShapeBeforeDraw(s, drawControlEnv); - - if (shapeToDraw != null) { - walkShape(shapeToDraw); - PDShading pdShading = applyPaint(shapeToDraw); - if (pdShading != null) - applyShadingAsColor(pdShading); - - if (stroke instanceof BasicStroke) { - BasicStroke basicStroke = (BasicStroke) this.stroke; - - // Cap Style maps 1:1 between Java and PDF Spec - contentStream.setLineCapStyle(basicStroke.getEndCap()); - // Line Join Style maps 1:1 between Java and PDF Spec - contentStream.setLineJoinStyle(basicStroke.getLineJoin()); - if (basicStroke.getMiterLimit() > 0) { - // Also Miter maps 1:1 between Java and PDF Spec - // (NB: set the miter-limit only if value is > 0) - contentStream.setMiterLimit(basicStroke.getMiterLimit()); - } - - AffineTransform tf = new AffineTransform(); - tf.concatenate(baseTransform); - tf.concatenate(transform); - - double scaleX = tf.getScaleX(); - contentStream - .setLineWidth((float) Math.abs(basicStroke.getLineWidth() * scaleX)); - float[] dashArray = basicStroke.getDashArray(); - if (dashArray != null) { - for (int i = 0; i < dashArray.length; i++) - dashArray[i] = (float) Math.abs(dashArray[i] * scaleX); - contentStream.setLineDashPattern(dashArray, - (float) Math.abs(basicStroke.getDashPhase() * scaleX)); - } - } - - contentStream.stroke(); - hasPathOnStream = false; - } - - drawControl.afterShapeDraw(s, drawControlEnv); - - contentStreamRestoreState(); - } catch (IOException e) { - throwException(e); - } - } - - public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { - BufferedImage img1 = op.filter(img, null); - drawImage(img1, new AffineTransform(1f, 0f, 0f, 1f, x, y), null); - } - - public void drawRenderedImage(RenderedImage img, AffineTransform xform) { - WritableRaster data = img.copyData(null); - drawImage(new BufferedImage(img.getColorModel(), data, false, null), xform, null); - } - - public void drawRenderableImage(RenderableImage img, AffineTransform xform) { - drawRenderedImage(img.createDefaultRendering(), xform); - } - - public void drawString(String str, int x, int y) { - drawString(str, (float) x, (float) y); - } - - public void drawString(String str, float x, float y) { - AttributedString attributedString = new AttributedString(str); - attributedString.addAttribute(TextAttribute.FONT, font); - drawString(attributedString.getIterator(), x, y); - } - - public void drawString(AttributedCharacterIterator iterator, int x, int y) { - drawString(iterator, (float) x, (float) y); - } - - public boolean drawImage(Image img, int x, int y, ImageObserver observer) { - return drawImage(img, x, y, img.getWidth(observer), img.getHeight(observer), observer); - } - - public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { - AffineTransform tf = new AffineTransform(); - tf.translate(x, y); - tf.scale((float) width / img.getWidth(null), (float) height / img.getHeight(null)); - return drawImage(img, tf, observer); - } - - public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { - return drawImage(img, x, y, img.getWidth(observer), img.getHeight(observer), bgcolor, - observer); - } - - public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, - ImageObserver observer) { - try { - if (bgcolor != null) { - contentStream.setNonStrokingColor(colorMapper.mapColor(contentStream, bgcolor)); - walkShape(new Rectangle(x, y, width, height)); - contentStream.fill(); - } - return drawImage(img, x, y, img.getWidth(observer), img.getHeight(observer), observer); - } catch (IOException e) { - throwException(e); - return false; - } - } - - public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, - int sx2, int sy2, ImageObserver observer) { - return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy2, sx2, sy2, null, observer); - } - - public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { - checkNoCopyActive(); - AffineTransform tf = new AffineTransform(); - tf.concatenate(baseTransform); - tf.concatenate(transform); - - // Sometimes the xform can be null - if (xform != null) - tf.concatenate((AffineTransform) xform.clone()); - - PDImageXObject pdImage = imageEncoder.encodeImage(document, contentStream, img); - try { - contentStreamSaveState(); - int imgHeight = img.getHeight(obs); - tf.translate(0, imgHeight); - tf.scale(1, -1); - contentStream.transform(new Matrix(tf)); - - Object keyInterpolation = renderingHints.get(RenderingHints.KEY_INTERPOLATION); - if (RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR.equals(keyInterpolation)) - pdImage.setInterpolate(false); - - if (composite != null) { - // We got an AlphaComposite, we must set the extended graphics dictionary correctly. - // The PaintApplyer will do this for us. So we just apply the current paint - // so that the graphics dictionary is set correctly. - applyPaint(null); - } - - contentStream.drawImage(pdImage, 0, 0, img.getWidth(obs), imgHeight); - contentStreamRestoreState(); - } catch (IOException e) { - throwException(e); - } - return true; - } - - public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, - int sx2, int sy2, Color bgcolor, ImageObserver observer) { - try { - contentStreamSaveState(); - int width = dx2 - dx1; - int height = dy2 - dy1; - - /* - * Set the clipping - */ - walkShape(new Rectangle2D.Double(dx1, dy1, width, height)); - contentStream.clip(); - - /* - * Maybe fill the background color - */ - if (bgcolor != null) { - contentStream.setNonStrokingColor(colorMapper.mapColor(contentStream, bgcolor)); - walkShape(new Rectangle(dx1, dy1, width, height)); - contentStream.fill(); - } - - /* - * Build the transform for the image - */ - AffineTransform tf = new AffineTransform(); - tf.translate(dx1, dy1); - float imgWidth = img.getWidth(observer); - float imgHeight = img.getHeight(observer); - tf.scale((float) width / imgWidth, (float) height / imgHeight); - tf.translate(-sx1, -sy1); - tf.scale((sx2 - sx1) / imgWidth, (sy2 - sy1) / imgHeight); - - drawImage(img, tf, observer); - contentStreamRestoreState(); - return true; - } catch (IOException e) { - throwException(e); - return false; - } - } - - private void drawStringUsingShapes(AttributedCharacterIterator iterator, float x, float y) { - Stroke originalStroke = stroke; - Paint originalPaint = paint; - TextLayout textLayout = new TextLayout(iterator, getFontRenderContext()); - textLayout.draw(this, x, y); - paint = originalPaint; - stroke = originalStroke; - } - - public void drawString(AttributedCharacterIterator iterator, float x, float y) { - /* - * Don't try to draw with no paint, just ignore that. - */ - if (paint == null) - return; - - try { - contentStreamSaveState(); - /* - * If we can draw the text using fonts, we do this - */ - if (fontTextDrawer - .canDrawText((AttributedCharacterIterator) iterator.clone(), fontDrawerEnv)) { - drawStringUsingText(iterator, x, y); - } else { - /* - * Otherwise we fall back to draw using shapes. This works always - */ - drawStringUsingShapes(iterator, x, y); - } - contentStreamRestoreState(); - } catch (IOException e) { - throwException(e); - } catch (FontFormatException e) { - throwException(e); - } - } - - private void drawStringUsingText(AttributedCharacterIterator iterator, float x, float y) - throws IOException, FontFormatException { - contentStreamSaveState(); - - AffineTransform tf = new AffineTransform(baseTransform); - tf.concatenate(transform); - tf.translate(x, y); - contentStream.transform(new Matrix(tf)); - - fontTextDrawer.drawText(iterator, fontDrawerEnv); - - contentStreamRestoreState(); - } - - private void contentStreamSaveState() throws IOException { - saveCounter++; - contentStream.saveGraphicsState(); - } - - private void contentStreamRestoreState() throws IOException { - if (saveCounter == 0) - throw new IllegalStateException( - "Internal save/restore state error. Should never happen."); - saveCounter--; - contentStream.restoreGraphicsState(); - } - - private final IFontTextDrawerEnv fontDrawerEnv = new IFontTextDrawerEnv() { + private final FontTextDrawerEnv fontDrawerEnv = new FontTextDrawerEnv() { @Override public PDDocument getDocument() { return document; @@ -737,6 +188,340 @@ public class PdfBoxGraphics2D extends Graphics2D { } }; + /** + * Create a PDfBox Graphics2D. This size is used for the BBox of the XForm. So + * everything drawn outside the rectangle (0x0)-(pixelWidth,pixelHeight) will be + * clipped. + * Note: pixelWidth and pixelHeight only define the size of the coordinate space + * within this Graphics2D. They do not affect how big the XForm is finally + * displayed in the PDF. + * + * @param document The document the graphics should be used to create a XForm in. + * @param pixelWidth the width in pixel of the drawing area. + * @param pixelHeight the height in pixel of the drawing area. + * @throws IOException if something goes wrong with writing into the content stream of + * the {@link PDDocument}. + */ + public PdfBoxGraphics2D(PDDocument document, int pixelWidth, int pixelHeight) throws IOException { + this(document, new PDRectangle(pixelWidth, pixelHeight)); + } + + /** + * Create a PDfBox Graphics2D. This size is used for the BBox of the XForm. So + * everything drawn outside the rectangle (0x0)-(pixelWidth,pixelHeight) will be + * clipped. + * Note: pixelWidth and pixelHeight only define the size of the coordinate space + * within this Graphics2D. They do not affect how big the XForm is finally + * displayed in the PDF. + * + * @param document The document the graphics should be used to create a XForm in. + * @param pixelWidth the width in pixel of the drawing area. + * @param pixelHeight the height in pixel of the drawing area. + * @throws IOException if something goes wrong with writing into the content stream of + * the {@link PDDocument}. + */ + public PdfBoxGraphics2D(PDDocument document, float pixelWidth, float pixelHeight) + throws IOException { + this(document, new PDRectangle(pixelWidth, pixelHeight)); + } + + /** + * @param document The document the graphics should be used to create a XForm in. + * @param bbox Bounding Box of the graphics + * @throws IOException when something goes wrong with writing into the content stream of + * the {@link PDDocument}. + */ + public PdfBoxGraphics2D(PDDocument document, PDRectangle bbox) throws IOException { + this(document, bbox, null); + } + + PdfBoxGraphics2D(PDDocument document, PDRectangle bbox, PdfBoxGraphics2D parentGfx) + throws IOException { + this.document = document; + this.bbox = bbox; + PDAppearanceStream appearance = new PDAppearanceStream(document); + xFormObject = appearance; + xFormObject.setResources(new PDResources()); + xFormObject.setBBox(bbox); + contentStream = new PDPageContentStream(document, appearance, + xFormObject.getStream().createOutputStream(COSName.FLATE_DECODE)); + contentStreamSaveState(); + if (parentGfx != null) { + this.colorMapper = parentGfx.colorMapper; + this.fontTextDrawer = parentGfx.fontTextDrawer; + this.imageEncoder = parentGfx.imageEncoder; + this.paintApplier = parentGfx.paintApplier; + } + baseTransform = new AffineTransform(); + baseTransform.translate(0, bbox.getHeight()); + baseTransform.scale(1, -1); + calcImage = new BufferedImage(100, 100, BufferedImage.TYPE_4BYTE_ABGR); + calcGfx = calcImage.createGraphics(); + font = calcGfx.getFont(); + copyInfo = null; + } + + private PdfBoxGraphics2D(PdfBoxGraphics2D gfx) throws IOException { + CopyInfo info = new CopyInfo(); + info.creatingContextInfo = null; + info.copy = this; + info.sourceGfx = gfx; + gfx.copyList.add(info); + this.copyInfo = info; + this.hasPathOnStream = false; + this.document = gfx.document; + this.bbox = gfx.bbox; + this.xFormObject = gfx.xFormObject; + this.contentStream = gfx.contentStream; + this.baseTransform = gfx.baseTransform; + this.transform = (AffineTransform) gfx.transform.clone(); + this.calcGfx = gfx.calcGfx; + this.calcImage = gfx.calcImage; + this.font = gfx.font; + this.stroke = gfx.stroke; + this.paint = gfx.paint; + this.clipShape = gfx.clipShape; + this.backgroundColor = gfx.backgroundColor; + this.colorMapper = gfx.colorMapper; + this.fontTextDrawer = gfx.fontTextDrawer; + this.imageEncoder = gfx.imageEncoder; + this.paintApplier = gfx.paintApplier; + this.drawControl = gfx.drawControl; + this.composite = gfx.composite; + this.renderingHints = new HashMap<>(gfx.renderingHints); + this.xorColor = gfx.xorColor; + this.saveCounter = 0; + contentStreamSaveState(); + } + + @Override + public void dispose() { + if (copyInfo != null) { + copyInfo.sourceGfx.copyList.remove(copyInfo); + try { + contentStreamRestoreState(); + } catch (IOException e) { + throw new PdfBoxGraphics2dException(e); + } + if (this.saveCounter != 0) + throw new IllegalStateException("Copy - SaveCounter should be 0, but is " + this.saveCounter); + return; + } + if (copyList.size() > 0) + throw new IllegalStateException("Not all PdfGraphics2D copies were destroyed! Please ensure that all create() calls get a matching dispose() on the returned copies. Also consider using disposeDanglingChildGraphics()"); + try { + contentStreamRestoreState(); + contentStream.close(); + } catch (IOException e) { + throw new PdfBoxGraphics2dException(e); + } + if (this.saveCounter != 0) { + throw new IllegalStateException("SaveCounter should be 0, but is " + this.saveCounter); + } + document = null; + calcGfx.dispose(); + calcImage.flush(); + calcImage = null; + } + + @Override + public void draw(Shape s) { + checkNoCopyActive(); + if (paint == null) { + return; + } + try { + contentStreamSaveState(); + Shape shapeToDraw = drawControl.transformShapeBeforeDraw(s, drawControlEnv); + if (shapeToDraw != null) { + walkShape(shapeToDraw); + PDShading pdShading = applyPaint(shapeToDraw); + if (pdShading != null) { + applyShadingAsColor(pdShading); + } + if (stroke instanceof BasicStroke) { + BasicStroke basicStroke = (BasicStroke) this.stroke; + contentStream.setLineCapStyle(basicStroke.getEndCap()); + contentStream.setLineJoinStyle(basicStroke.getLineJoin()); + if (basicStroke.getMiterLimit() > 0) { + contentStream.setMiterLimit(basicStroke.getMiterLimit()); + } + AffineTransform tf = new AffineTransform(); + tf.concatenate(baseTransform); + tf.concatenate(transform); + double scaleX = tf.getScaleX(); + contentStream.setLineWidth((float) Math.abs(basicStroke.getLineWidth() * scaleX)); + float[] dashArray = basicStroke.getDashArray(); + if (dashArray != null) { + for (int i = 0; i < dashArray.length; i++) { + dashArray[i] = (float) Math.abs(dashArray[i] * scaleX); + } + contentStream.setLineDashPattern(dashArray, + (float) Math.abs(basicStroke.getDashPhase() * scaleX)); + } + } + contentStream.stroke(); + hasPathOnStream = false; + } + drawControl.afterShapeDraw(s, drawControlEnv); + contentStreamRestoreState(); + } catch (IOException e) { + throw new PdfBoxGraphics2dException(e); + } + } + + @Override + public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { + BufferedImage img1 = op.filter(img, null); + drawImage(img1, new AffineTransform(1f, 0f, 0f, 1f, x, y), null); + } + + @Override + public void drawRenderedImage(RenderedImage img, AffineTransform xform) { + WritableRaster data = img.copyData(null); + drawImage(new BufferedImage(img.getColorModel(), data, false, null), xform, null); + } + + @Override + public void drawRenderableImage(RenderableImage img, AffineTransform xform) { + drawRenderedImage(img.createDefaultRendering(), xform); + } + + @Override + public void drawString(String str, int x, int y) { + drawString(str, (float) x, (float) y); + } + + @Override + public void drawString(String str, float x, float y) { + AttributedString attributedString = new AttributedString(str); + attributedString.addAttribute(TextAttribute.FONT, font); + drawString(attributedString.getIterator(), x, y); + } + + @Override + public void drawString(AttributedCharacterIterator iterator, int x, int y) { + drawString(iterator, (float) x, (float) y); + } + + @Override + public boolean drawImage(Image img, int x, int y, ImageObserver observer) { + return drawImage(img, x, y, img.getWidth(observer), img.getHeight(observer), observer); + } + + @Override + public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { + AffineTransform tf = new AffineTransform(); + tf.translate(x, y); + tf.scale((float) width / img.getWidth(null), (float) height / img.getHeight(null)); + return drawImage(img, tf, observer); + } + + @Override + public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { + return drawImage(img, x, y, img.getWidth(observer), img.getHeight(observer), bgcolor, observer); + } + + @Override + public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, + ImageObserver observer) { + try { + if (bgcolor != null) { + contentStream.setNonStrokingColor(colorMapper.mapColor(contentStream, bgcolor)); + walkShape(new Rectangle(x, y, width, height)); + contentStream.fill(); + } + return drawImage(img, x, y, img.getWidth(observer), img.getHeight(observer), observer); + } catch (IOException e) { + throw new PdfBoxGraphics2dException(e); + } + } + + @Override + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, + int sx2, int sy2, ImageObserver observer) { + return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy2, sx2, sy2, null, observer); + } + + @Override + public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { + checkNoCopyActive(); + AffineTransform tf = new AffineTransform(); + tf.concatenate(baseTransform); + tf.concatenate(transform); + if (xform != null) { + tf.concatenate((AffineTransform) xform.clone()); + } + PDImageXObject pdImage = imageEncoder.encodeImage(document, contentStream, img); + try { + contentStreamSaveState(); + int imgHeight = img.getHeight(obs); + tf.translate(0, imgHeight); + tf.scale(1, -1); + contentStream.transform(new Matrix(tf)); + Object keyInterpolation = renderingHints.get(RenderingHints.KEY_INTERPOLATION); + if (RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR.equals(keyInterpolation)) { + pdImage.setInterpolate(false); + } + if (composite != null) { + applyPaint(null); + } + contentStream.drawImage(pdImage, 0, 0, img.getWidth(obs), imgHeight); + contentStreamRestoreState(); + } catch (IOException e) { + throw new PdfBoxGraphics2dException(e); + } + return true; + } + + @Override + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, + int sx2, int sy2, Color bgcolor, ImageObserver observer) { + try { + contentStreamSaveState(); + int width = dx2 - dx1; + int height = dy2 - dy1; + walkShape(new Rectangle2D.Double(dx1, dy1, width, height)); + contentStream.clip(); + if (bgcolor != null) { + contentStream.setNonStrokingColor(colorMapper.mapColor(contentStream, bgcolor)); + walkShape(new Rectangle(dx1, dy1, width, height)); + contentStream.fill(); + } + AffineTransform tf = new AffineTransform(); + tf.translate(dx1, dy1); + float imgWidth = img.getWidth(observer); + float imgHeight = img.getHeight(observer); + tf.scale((float) width / imgWidth, (float) height / imgHeight); + tf.translate(-sx1, -sy1); + tf.scale((sx2 - sx1) / imgWidth, (sy2 - sy1) / imgHeight); + drawImage(img, tf, observer); + contentStreamRestoreState(); + return true; + } catch (IOException e) { + throw new PdfBoxGraphics2dException(e); + } + } + + @Override + public void drawString(AttributedCharacterIterator iterator, float x, float y) { + if (paint == null) { + return; + } + try { + contentStreamSaveState(); + if (fontTextDrawer.canDrawText((AttributedCharacterIterator) iterator.clone(), fontDrawerEnv)) { + drawStringUsingText(iterator, x, y); + } else { + drawStringUsingShapes(iterator, x, y); + } + contentStreamRestoreState(); + } catch (IOException | FontFormatException e) { + throw new PdfBoxGraphics2dException(e); + } + } + + @Override public void drawGlyphVector(GlyphVector g, float x, float y) { checkNoCopyActive(); AffineTransform transformOrig = (AffineTransform) transform.clone(); @@ -745,34 +530,21 @@ public class PdfBoxGraphics2D extends Graphics2D { transform = transformOrig; } + @Override public void fill(Shape s) { checkNoCopyActive(); - - /* - * Don't try to draw with no paint, just ignore that. - */ - if (paint == null) + if (paint == null) { return; - + } try { contentStreamSaveState(); - Shape shapeToFill = drawControl.transformShapeBeforeFill(s, drawControlEnv); - if (shapeToFill != null) { boolean useEvenOdd = walkShape(shapeToFill); PDShading shading = applyPaint(shapeToFill); if (shading != null) { - /* - * NB: the shading fill doesn't work with shapes with zero or negative - * dimensions (width and/or height): in these cases a normal fill is used - */ Rectangle2D r2d = s.getBounds2D(); if ((r2d.getWidth() <= 0) || (r2d.getHeight() <= 0)) { - /* - * But we apply the shading as color, we usually want to avoid that because it - * creates another nested XForm for that ... - */ applyShadingAsColor(shading); fill(useEvenOdd); } else { @@ -784,121 +556,72 @@ public class PdfBoxGraphics2D extends Graphics2D { } hasPathOnStream = false; } - drawControl.afterShapeFill(s, drawControlEnv); - contentStreamRestoreState(); } catch (IOException e) { - throwException(e); + throw new PdfBoxGraphics2dException(e); } } - private void fill(boolean useEvenOdd) throws IOException { - if (useEvenOdd) - contentStream.fillEvenOdd(); - else - contentStream.fill(); - } - - private void applyShadingAsColor(PDShading shading) throws IOException { - /* - * If the paint has a shading we must create a tiling pattern and set that as - * stroke color... - */ - PDTilingPattern pattern = new PDTilingPattern(); - pattern.setPaintType(PDTilingPattern.PAINT_COLORED); - pattern.setTilingType(PDTilingPattern.TILING_CONSTANT_SPACING_FASTER_TILING); - PDRectangle anchorRect = bbox; - pattern.setBBox(anchorRect); - pattern.setXStep(anchorRect.getWidth()); - pattern.setYStep(anchorRect.getHeight()); - - PDAppearanceStream appearance = new PDAppearanceStream(this.document); - appearance.setResources(pattern.getResources()); - appearance.setBBox(pattern.getBBox()); - - PDPageContentStream imageContentStream = new PDPageContentStream(document, appearance, - ((COSStream) pattern.getCOSObject()).createOutputStream()); - imageContentStream.addRect(0, 0, anchorRect.getWidth(), anchorRect.getHeight()); - imageContentStream.clip(); - imageContentStream.shadingFill(shading); - imageContentStream.close(); - - PDColorSpace patternCS1 = new PDPattern(null); - COSName tilingPatternName = xFormObject.getResources().add(pattern); - PDColor patternColor = new PDColor(tilingPatternName, patternCS1); - - contentStream.setNonStrokingColor(patternColor); - contentStream.setStrokingColor(patternColor); - } - - private PDShading applyPaint(Shape shapeToDraw) throws IOException { - return applyPaint(paint, shapeToDraw); - } - - private final PaintEnvImpl paintEnv = new PaintEnvImpl(); - - private PDShading applyPaint(Paint paintToApply, Shape shapeToDraw) throws IOException { - AffineTransform tf = new AffineTransform(baseTransform); - tf.concatenate(transform); - paintEnv.shapeToDraw = shapeToDraw; - return paintApplier.applyPaint(paintToApply, contentStream, tf, paintEnv); - } - + @Override public boolean hit(Rectangle rect, Shape s, boolean onStroke) { return false; } + @Override public GraphicsConfiguration getDeviceConfiguration() { return null; } + @Override public void setComposite(Composite comp) { composite = comp; } + @Override public void setPaint(Paint paint) { this.paint = paint; } + @Override public void setStroke(Stroke stroke) { this.stroke = stroke; } - private Map renderingHints = new HashMap(); - + @Override public void setRenderingHint(Key hintKey, Object hintValue) { renderingHints.put(hintKey, hintValue); } + @Override public Object getRenderingHint(Key hintKey) { return renderingHints.get(hintKey); } + @Override public void setRenderingHints(Map hints) { hints.clear(); addRenderingHints(hints); } @SuppressWarnings("unchecked") + @Override public void addRenderingHints(Map hints) { renderingHints.putAll((Map) hints); - } + @Override public RenderingHints getRenderingHints() { return new RenderingHints(renderingHints); } /** * Creates a copy of this graphics object. Please call {@link #dispose()} always - * on the copy after you have finished drawing with it.
- *
+ * on the copy after you have finished drawing with it. * Never draw both in this copy and its parent graphics at the same time, as * they all write to the same content stream. This will create a broken PDF * content stream. You should get an {@link IllegalStateException} if - * you do so, but better just don't try.
- *
+ * you do so, but better just don't try. * The copy allows you to have different transforms, paints, etc. than the * parent graphics context without affecting the parent. You may also call * create() on a copy, but always remember to call {@link #dispose()} in reverse @@ -906,6 +629,7 @@ public class PdfBoxGraphics2D extends Graphics2D { * * @return a copy of this Graphics. */ + @Override public PdfBoxGraphics2D create() { try { return new PdfBoxGraphics2D(this); @@ -914,72 +638,84 @@ public class PdfBoxGraphics2D extends Graphics2D { } } + @Override public PdfBoxGraphics2D create(int x, int y, int width, int height) { return (PdfBoxGraphics2D) super.create(x, y, width, height); } + @Override public void translate(int x, int y) { transform.translate(x, y); } + @Override public Color getColor() { - if (paint instanceof Color) + if (paint instanceof Color) { return (Color) paint; + } return null; } + @Override public void setColor(Color color) { this.paint = color; } + @Override public void setPaintMode() { xorColor = null; } /** - * XOR Mode is currently not implemented as it's not possible in PDF. This mode - * is ignored. + * XOR Mode is currently not implemented as it's not possible in PDF. This mode is ignored. * * @param c1 the XORMode Color */ + @Override public void setXORMode(Color c1) { xorColor = c1; } + @Override public Font getFont() { return font; } + @Override public void setFont(Font font) { this.font = font; } + @Override public FontMetrics getFontMetrics(Font f) { try { return fontTextDrawer.getFontMetrics(f, fontDrawerEnv); - } catch (IOException e) { - throw new RuntimeException(e); - } catch (FontFormatException e) { + } catch (IOException | FontFormatException e) { throw new RuntimeException(e); } } + @Override public Rectangle getClipBounds() { Shape clip = getClip(); - if (clip != null) + if (clip != null) { return clip.getBounds(); + } return null; } + @Override public void clipRect(int x, int y, int width, int height) { Rectangle2D rect = new Rectangle2D.Double(x, y, width, height); clip(rect); } + @Override public void setClip(int x, int y, int width, int height) { setClip(new Rectangle(x, y, width, height)); } + @Override public Shape getClip() { try { return transform.createInverse().createTransformedShape(clipShape); @@ -988,26 +724,400 @@ public class PdfBoxGraphics2D extends Graphics2D { } } + @Override public void setClip(Shape clip) { checkNoCopyActive(); this.clipShape = transform.createTransformedShape(clip); - /* - * Clip on the content stream - */ try { contentStreamRestoreState(); contentStreamSaveState(); - /* - * clip can be null, only set a clipping if not null - */ if (clip != null) { internalClip(walkShape(clip)); } } catch (IOException e) { - throwException(e); + throw new PdfBoxGraphics2dException(e); } } + @Override + public void copyArea(int x, int y, int width, int height, int dx, int dy) { + throw new UnsupportedOperationException("copyArea() not implemented"); + } + + @Override + public void drawLine(int x1, int y1, int x2, int y2) { + draw(new Line2D.Double(x1, y1, x2, y2)); + } + + @Override + public void fillRect(int x, int y, int width, int height) { + fill(new Rectangle(x, y, width, height)); + } + + @Override + public void clearRect(int x, int y, int width, int height) { + Paint p = paint; + paint = backgroundColor; + fillRect(x, y, width, height); + paint = p; + } + + @Override + public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { + draw(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight)); + } + + @Override + public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { + fill(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight)); + } + + @Override + public void drawOval(int x, int y, int width, int height) { + draw(new Ellipse2D.Double(x, y, width, height)); + } + + @Override + public void fillOval(int x, int y, int width, int height) { + fill(new Ellipse2D.Double(x, y, width, height)); + } + + @Override + public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { + draw(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN)); + } + + @Override + public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { + fill(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.PIE)); + } + + @Override + public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { + Path2D.Double path = new Path2D.Double(); + path.moveTo(xPoints[0], yPoints[0]); + for (int i = 1; i < nPoints; i++) + path.lineTo(xPoints[i], yPoints[i]); + draw(path); + } + + @Override + public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { + draw(new Polygon(xPoints, yPoints, nPoints)); + } + + @Override + public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { + fill(new Polygon(xPoints, yPoints, nPoints)); + } + + @Override + public void translate(double tx, double ty) { + checkNoCopyActive(); + transform.translate(tx, ty); + } + + @Override + public void rotate(double theta) { + checkNoCopyActive(); + transform.rotate(theta); + } + + @Override + public void rotate(double theta, double x, double y) { + checkNoCopyActive(); + transform.rotate(theta, x, y); + } + + @Override + public void scale(double sx, double sy) { + checkNoCopyActive(); + transform.scale(sx, sy); + } + + @Override + public void shear(double shx, double shy) { + checkNoCopyActive(); + transform.shear(shx, shy); + } + + @Override + public void transform(AffineTransform Tx) { + checkNoCopyActive(); + transform.concatenate(Tx); + } + + @Override + public void setTransform(AffineTransform Tx) { + checkNoCopyActive(); + transform = new AffineTransform(); + transform.concatenate(Tx); + } + + @Override + public AffineTransform getTransform() { + return (AffineTransform) transform.clone(); + } + + @Override + public Paint getPaint() { + return paint; + } + + @Override + public Composite getComposite() { + return composite; + } + + @Override + public void setBackground(Color color) { + backgroundColor = color; + } + + @Override + public Color getBackground() { + return backgroundColor; + } + + @Override + public Stroke getStroke() { + return stroke; + } + + @Override + public void clip(Shape shape) { + Shape clip = getClip(); + if (clip == null) { + setClip(shape); + } else { + Area area = new Area(clip); + area.intersect(new Area(shape)); + setClip(area); + } + } + + @Override + public FontRenderContext getFontRenderContext() { + calcGfx.addRenderingHints(renderingHints); + return calcGfx.getFontRenderContext(); + } + + /** + * @return the PDAppearanceStream which resulted in this graphics + */ + public PDFormXObject getXFormObject() { + if (document != null) { + throw new IllegalStateException("You can only get the XformObject after you disposed the Graphics2D!"); + } + if (copyInfo != null) { + throw new IllegalStateException("You can not get the Xform stream from the copy"); + } + return xFormObject; + } + + /** + * Sometimes the users of {@link #create()} don't correctly {@link #dispose()} + * the child graphics they create. And you may not always be able to fix this + * uses, as it may be in some 3rdparty library. In this case this method can + * help you. It will cleanup all dangling child graphics. The child graphics can + * not be used after that. This method is a workaround for a buggy old code. You + * should only use it if you have to. + * Note: You can only call this method on the "main" graphics, not on a child + * created with {@link #create()} + */ + public void disposeDanglingChildGraphics() { + if (copyInfo != null) + throw new IllegalStateException( + "Don't call disposeDanglingChildGraphics() on a child!"); + disposeCopies(copyList); + } + + /** + * Set a new color mapper. + * + * @param colorMapper the color mapper which maps Color to PDColor. + */ + public void setColorMapper(ColorMapper colorMapper) { + this.colorMapper = colorMapper; + } + + /** + * Set a new image encoder + * + * @param imageEncoder the image encoder, which encodes a image as PDImageXForm. + */ + public void setImageEncoder(ImageEncoder imageEncoder) { + this.imageEncoder = imageEncoder; + } + + /** + * Set a new paint applier. You should always derive your custom paint applier + * from the {@link PaintApplier} and just extend the paint + * mapping for custom paint. + * If the paint you map is a paint from a standard library and you can implement + * the mapping using reflection please feel free to send a pull request to + * extend the default paint mapper. + * + * @param paintApplier the paint applier responsible for mapping the paint correctly + */ + public void setPaintApplier(PaintApplier paintApplier) { + this.paintApplier = paintApplier; + } + + /** + * Set a new draw control. This allows you to influence fill() and draw() + * operations. drawString() is only influence if the text is drawn as vector + * shape. + * + * @param drawControl the draw control + */ + public void setDrawControl(DrawControl drawControl) { + this.drawControl = drawControl; + } + + /** + * Set an optional text drawer. By default, all text is vectorized and drawn + * using vector shapes. To embed fonts into a PDF file it is necessary to have + * the underlying TTF file. The java.awt.Font class does not provide that. The + * FontTextDrawer must perform the java.awt.Font <=> PDFont mapping and + * also must perform the text layout. If it can not map the text or font + * correctly, the font drawing falls back to vectoring the text. + * + * @param fontTextDrawer The text drawer, which can draw text using fonts + */ + public void setFontTextDrawer(FontTextDrawer fontTextDrawer) { + this.fontTextDrawer = fontTextDrawer; + } + + /** + * Set an internal flag that some path - which may be added from the paint + * applyer to the content stream or by walkShape() - is on the content stream. + * We can then safely clip() if there is a path on the content stream. + */ + void markPathIsOnStream() { + hasPathOnStream = true; + } + + private void fill(boolean useEvenOdd) throws IOException { + if (useEvenOdd) { + contentStream.fillEvenOdd(); + } else { + contentStream.fill(); + } + } + + private void drawStringUsingShapes(AttributedCharacterIterator iterator, float x, float y) { + Stroke originalStroke = stroke; + Paint originalPaint = paint; + TextLayout textLayout = new TextLayout(iterator, getFontRenderContext()); + textLayout.draw(this, x, y); + paint = originalPaint; + stroke = originalStroke; + } + + private void drawStringUsingText(AttributedCharacterIterator iterator, float x, float y) + throws IOException, FontFormatException { + contentStreamSaveState(); + AffineTransform tf = new AffineTransform(baseTransform); + tf.concatenate(transform); + tf.translate(x, y); + contentStream.transform(new Matrix(tf)); + fontTextDrawer.drawText(iterator, fontDrawerEnv); + contentStreamRestoreState(); + } + + private void contentStreamSaveState() throws IOException { + saveCounter++; + contentStream.saveGraphicsState(); + } + + private void contentStreamRestoreState() throws IOException { + if (saveCounter == 0) { + throw new IllegalStateException("Internal save/restore state error. Should never happen."); + } + saveCounter--; + contentStream.restoreGraphicsState(); + } + + private void applyShadingAsColor(PDShading shading) throws IOException { + PDTilingPattern pattern = new PDTilingPattern(); + pattern.setPaintType(PDTilingPattern.PAINT_COLORED); + pattern.setTilingType(PDTilingPattern.TILING_CONSTANT_SPACING_FASTER_TILING); + PDRectangle anchorRect = bbox; + pattern.setBBox(anchorRect); + pattern.setXStep(anchorRect.getWidth()); + pattern.setYStep(anchorRect.getHeight()); + PDAppearanceStream appearance = new PDAppearanceStream(this.document); + appearance.setResources(pattern.getResources()); + appearance.setBBox(pattern.getBBox()); + PDPageContentStream imageContentStream = new PDPageContentStream(document, appearance, + ((COSStream) pattern.getCOSObject()).createOutputStream()); + imageContentStream.addRect(0, 0, anchorRect.getWidth(), anchorRect.getHeight()); + imageContentStream.clip(); + imageContentStream.shadingFill(shading); + imageContentStream.close(); + PDColorSpace patternCS1 = new PDPattern(null); + COSName tilingPatternName = xFormObject.getResources().add(pattern); + PDColor patternColor = new PDColor(tilingPatternName, patternCS1); + contentStream.setNonStrokingColor(patternColor); + contentStream.setStrokingColor(patternColor); + } + + private PDShading applyPaint(Shape shapeToDraw) throws IOException { + return applyPaint(paint, shapeToDraw); + } + + private PDShading applyPaint(Paint paintToApply, Shape shapeToDraw) throws IOException { + AffineTransform tf = new AffineTransform(baseTransform); + tf.concatenate(transform); + paintEnv.shapeToDraw = shapeToDraw; + return paintApplier.applyPaint(paintToApply, contentStream, tf, paintEnv); + } + + /** + * Walk the path and return true if we need to use the even odd winding rule. + * + * @return true if we need to use the even odd winding rule + */ + private boolean walkShape(Shape clip) throws IOException { + checkNoCopyActive(); + AffineTransform tf = new AffineTransform(baseTransform); + tf.concatenate(transform); + PathIterator pi = clip.getPathIterator(tf); + float[] coords = new float[6]; + while (!pi.isDone()) { + int segment = pi.currentSegment(coords); + switch (segment) { + case PathIterator.SEG_MOVETO: + if (isFinite(coords, 2)) { + contentStream.moveTo(coords[0], coords[1]); + } + break; + case PathIterator.SEG_LINETO: + if (isFinite(coords, 2)) { + contentStream.lineTo(coords[0], coords[1]); + } + break; + case PathIterator.SEG_QUADTO: + if (isFinite(coords, 4)) { + contentStream.curveTo1(coords[0], coords[1], coords[2], coords[3]); + } + break; + case PathIterator.SEG_CUBICTO: + if (isFinite(coords, 6)) { + contentStream.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); + } + break; + case PathIterator.SEG_CLOSE: + contentStream.closePath(); + break; + } + pi.next(); + } + markPathIsOnStream(); + return pi.getWindingRule() == PathIterator.WIND_EVEN_ODD; + } + /** * Perform a clip, but only if we really have an active clipping path * @@ -1015,14 +1125,42 @@ public class PdfBoxGraphics2D extends Graphics2D { */ void internalClip(boolean useEvenOdd) throws IOException { if (hasPathOnStream) { - if (useEvenOdd) + if (useEvenOdd) { contentStream.clipEvenOdd(); - else + } else { contentStream.clip(); + } hasPathOnStream = false; } } + private void checkNoCopyActive() { + if (copyList.size() > 0) + throw new IllegalStateException("Don't use the main context as long as a copy is active! Child context is missing a .dispose() call\n" + + gatherDebugCopyInfo(this)); + } + + private static String gatherDebugCopyInfo(PdfBoxGraphics2D gfx) { + StringBuilder sb = new StringBuilder(); + if (!gfx.copyList.isEmpty()) { + for (CopyInfo copyInfo : gfx.copyList) { + sb.append("# Dangling Child").append(copyInfo.toString()).append("\n"); + } + } + while (gfx != null) { + if (gfx.copyList.isEmpty()) { + sb.append("* Last Child\n"); + } else { + sb.append("- Parent with ").append(gfx.copyList.size()).append(" childs.\n"); + } + if (gfx.copyInfo == null) { + break; + } + gfx = gfx.copyInfo.sourceGfx; + } + return sb.toString(); + } + /** * Float#isFinite() is JDK 8+. We just copied the trivial implementation here. * When we require JDK 8+ we can just drop this method and replace it bei @@ -1036,248 +1174,25 @@ public class PdfBoxGraphics2D extends Graphics2D { * @return true when all required values are finite */ private static boolean isFinite(float[] coords, int count) { - for (int i = 0; i < count; i++) - if (!isFinite(coords[i])) + for (int i = 0; i < count; i++) { + if (!isFinite(coords[i])) { return false; + } + } return true; } - /** - * Do we currently have an active path on the content stream, which has not been - * closed? - *

- * We need this flag to avoid to clip twice if both the plaint applyer needs to - * clip and we have some clipping. If at the end we try to clip with an empty - * path, then Acrobat Reader does not like that and draws nothing. - */ - private boolean hasPathOnStream = false; - - /** - * Set an internal flag that some path - which may be added from the paint - * applyer to the content stream or by walkShape() - is on the content stream. - * We can then safely clip() if there is a path on the content stream. - */ - void markPathIsOnStream() { - hasPathOnStream = true; - } - - /** - * Walk the path and return true if we need to use the even odd winding rule. - * - * @return true if we need to use the even odd winding rule - */ - private boolean walkShape(Shape clip) throws IOException { - checkNoCopyActive(); - - AffineTransform tf = new AffineTransform(baseTransform); - tf.concatenate(transform); - PathIterator pi = clip.getPathIterator(tf); - float[] coords = new float[6]; - while (!pi.isDone()) { - int segment = pi.currentSegment(coords); - switch (segment) { - case PathIterator.SEG_MOVETO: - if (isFinite(coords, 2)) - contentStream.moveTo(coords[0], coords[1]); - break; - case PathIterator.SEG_LINETO: - if (isFinite(coords, 2)) - contentStream.lineTo(coords[0], coords[1]); - break; - case PathIterator.SEG_QUADTO: - if (isFinite(coords, 4)) - contentStream.curveTo1(coords[0], coords[1], coords[2], coords[3]); - break; - case PathIterator.SEG_CUBICTO: - if (isFinite(coords, 6)) - contentStream.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], - coords[5]); - break; - case PathIterator.SEG_CLOSE: - contentStream.closePath(); - break; - } - pi.next(); - } - markPathIsOnStream(); - return pi.getWindingRule() == PathIterator.WIND_EVEN_ODD; - } - - private void checkNoCopyActive() { - /* - * As long as a copy is in use you are not allowed to do anything here - */ - if (copyList.size() > 0) - throw new IllegalStateException( - "Don't use the main context as long as a copy is active! Child context is missing a .dispose() call. \n" - + gatherDebugCopyInfo(this)); - } - - private static String gatherDebugCopyInfo(PdfBoxGraphics2D gfx) { - StringBuilder sb = new StringBuilder(); - if (!gfx.copyList.isEmpty()) { - for (CopyInfo copyInfo : gfx.copyList) { - sb.append("# Dangling Child").append(copyInfo.toString()).append("\n"); - } - } - - while (gfx != null) { - if (gfx.copyList.isEmpty()) { - sb.append("* Last Child\n"); - } else { - sb.append("- Parent with ").append(gfx.copyList.size()).append(" childs.\n"); - } - if (gfx.copyInfo == null) - break; - gfx = gfx.copyInfo.sourceGfx; - } - return sb.toString(); - } - - private void throwException(Exception e) { - throw new RuntimeException(e); - } - - public void copyArea(int x, int y, int width, int height, int dx, int dy) { - /* - * Sorry, cant do that :( - */ - throw new IllegalStateException("copyArea() not possible!"); - } - - public void drawLine(int x1, int y1, int x2, int y2) { - draw(new Line2D.Double(x1, y1, x2, y2)); - } - - public void fillRect(int x, int y, int width, int height) { - fill(new Rectangle(x, y, width, height)); - } - - public void clearRect(int x, int y, int width, int height) { - Paint p = paint; - paint = backgroundColor; - fillRect(x, y, width, height); - paint = p; - } - - public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { - draw(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight)); - } - - public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { - fill(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight)); - } - - public void drawOval(int x, int y, int width, int height) { - draw(new Ellipse2D.Double(x, y, width, height)); - } - - public void fillOval(int x, int y, int width, int height) { - fill(new Ellipse2D.Double(x, y, width, height)); - } - - public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { - draw(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN)); - } - - public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { - fill(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.PIE)); - } - - public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { - Path2D.Double path = new Path2D.Double(); - path.moveTo(xPoints[0], yPoints[0]); - for (int i = 1; i < nPoints; i++) - path.lineTo(xPoints[i], yPoints[i]); - draw(path); - } - - public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { - draw(new Polygon(xPoints, yPoints, nPoints)); - } - - public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { - fill(new Polygon(xPoints, yPoints, nPoints)); - } - - public void translate(double tx, double ty) { - checkNoCopyActive(); - transform.translate(tx, ty); - } - - public void rotate(double theta) { - checkNoCopyActive(); - transform.rotate(theta); - } - - public void rotate(double theta, double x, double y) { - checkNoCopyActive(); - transform.rotate(theta, x, y); - } - - public void scale(double sx, double sy) { - checkNoCopyActive(); - transform.scale(sx, sy); - } - - public void shear(double shx, double shy) { - checkNoCopyActive(); - transform.shear(shx, shy); - } - - public void transform(AffineTransform Tx) { - checkNoCopyActive(); - transform.concatenate(Tx); - } - - public void setTransform(AffineTransform Tx) { - checkNoCopyActive(); - transform = new AffineTransform(); - transform.concatenate(Tx); - } - - public AffineTransform getTransform() { - return (AffineTransform) transform.clone(); - } - - public Paint getPaint() { - return paint; - } - - public Composite getComposite() { - return composite; - } - - public void setBackground(Color color) { - backgroundColor = color; - } - - public Color getBackground() { - return backgroundColor; - } - - public Stroke getStroke() { - return stroke; - } - - public void clip(Shape shape) { - Shape clip = getClip(); - if (clip == null) - setClip(shape); - else { - Area area = new Area(clip); - area.intersect(new Area(shape)); - setClip(area); + private static void disposeCopies(List cl) { + while (cl.size() > 0) { + CopyInfo copyInfo = cl.get(0); + disposeCopies(copyInfo.copy.copyList); + copyInfo.copy.dispose(); } } - public FontRenderContext getFontRenderContext() { - calcGfx.addRenderingHints(renderingHints); - return calcGfx.getFontRenderContext(); - } + private class PaintApplierEnvImpl implements PaintApplierEnv { - private class PaintEnvImpl implements IPaintEnv { - public Shape shapeToDraw; + private Shape shapeToDraw; @Override public Shape getShapeToDraw() { @@ -1319,4 +1234,18 @@ public class PdfBoxGraphics2D extends Graphics2D { return xorColor; } } + + private static class CopyInfo { + + private PdfBoxGraphics2D sourceGfx; + + private PdfBoxGraphics2D copy; + + private String creatingContextInfo; + + @Override + public String toString() { + return "CopyInfo{creatingContextInfo='" + creatingContextInfo + '\'' + '}'; + } + } } diff --git a/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/PdfBoxGraphics2dException.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/PdfBoxGraphics2dException.java new file mode 100644 index 0000000..94e0869 --- /dev/null +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/PdfBoxGraphics2dException.java @@ -0,0 +1,13 @@ +package org.xbib.graphics.io.pdfbox; + +@SuppressWarnings("serial") +public class PdfBoxGraphics2dException extends RuntimeException { + + public PdfBoxGraphics2dException(String message) { + super(message); + } + + public PdfBoxGraphics2dException(Throwable throwable) { + super(throwable); + } +} diff --git a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/RGBtoCMYKColorMapper.java b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/RGBtoCMYKColorMapper.java similarity index 73% rename from graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/RGBtoCMYKColorMapper.java rename to io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/RGBtoCMYKColorMapper.java index 938bdd5..d64bebc 100644 --- a/graphics2d-pdfbox/src/main/java/org/xbib/graphics/graphics2d/pdfbox/RGBtoCMYKColorMapper.java +++ b/io-pdfbox/src/main/java/org/xbib/graphics/io/pdfbox/RGBtoCMYKColorMapper.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.PDDocument; @@ -20,12 +20,14 @@ import java.io.OutputStream; pdfBoxGraphics2D.setColorMapper(colorMapper); Where icc_profile is an instance of java.awt.color.ICC_Profile that supports a CMYK - colorspace. For testing purposes, we're using ISOcoated_v2_300_bas.icc which ships + colorspace. For testing purposes, we're using ISOcoated_v2_300_bas.icc which ships with PDFBox. */ public class RGBtoCMYKColorMapper extends DefaultColorMapper { - ICC_ColorSpace icc_colorspace; - PDICCBased pdProfile; + + private final ICC_ColorSpace icc_colorspace; + + private final PDICCBased pdProfile; public RGBtoCMYKColorMapper(ICC_Profile icc_profile, PDDocument document) throws IOException { icc_colorspace = new ICC_ColorSpace(icc_profile); @@ -44,20 +46,13 @@ public class RGBtoCMYKColorMapper extends DefaultColorMapper { int[] rgbInts = {r, g, b}; float[] rgbFoats = rgbIntToFloat(rgbInts); float[] cmykFloats = icc_colorspace.fromRGB(rgbFoats); - - PDColor cmykColor = new PDColor(cmykFloats, pdProfile); - return cmykColor; + return new PDColor(cmykFloats, pdProfile); } public static float[] rgbIntToFloat(int[] rgbInts) { - // the input ints are in the range 0 to 255 - // the output floats need to be in the range 0.0 to 1.0 - float red = (float) rgbInts[0] / 255.0F; - float green = (float) rgbInts[1] / 255.0F; - float blue = (float) rgbInts[2] / 255.0F; - float[] rgbFloats = new float[]{red, green, blue}; - return rgbFloats; + float red = (float) rgbInts[0] / 255.0f; + float green = (float) rgbInts[1] / 255.0f; + float blue = (float) rgbInts[2] / 255.0f; + return new float[]{red, green, blue}; } - } - diff --git a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/DanglingGfxCaseTest.java b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/DanglingGfxCaseTest.java similarity index 96% rename from graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/DanglingGfxCaseTest.java rename to io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/DanglingGfxCaseTest.java index 60e98dc..a08d17c 100644 --- a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/DanglingGfxCaseTest.java +++ b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/DanglingGfxCaseTest.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; @@ -8,6 +8,7 @@ import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; import org.apache.pdfbox.util.Matrix; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.xbib.graphics.io.pdfbox.PdfBoxGraphics2D; import java.awt.Color; import java.io.File; diff --git a/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/DefaultFontTextDrawerFontsTest.java b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/DefaultFontTextDrawerFontsTest.java new file mode 100644 index 0000000..e5029fa --- /dev/null +++ b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/DefaultFontTextDrawerFontsTest.java @@ -0,0 +1,65 @@ +package org.xbib.graphics.io.pdfbox; + +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.junit.jupiter.api.Test; + +import java.awt.Font; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class DefaultFontTextDrawerFontsTest { + + @Test + public void testFontStyleMatching() { + Font anyFont = Font.decode("Dialog"); + Font anyFontBold = anyFont.deriveFont(Font.BOLD); + Font anyFontItalic = anyFont.deriveFont(Font.ITALIC); + Font anyFontBoldItalic = anyFont.deriveFont(Font.BOLD | Font.ITALIC); + + assertEquals(PDType1Font.COURIER, DefaultFontTextDrawerFonts.chooseMatchingCourier(anyFont)); + assertEquals(PDType1Font.COURIER_BOLD, + DefaultFontTextDrawerFonts.chooseMatchingCourier(anyFontBold)); + assertEquals(PDType1Font.COURIER_OBLIQUE, + DefaultFontTextDrawerFonts.chooseMatchingCourier(anyFontItalic)); + assertEquals(PDType1Font.COURIER_BOLD_OBLIQUE, + DefaultFontTextDrawerFonts.chooseMatchingCourier(anyFontBoldItalic)); + + assertEquals(PDType1Font.HELVETICA, + DefaultFontTextDrawerFonts.chooseMatchingHelvetica(anyFont)); + assertEquals(PDType1Font.HELVETICA_BOLD, + DefaultFontTextDrawerFonts.chooseMatchingHelvetica(anyFontBold)); + assertEquals(PDType1Font.HELVETICA_OBLIQUE, + DefaultFontTextDrawerFonts.chooseMatchingHelvetica(anyFontItalic)); + assertEquals(PDType1Font.HELVETICA_BOLD_OBLIQUE, + DefaultFontTextDrawerFonts.chooseMatchingHelvetica(anyFontBoldItalic)); + + assertEquals(PDType1Font.TIMES_ROMAN, DefaultFontTextDrawerFonts.chooseMatchingTimes(anyFont)); + assertEquals(PDType1Font.TIMES_BOLD, + DefaultFontTextDrawerFonts.chooseMatchingTimes(anyFontBold)); + assertEquals(PDType1Font.TIMES_ITALIC, + DefaultFontTextDrawerFonts.chooseMatchingTimes(anyFontItalic)); + assertEquals(PDType1Font.TIMES_BOLD_ITALIC, + DefaultFontTextDrawerFonts.chooseMatchingTimes(anyFontBoldItalic)); + } + + @Test + public void testDefaultFontMapping() { + assertEquals(PDType1Font.HELVETICA, + DefaultFontTextDrawerFonts.mapDefaultFonts(Font.decode(Font.DIALOG))); + assertEquals(PDType1Font.HELVETICA, + DefaultFontTextDrawerFonts.mapDefaultFonts(Font.decode(Font.DIALOG_INPUT))); + assertEquals(PDType1Font.HELVETICA, + DefaultFontTextDrawerFonts.mapDefaultFonts(Font.decode("Arial"))); + assertEquals(PDType1Font.COURIER, + DefaultFontTextDrawerFonts.mapDefaultFonts(Font.decode(Font.MONOSPACED))); + assertEquals(PDType1Font.TIMES_ROMAN, + DefaultFontTextDrawerFonts.mapDefaultFonts(Font.decode(Font.SERIF))); + assertEquals(PDType1Font.ZAPF_DINGBATS, + DefaultFontTextDrawerFonts.mapDefaultFonts(Font.decode("Dingbats"))); + assertEquals(PDType1Font.SYMBOL, + DefaultFontTextDrawerFonts.mapDefaultFonts(Font.decode("Symbol"))); + assertNull(DefaultFontTextDrawerFonts.mapDefaultFonts(Font.decode("Georgia"))); + } + +} diff --git a/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/FontTest.java b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/FontTest.java new file mode 100644 index 0000000..8ca52cc --- /dev/null +++ b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/FontTest.java @@ -0,0 +1,23 @@ +package org.xbib.graphics.io.pdfbox; + +import org.junit.jupiter.api.Test; + +import java.awt.Color; +import java.awt.Font; +import java.awt.FontFormatException; +import java.io.IOException; + +public class FontTest extends PdfBoxGraphics2DTestBase { + + @Test + public void testAntonioFont() throws IOException, FontFormatException { + final Font antonioRegular = Font.createFont(Font.TRUETYPE_FONT, + PdfBoxGraphics2dTest.class.getResourceAsStream("antonio/Antonio-Regular.ttf")) + .deriveFont(15f); + exportGraphic("fonts", "antonio", gfx -> { + gfx.setColor(Color.BLACK); + gfx.setFont(antonioRegular); + gfx.drawString("Für älter österlich, Umlauts are not always fun.", 10, 50); + }); + } +} diff --git a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/FontWidthDiscrepancyTest.java b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/FontWidthDiscrepancyTest.java similarity index 98% rename from graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/FontWidthDiscrepancyTest.java rename to io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/FontWidthDiscrepancyTest.java index 4ef3a88..9031fd5 100644 --- a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/FontWidthDiscrepancyTest.java +++ b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/FontWidthDiscrepancyTest.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.font.PDFont; diff --git a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/MultiPageTest.java b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/MultiPageTest.java similarity index 99% rename from graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/MultiPageTest.java rename to io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/MultiPageTest.java index 6ac7c4b..20087bb 100644 --- a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/MultiPageTest.java +++ b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/MultiPageTest.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; @@ -31,6 +31,7 @@ import org.jfree.data.xy.XYSeriesCollection; //import org.jfree.ui.RectangleEdge; //import org.jfree.util.TableOrder; import org.junit.jupiter.api.Test; +import org.xbib.graphics.io.pdfbox.PdfBoxGraphics2D; import java.awt.Color; import java.awt.Font; diff --git a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/PdfBoxGraphics2DTestBase.java b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/PdfBoxGraphics2DTestBase.java similarity index 89% rename from graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/PdfBoxGraphics2DTestBase.java rename to io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/PdfBoxGraphics2DTestBase.java index 20999cb..c33bc5d 100644 --- a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/PdfBoxGraphics2DTestBase.java +++ b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/PdfBoxGraphics2DTestBase.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import javax.imageio.ImageIO; import org.apache.pdfbox.pdmodel.PDDocument; @@ -6,7 +6,6 @@ import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.font.PDFont; -import org.apache.pdfbox.pdmodel.font.PDFontFactory; import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; import org.apache.pdfbox.util.Matrix; @@ -29,17 +28,14 @@ class PdfBoxGraphics2DTestBase { PDFont pdArial = PDType1Font.HELVETICA; File parentDir = new File("build/test/" + dir); parentDir.mkdirs(); - BufferedImage image = new BufferedImage(400, 400, BufferedImage.TYPE_4BYTE_ABGR); Graphics2D imageGraphics = image.createGraphics(); exporter.draw(imageGraphics); imageGraphics.dispose(); ImageIO.write(image, "PNG", new File(parentDir, name + ".png")); - for (Mode m : Mode.values()) { PDPage page = new PDPage(PDRectangle.A4); document.addPage(page); - PDPageContentStream contentStream = new PDPageContentStream(document, page); PdfBoxGraphics2D pdfBoxGraphics2D = new PdfBoxGraphics2D(document, 400, 400); DefaultFontTextDrawer fontTextDrawer = null; @@ -56,12 +52,12 @@ class PdfBoxGraphics2DTestBase { registerFots(fontTextDrawer); break; case DefaultFontText: { - fontTextDrawer = new DefaultFontTextDrawerDefaultFonts(); + fontTextDrawer = new DefaultFontTextDrawerFonts(); registerFots(fontTextDrawer); break; } case ForceFontText: - fontTextDrawer = new DefaultFontTextForcedDrawer(); + fontTextDrawer = new DefaultFontTextDrawerForce(); registerFots(fontTextDrawer); fontTextDrawer.registerFont("Arial", pdArial); break; @@ -93,10 +89,8 @@ class PdfBoxGraphics2DTestBase { } private void registerFots(DefaultFontTextDrawer fontTextDrawer) { - fontTextDrawer.registerFont(new File( - "src/test/resources/org/xbib/graphics/graphics2d/pdfbox/DejaVuSerifCondensed.ttf")); - fontTextDrawer.registerFont(new File( - "src/test/resources/org/xbib/graphics/graphics2d/pdfbox/antonio/Antonio-Regular.ttf")); + fontTextDrawer.registerFont(new File("src/test/resources/org/xbib/graphics/io/pdfbox/DejaVuSerifCondensed.ttf")); + fontTextDrawer.registerFont(new File("src/test/resources/org/xbib/graphics/io/pdfbox/antonio/Antonio-Regular.ttf")); } interface GraphicsExporter { diff --git a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/PdfBoxGraphics2dTest.java b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/PdfBoxGraphics2dTest.java similarity index 99% rename from graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/PdfBoxGraphics2dTest.java rename to io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/PdfBoxGraphics2dTest.java index 2a4c6c4..d29798c 100644 --- a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/PdfBoxGraphics2dTest.java +++ b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/PdfBoxGraphics2dTest.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import javax.imageio.ImageIO; import javax.imageio.ImageReader; @@ -256,9 +256,7 @@ public class PdfBoxGraphics2dTest extends PdfBoxGraphics2DTestBase { as1.addAttribute(TextAttribute.BACKGROUND, Color.LIGHT_GRAY, 12, 19); as1.addAttribute(TextAttribute.FONT, font2, 20, 28); as1.addAttribute(TextAttribute.LIGATURES, TextAttribute.LIGATURES_ON, 20, 28); - as1.addAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON, 20, - 28); - + as1.addAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON, 20, 28); gfx.drawString(as1.getIterator(), 15, 160); // Hello World - in arabic and hebrew @@ -278,5 +276,4 @@ public class PdfBoxGraphics2dTest extends PdfBoxGraphics2DTestBase { }); } - } diff --git a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/PdfRerenderTest.java b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/PdfRerenderTest.java similarity index 97% rename from graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/PdfRerenderTest.java rename to io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/PdfRerenderTest.java index 1080f17..e8d44c9 100644 --- a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/PdfRerenderTest.java +++ b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/PdfRerenderTest.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; @@ -123,12 +123,12 @@ public class PdfRerenderTest { boolean insideOwnDraw = false; @Override - public void afterShapeFill(Shape shape, IDrawControlEnv env) { + public void afterShapeFill(Shape shape, DrawControlEnv env) { afterShapeDraw(shape, env); } @Override - public void afterShapeDraw(Shape shape, IDrawControlEnv env) { + public void afterShapeDraw(Shape shape, DrawControlEnv env) { if (insideOwnDraw) return; insideOwnDraw = true; diff --git a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/RenderSVGsTest.java b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/RenderSVGsTest.java similarity index 91% rename from graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/RenderSVGsTest.java rename to io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/RenderSVGsTest.java index ade6dc5..230032f 100644 --- a/graphics2d-pdfbox/src/test/java/org/xbib/graphics/graphics2d/pdfbox/RenderSVGsTest.java +++ b/io-pdfbox/src/test/java/org/xbib/graphics/io/pdfbox/RenderSVGsTest.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.graphics2d.pdfbox; +package org.xbib.graphics.io.pdfbox; import org.apache.batik.anim.dom.SAXSVGDocumentFactory; import org.apache.batik.bridge.BridgeContext; @@ -59,63 +59,44 @@ public class RenderSVGsTest extends PdfBoxGraphics2DTestBase { private void renderSVG(String name, final double scale) throws IOException { String uri = RenderSVGsTest.class.getResource(name).toString(); - - // create the document String parser = XMLResourceDescriptor.getXMLParserClassName(); SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser); Document document = f.createDocument(uri, RenderSVGsTest.class.getResourceAsStream(name)); - - // create the GVT UserAgent userAgent = new UserAgentAdapter(); DocumentLoader loader = new DocumentLoader(userAgent); BridgeContext bctx = new BridgeContext(userAgent, loader); bctx.setDynamicState(BridgeContext.STATIC); GVTBuilder builder = new GVTBuilder(); final GraphicsNode gvtRoot = builder.build(bctx, document); - - this.exportGraphic("svg", name.replace(".svg", ""), new GraphicsExporter() { - @Override - public void draw(Graphics2D gfx) { - gfx.scale(scale, scale); - gvtRoot.paint(gfx); - } + this.exportGraphic("svg", name.replace(".svg", ""), gfx -> { + gfx.scale(scale, scale); + gvtRoot.paint(gfx); }); } private void renderSVGCMYK(String name, final double scale) throws IOException { String uri = RenderSVGsTest.class.getResource(name).toString(); - - // create the document String parser = XMLResourceDescriptor.getXMLParserClassName(); SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser); Document document = f.createDocument(uri, RenderSVGsTest.class.getResourceAsStream(name)); - - // create the GVT UserAgent userAgent = new UserAgentAdapter(); DocumentLoader loader = new DocumentLoader(userAgent); BridgeContext bctx = new BridgeContext(userAgent, loader); bctx.setDynamicState(BridgeContext.STATIC); GVTBuilder builder = new GVTBuilder(); final GraphicsNode gvtRoot = builder.build(bctx, document); - PDDocument pdfDocument = new PDDocument(); - File parentDir = new File("build/test/svg"); parentDir.mkdirs(); - PDPage page = new PDPage(PDRectangle.A4); pdfDocument.addPage(page); - PDPageContentStream contentStream = new PDPageContentStream(pdfDocument, page); - PdfBoxGraphics2D pdfBoxGraphics2D = new PdfBoxGraphics2D(pdfDocument, 400, 400); - ICC_Profile icc_profile = ICC_Profile.getInstance(PDDocument.class.getResourceAsStream( "/org/apache/pdfbox/resources/icc/ISOcoated_v2_300_bas.icc")); DefaultColorMapper colorMapper = new RGBtoCMYKColorMapper(icc_profile, pdfDocument); pdfBoxGraphics2D.setColorMapper(colorMapper); - - FontTextDrawer fontTextDrawer = null; + FontTextDrawer fontTextDrawer; contentStream.beginText(); contentStream.setStrokingColor(0.0f, 0.0f, 0.0f, 1.0f); contentStream.setNonStrokingColor(0.0f, 0.0f, 0.0f, 1.0f); @@ -124,21 +105,16 @@ public class RenderSVGsTest extends PdfBoxGraphics2DTestBase { contentStream.showText("Mode: CMYK colorspace"); contentStream.endText(); fontTextDrawer = new DefaultFontTextDrawer(); - pdfBoxGraphics2D.setFontTextDrawer(fontTextDrawer); - pdfBoxGraphics2D.scale(scale, scale); gvtRoot.paint(pdfBoxGraphics2D); pdfBoxGraphics2D.dispose(); - PDFormXObject appearanceStream = pdfBoxGraphics2D.getXFormObject(); Matrix matrix = new Matrix(); matrix.translate(0, 300); contentStream.transform(matrix); contentStream.drawForm(appearanceStream); - contentStream.close(); - String baseName = name.substring(0, name.lastIndexOf('.')); pdfDocument.save(new File(parentDir, baseName + ".pdf")); pdfDocument.close(); diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/16bit-image1.png b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/16bit-image1.png similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/16bit-image1.png rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/16bit-image1.png diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/16bit-image2.png b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/16bit-image2.png similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/16bit-image2.png rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/16bit-image2.png diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/DejaVuSerifCondensed.ttf b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/DejaVuSerifCondensed.ttf similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/DejaVuSerifCondensed.ttf rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/DejaVuSerifCondensed.ttf diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/Italy-P3.jpg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/Italy-P3.jpg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/Italy-P3.jpg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/Italy-P3.jpg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/Rose-ProPhoto.jpg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/Rose-ProPhoto.jpg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/Rose-ProPhoto.jpg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/Rose-ProPhoto.jpg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/antonio/Antonio-Bold.ttf b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/antonio/Antonio-Bold.ttf similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/antonio/Antonio-Bold.ttf rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/antonio/Antonio-Bold.ttf diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/antonio/Antonio-Light.ttf b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/antonio/Antonio-Light.ttf similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/antonio/Antonio-Light.ttf rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/antonio/Antonio-Light.ttf diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/antonio/Antonio-Regular.ttf b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/antonio/Antonio-Regular.ttf similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/antonio/Antonio-Regular.ttf rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/antonio/Antonio-Regular.ttf diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/antonio/SIL Open Font License.txt b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/antonio/SIL Open Font License.txt similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/antonio/SIL Open Font License.txt rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/antonio/SIL Open Font License.txt diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/antonio_sample.pdf b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/antonio_sample.pdf similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/antonio_sample.pdf rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/antonio_sample.pdf diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/atmospheric-composiition.svg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/atmospheric-composiition.svg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/atmospheric-composiition.svg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/atmospheric-composiition.svg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/barChart.pdf b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/barChart.pdf similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/barChart.pdf rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/barChart.pdf diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/barChart.svg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/barChart.svg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/barChart.svg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/barChart.svg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/colortest.png b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/colortest.png similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/colortest.png rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/colortest.png diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/compuserver_msn_Ford_Focus.pdf b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/compuserver_msn_Ford_Focus.pdf similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/compuserver_msn_Ford_Focus.pdf rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/compuserver_msn_Ford_Focus.pdf diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/compuserver_msn_Ford_Focus.svg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/compuserver_msn_Ford_Focus.svg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/compuserver_msn_Ford_Focus.svg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/compuserver_msn_Ford_Focus.svg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/displayWebStats.svg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/displayWebStats.svg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/displayWebStats.svg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/displayWebStats.svg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/gump-bench.svg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/gump-bench.svg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/gump-bench.svg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/gump-bench.svg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/heart.pdf b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/heart.pdf similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/heart.pdf rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/heart.pdf diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/heart.svg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/heart.svg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/heart.svg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/heart.svg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/horizontal-gradient.svg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/horizontal-gradient.svg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/horizontal-gradient.svg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/horizontal-gradient.svg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/json.svg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/json.svg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/json.svg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/json.svg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/long-gradient.svg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/long-gradient.svg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/long-gradient.svg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/long-gradient.svg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/near-square-gradient.svg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/near-square-gradient.svg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/near-square-gradient.svg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/near-square-gradient.svg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/openhtml_536.svg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/openhtml_536.svg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/openhtml_536.svg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/openhtml_536.svg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/openhtml_538_gradient.svg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/openhtml_538_gradient.svg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/openhtml_538_gradient.svg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/openhtml_538_gradient.svg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/patternfill.pdf b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/patternfill.pdf similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/patternfill.pdf rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/patternfill.pdf diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/pixeltest.png b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/pixeltest.png similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/pixeltest.png rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/pixeltest.png diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/square-gradient.svg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/square-gradient.svg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/square-gradient.svg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/square-gradient.svg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/tall-gradient-downward-slope.svg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/tall-gradient-downward-slope.svg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/tall-gradient-downward-slope.svg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/tall-gradient-downward-slope.svg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/tall-gradient.svg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/tall-gradient.svg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/tall-gradient.svg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/tall-gradient.svg diff --git a/graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/watermark.svg b/io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/watermark.svg similarity index 100% rename from graphics2d-pdfbox/src/test/resources/org/xbib/graphics/graphics2d/pdfbox/watermark.svg rename to io-pdfbox/src/test/resources/org/xbib/graphics/io/pdfbox/watermark.svg diff --git a/io-vector-eps/build.gradle b/io-vector-eps/build.gradle new file mode 100644 index 0000000..b04c262 --- /dev/null +++ b/io-vector-eps/build.gradle @@ -0,0 +1,3 @@ +dependencies { + api project(':io-vector') +} diff --git a/io-vector-eps/src/main/java/module-info.java b/io-vector-eps/src/main/java/module-info.java new file mode 100644 index 0000000..e399390 --- /dev/null +++ b/io-vector-eps/src/main/java/module-info.java @@ -0,0 +1,6 @@ +module org.xbib.graphics.io.vector.eps { + exports org.xbib.graphics.io.vector.eps; + requires transitive org.xbib.graphics.io.vector; + provides org.xbib.graphics.io.vector.VectorGraphics2DProvider with + org.xbib.graphics.io.vector.eps.EPSGraphics2DProvider; +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/eps/EPSGraphics2D.java b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/EPSGraphics2D.java similarity index 100% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/eps/EPSGraphics2D.java rename to io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/EPSGraphics2D.java index 1bd4542..04802b5 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/eps/EPSGraphics2D.java +++ b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/EPSGraphics2D.java @@ -1,7 +1,7 @@ package org.xbib.graphics.io.vector.eps; -import org.xbib.graphics.io.vector.VectorGraphics2D; import org.xbib.graphics.io.vector.PageSize; +import org.xbib.graphics.io.vector.VectorGraphics2D; import java.awt.BasicStroke; import java.awt.Color; diff --git a/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/EPSGraphics2DProvider.java b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/EPSGraphics2DProvider.java new file mode 100644 index 0000000..a72a7bc --- /dev/null +++ b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/EPSGraphics2DProvider.java @@ -0,0 +1,15 @@ +package org.xbib.graphics.io.vector.eps; + +import org.xbib.graphics.io.vector.VectorGraphics2DProvider; + +public class EPSGraphics2DProvider implements VectorGraphics2DProvider { + @Override + public String name() { + return "eps"; + } + + @Override + public EPSGraphics2D provide(double x, double y, double width, double height) { + return new EPSGraphics2D(x, y, width, height); + } +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/eps/EPSProcessor.java b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/EPSProcessor.java similarity index 100% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/eps/EPSProcessor.java rename to io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/EPSProcessor.java index 775f653..2b2e868 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/eps/EPSProcessor.java +++ b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/EPSProcessor.java @@ -1,10 +1,10 @@ package org.xbib.graphics.io.vector.eps; -import org.xbib.graphics.io.vector.ProcessorResult; -import org.xbib.graphics.io.vector.Processor; import org.xbib.graphics.io.vector.Command; -import org.xbib.graphics.io.vector.filters.FillPaintedShapeAsImageFilter; import org.xbib.graphics.io.vector.PageSize; +import org.xbib.graphics.io.vector.Processor; +import org.xbib.graphics.io.vector.ProcessorResult; +import org.xbib.graphics.io.vector.filters.FillPaintedShapeAsImageFilter; import java.io.IOException; public class EPSProcessor implements Processor { diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/eps/EPSProcessorResult.java b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/EPSProcessorResult.java similarity index 66% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/eps/EPSProcessorResult.java rename to io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/EPSProcessorResult.java index 2158b6a..1ab8d16 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/eps/EPSProcessorResult.java +++ b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/EPSProcessorResult.java @@ -1,8 +1,9 @@ package org.xbib.graphics.io.vector.eps; -import org.xbib.graphics.io.vector.ProcessorResult; -import org.xbib.graphics.io.vector.GraphicsState; import org.xbib.graphics.io.vector.Command; +import org.xbib.graphics.io.vector.GraphicsState; +import org.xbib.graphics.io.vector.PageSize; +import org.xbib.graphics.io.vector.ProcessorResult; import org.xbib.graphics.io.vector.commands.CreateCommand; import org.xbib.graphics.io.vector.commands.DisposeCommand; import org.xbib.graphics.io.vector.commands.DrawImageCommand; @@ -21,38 +22,53 @@ import org.xbib.graphics.io.vector.commands.SetTransformCommand; import org.xbib.graphics.io.vector.commands.ShearCommand; import org.xbib.graphics.io.vector.commands.TransformCommand; import org.xbib.graphics.io.vector.commands.TranslateCommand; -import org.xbib.graphics.io.vector.util.ASCII85EncodeStream; -import org.xbib.graphics.io.vector.util.AlphaToMaskOp; -import org.xbib.graphics.io.vector.util.DataUtils; -import org.xbib.graphics.io.vector.util.FlateEncodeStream; -import org.xbib.graphics.io.vector.util.GraphicsUtils; -import org.xbib.graphics.io.vector.util.ImageDataStream; -import org.xbib.graphics.io.vector.util.ImageDataStream.Interleaving; -import org.xbib.graphics.io.vector.util.LineWrapOutputStream; -import org.xbib.graphics.io.vector.PageSize; +import org.xbib.graphics.io.vector.eps.util.ASCII85EncodeStream; +import org.xbib.graphics.io.vector.eps.util.AlphaToMaskOp; +import org.xbib.graphics.io.vector.eps.util.FlateEncodeStream; +import org.xbib.graphics.io.vector.eps.util.ImageDataStream; +import org.xbib.graphics.io.vector.eps.util.LineWrapOutputStream; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; import java.awt.Image; import java.awt.Shape; import java.awt.Stroke; +import java.awt.Transparency; +import java.awt.font.FontRenderContext; +import java.awt.font.TextLayout; import java.awt.geom.Arc2D; import java.awt.geom.Ellipse2D; import java.awt.geom.Line2D; import java.awt.geom.PathIterator; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.PixelGrabber; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.util.Arrays; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.PriorityQueue; +import java.util.Queue; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import javax.swing.ImageIcon; public class EPSProcessorResult implements ProcessorResult { /** @@ -72,7 +88,7 @@ public class EPSProcessorResult implements ProcessorResult { /** * Mapping of stroke endcap values from Java to PostScript®. */ - private static final Map STROKE_ENDCAPS = DataUtils.map( + private static final Map STROKE_ENDCAPS = map( new Integer[]{BasicStroke.CAP_BUTT, BasicStroke.CAP_ROUND, BasicStroke.CAP_SQUARE}, new Integer[]{0, 1, 2} ); @@ -81,7 +97,7 @@ public class EPSProcessorResult implements ProcessorResult { * Mapping of line join values for path drawing from Java to * PostScript®. */ - private static final Map STROKE_LINEJOIN = DataUtils.map( + private static final Map STROKE_LINEJOIN = map( new Integer[]{BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND, BasicStroke.JOIN_BEVEL}, new Integer[]{0, 1, 2} ); @@ -99,8 +115,7 @@ public class EPSProcessorResult implements ProcessorResult { } private static String getOutput(Color c) { - // TODO Handle transparency - return String.valueOf(c.getRed() / 255.0) + " " + c.getGreen() / 255.0 + " " + c.getBlue() / 255.0 + " rgb"; + return c.getRed() / 255.0 + " " + c.getGreen() / 255.0 + " " + c.getBlue() / 255.0 + " rgb"; } private static String getOutput(Shape s) { @@ -199,9 +214,9 @@ public class EPSProcessorResult implements ProcessorResult { private static String getOutput(Image image, int imageWidth, int imageHeight, double x, double y, double width, double height) throws IOException { StringBuilder out = new StringBuilder(); - BufferedImage bufferedImage = GraphicsUtils.toBufferedImage(image); + BufferedImage bufferedImage = toBufferedImage(image); int bands = bufferedImage.getSampleModel().getNumBands(); - int bitsPerSample = DataUtils.max(bufferedImage.getSampleModel().getSampleSize()); + int bitsPerSample = max(bufferedImage.getSampleModel().getSampleSize()); bitsPerSample = (int) (Math.ceil(bitsPerSample / 8.0) * 8.0); if (bands > 3) { bands = 3; @@ -215,7 +230,6 @@ public class EPSProcessorResult implements ProcessorResult { } int decodeScale = 1; if (bufferedImage.getColorModel().hasAlpha()) { - // TODO Use different InterleaveType (2 or 3) for more efficient compression out.append("<< /ImageType 3 /InterleaveType 1 ") .append("/MaskDict ") .append(imageWidth).append(" ").append(imageHeight).append(" ") @@ -229,9 +243,6 @@ public class EPSProcessorResult implements ProcessorResult { .append("/FlateDecode filter ") .append("imgdict ") .append(">> image").append(EOL); - - // Convert alpha values to binary mask - // FIXME Do alpha conversion in a preprocessing step on commands bufferedImage = new AlphaToMaskOp(true).filter(bufferedImage, null); output(bufferedImage, out); } else { @@ -255,11 +266,11 @@ public class EPSProcessorResult implements ProcessorResult { } private static void output(BufferedImage image, StringBuilder out) throws IOException { - InputStream imageDataStream = new ImageDataStream(image, Interleaving.SAMPLE); + InputStream imageDataStream = new ImageDataStream(image, ImageDataStream.Interleaving.SAMPLE); ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); - OutputStream compressionStream = new FlateEncodeStream( - new ASCII85EncodeStream(new LineWrapOutputStream(outBytes, 80))); - DataUtils.transfer(imageDataStream, compressionStream, 4096); + OutputStream compressionStream = + new FlateEncodeStream(new ASCII85EncodeStream(new LineWrapOutputStream(outBytes, 80))); + imageDataStream.transferTo(compressionStream); compressionStream.close(); String compressed = outBytes.toString(CHARSET); out.append(compressed).append(EOL); @@ -287,10 +298,15 @@ public class EPSProcessorResult implements ProcessorResult { StringBuilder out = new StringBuilder(); if (s instanceof BasicStroke) { BasicStroke bs = (BasicStroke) s; + float[] f = bs.getDashArray(); + String dash = f == null ? "" : IntStream.range(0, f.length) + .mapToDouble(i -> f[i]) + .mapToObj(String::valueOf) + .collect(Collectors.joining(" ")); out.append(bs.getLineWidth()).append(" setlinewidth ") .append(STROKE_LINEJOIN.get(bs.getLineJoin())).append(" setlinejoin ") .append(STROKE_ENDCAPS.get(bs.getEndCap())).append(" setlinecap ") - .append("[").append(DataUtils.join(" ", bs.getDashArray())).append("] ") + .append("[").append(dash).append("] ") .append(bs.getDashPhase()).append(" setdash"); } else { out.append("% Custom strokes aren't supported at the moment"); @@ -300,18 +316,13 @@ public class EPSProcessorResult implements ProcessorResult { private static String getOutput(Font font) { StringBuilder out = new StringBuilder(); - font = GraphicsUtils.getPhysicalFont(font); + font = getPhysicalFont(font); String fontName = font.getPSName(); - - // Convert font to ISO-8859-1 encoding String fontNameLatin1 = fontName + FONT_LATIN1_SUFFIX; out.append("/").append(fontNameLatin1).append(" ") .append("/").append(font.getPSName()).append(" latinize "); - - // Use encoded font out.append("/").append(fontNameLatin1).append(" ") .append(font.getSize2D()).append(" selectfont"); - return out.toString(); } @@ -393,14 +404,12 @@ public class EPSProcessorResult implements ProcessorResult { elements.add(getOutput(c.getValue())); } else if (command instanceof SetCompositeCommand) { SetCompositeCommand c = (SetCompositeCommand) command; - // TODO Implement composite rendering for EPS elements.add("% composite not yet implemented: " + c.getValue()); } else if (command instanceof SetFontCommand) { SetFontCommand c = (SetFontCommand) command; elements.add(getOutput(c.getValue())); } else if (command instanceof SetPaintCommand) { SetPaintCommand c = (SetPaintCommand) command; - // TODO Implement paint rendering for EPS elements.add("% paint not yet implemented: " + c.getValue()); } else if (command instanceof SetStrokeCommand) { SetStrokeCommand c = (SetStrokeCommand) command; @@ -410,8 +419,8 @@ public class EPSProcessorResult implements ProcessorResult { StringBuilder e = new StringBuilder(); double[] matrix = new double[6]; c.getValue().getMatrix(matrix); - e.append("basematrix setmatrix [") - .append(DataUtils.join(" ", matrix)).append("] concat"); + String j = Arrays.stream(matrix).mapToObj(String::valueOf).collect(Collectors.joining(" ")); + e.append("basematrix setmatrix [").append(j).append("] concat"); elements.add(e.toString()); } else if (command instanceof RotateCommand) { RotateCommand c = (RotateCommand) command; @@ -430,21 +439,21 @@ public class EPSProcessorResult implements ProcessorResult { elements.add(e.toString()); } else if (command instanceof ScaleCommand) { ScaleCommand c = (ScaleCommand) command; - elements.add(DataUtils.format(c.getScaleX()) + " " + DataUtils.format(c.getScaleY()) + " scale"); + elements.add(format(c.getScaleX()) + " " + format(c.getScaleY()) + " scale"); } else if (command instanceof ShearCommand) { ShearCommand c = (ShearCommand) command; - elements.add("[1 " + DataUtils.format(c.getShearY()) + " " + DataUtils.format(c.getShearX()) + " 1 0 0] concat"); + elements.add("[1 " + format(c.getShearY()) + " " + format(c.getShearX()) + " 1 0 0] concat"); } else if (command instanceof TransformCommand) { TransformCommand c = (TransformCommand) command; StringBuilder e = new StringBuilder(); double[] matrix = new double[6]; c.getValue().getMatrix(matrix); - e.append("[").append(DataUtils.join(" ", matrix)) - .append("] concat"); + String j = Arrays.stream(matrix).mapToObj(String::valueOf).collect(Collectors.joining(" ")); + e.append("[").append(j).append("] concat"); elements.add(e.toString()); } else if (command instanceof TranslateCommand) { TranslateCommand c = (TranslateCommand) command; - elements.add(String.valueOf(c.getDeltaX()) + " " + c.getDeltaY() + " translate"); + elements.add(c.getDeltaX() + " " + c.getDeltaY() + " translate"); } else if (command instanceof DrawImageCommand) { DrawImageCommand c = (DrawImageCommand) command; String e = getOutput(c.getValue(), @@ -466,5 +475,209 @@ public class EPSProcessorResult implements ProcessorResult { elements.add("grestore"); } } + + /** + * Returns a formatted string of the specified number. All trailing zeroes + * or decimal points will be stripped. + * + * @param number Number to convert to a string. + * @return A formatted string. + */ + private static String format(Number number) { + String formatted; + if (number instanceof Double || number instanceof Float) { + formatted = Double.toString(number.doubleValue()) + .replaceAll("\\.0+$", "") + .replaceAll("(\\.[0-9]*[1-9])0+$", "$1"); + } else { + formatted = number.toString(); + } + return formatted; + } + + /** + * Creates a mapping from two arrays, one with keys, one with values. + * + * @param Data type of the keys. + * @param Data type of the values. + * @param keys Array containing the keys. + * @param values Array containing the values. + * @return Map with keys and values from the specified arrays. + */ + private static Map map(K[] keys, V[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException("Cannot create a Map: number of keys and values differs."); + } + Map map = new LinkedHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + return map; + } + + /** + * Returns the largest of all specified values. + * + * @param values Several integer values. + * @return largest value. + */ + private static int max(int... values) { + int max = values[0]; + for (int i = 1; i < values.length; i++) { + if (values[i] > max) { + max = values[i]; + } + } + return max; + } + + /** + * This method returns a buffered image with the contents of an image. + * Taken from http://www.exampledepot.com/egs/java.awt.image/Image2Buf.html + * + * @param image Image to be converted + * @return a buffered image with the contents of the specified image + */ + public static BufferedImage toBufferedImage(Image image) { + if (image instanceof BufferedImage) { + return (BufferedImage) image; + } + image = new ImageIcon(image).getImage(); + boolean hasAlpha = hasAlpha(image); + BufferedImage bimage; + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + try { + int transparency = Transparency.OPAQUE; + if (hasAlpha) { + transparency = Transparency.TRANSLUCENT; + } + GraphicsDevice gs = ge.getDefaultScreenDevice(); + GraphicsConfiguration gc = gs.getDefaultConfiguration(); + bimage = gc.createCompatibleImage(image.getWidth(null), image.getHeight(null), transparency); + } catch (HeadlessException e) { + bimage = null; + } + if (bimage == null) { + int type = BufferedImage.TYPE_INT_RGB; + if (hasAlpha) { + type = BufferedImage.TYPE_INT_ARGB; + } + bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type); + } + Graphics g = bimage.createGraphics(); + g.drawImage(image, 0, 0, null); + g.dispose(); + return bimage; + } + + /** + * This method returns {@code true} if the specified image has the + * possibility to store transparent pixels. + * Inspired by http://www.exampledepot.com/egs/java.awt.image/HasAlpha.html + * + * @param image Image that should be checked for alpha channel. + * @return {@code true} if the specified image can have transparent pixels, + * {@code false} otherwise + */ + private static boolean hasAlpha(Image image) { + ColorModel cm; + if (image instanceof BufferedImage) { + BufferedImage bimage = (BufferedImage) image; + cm = bimage.getColorModel(); + } else { + PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false); + try { + pg.grabPixels(); + } catch (InterruptedException e) { + return false; + } + cm = pg.getColorModel(); + } + return cm.hasAlpha(); + } + + /** + * Try to guess physical font from the properties of a logical font, like + * "Dialog", "Serif", "Monospaced" etc. + * + * @param logicalFont Logical font object. + * @param testText Text used to determine font properties. + * @return An object of the first matching physical font. The original font + * object is returned if it was a physical font or no font matched. + */ + private static Font getPhysicalFont(Font logicalFont, String testText) { + String logicalFamily = logicalFont.getFamily(); + if (!isLogicalFontFamily(logicalFamily)) { + return logicalFont; + } + final TextLayout logicalLayout = new TextLayout(testText, logicalFont, FONT_RENDER_CONTEXT); + Queue physicalFonts = new PriorityQueue<>(1, FONT_EXPRESSIVENESS_COMPARATOR); + Font[] allPhysicalFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); + for (Font physicalFont : allPhysicalFonts) { + String physicalFamily = physicalFont.getFamily(); + if (isLogicalFontFamily(physicalFamily)) { + continue; + } + physicalFont = physicalFont.deriveFont(logicalFont.getStyle(), logicalFont.getSize2D()); + TextLayout physicalLayout = new TextLayout(testText, physicalFont, FONT_RENDER_CONTEXT); + if (physicalLayout.getBounds().equals(logicalLayout.getBounds()) && + physicalLayout.getAscent() == logicalLayout.getAscent() && + physicalLayout.getDescent() == logicalLayout.getDescent() && + physicalLayout.getLeading() == logicalLayout.getLeading() && + physicalLayout.getAdvance() == logicalLayout.getAdvance() && + physicalLayout.getVisibleAdvance() == logicalLayout.getVisibleAdvance()) { + physicalFonts.add(physicalFont); + } + } + if (physicalFonts.isEmpty()) { + return logicalFont; + } + return physicalFonts.poll(); + } + + public static Font getPhysicalFont(Font logicalFont) { + return getPhysicalFont(logicalFont, FONT_TEST_STRING); + } + + private static boolean isLogicalFontFamily(String family) { + return (Font.DIALOG.equals(family) || + Font.DIALOG_INPUT.equals(family) || + Font.SANS_SERIF.equals(family) || + Font.SERIF.equals(family) || + Font.MONOSPACED.equals(family)); + } + + private static final FontRenderContext FONT_RENDER_CONTEXT = + new FontRenderContext(null, false, true); + + private static final String FONT_TEST_STRING = + "Falsches Üben von Xylophonmusik quält jeden größeren Zwerg"; + + private static final FontExpressivenessComparator FONT_EXPRESSIVENESS_COMPARATOR = + new FontExpressivenessComparator(); + + private static class FontExpressivenessComparator implements Comparator { + private static final int[] STYLES = { + Font.PLAIN, Font.ITALIC, Font.BOLD, Font.BOLD | Font.ITALIC + }; + + public int compare(Font font1, Font font2) { + if (font1 == font2) { + return 0; + } + Set variantNames1 = new HashSet(); + Set variantNames2 = new HashSet(); + for (int style : STYLES) { + variantNames1.add(font1.deriveFont(style).getPSName()); + variantNames2.add(font2.deriveFont(style).getPSName()); + } + if (variantNames1.size() < variantNames2.size()) { + return 1; + } else if (variantNames1.size() > variantNames2.size()) { + return -1; + } + return font1.getName().compareTo(font2.getName()); + } + } } diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/ASCII85EncodeStream.java b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/util/ASCII85EncodeStream.java similarity index 98% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/util/ASCII85EncodeStream.java rename to io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/util/ASCII85EncodeStream.java index 7bb0976..c00e0f1 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/ASCII85EncodeStream.java +++ b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/util/ASCII85EncodeStream.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.io.vector.util; +package org.xbib.graphics.io.vector.eps.util; import java.io.FilterOutputStream; import java.io.IOException; diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/AlphaToMaskOp.java b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/util/AlphaToMaskOp.java similarity index 98% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/util/AlphaToMaskOp.java rename to io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/util/AlphaToMaskOp.java index 98f4979..7d6008c 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/AlphaToMaskOp.java +++ b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/util/AlphaToMaskOp.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.io.vector.util; +package org.xbib.graphics.io.vector.eps.util; import java.awt.RenderingHints; import java.awt.geom.Point2D; diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/FlateEncodeStream.java b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/util/FlateEncodeStream.java similarity index 82% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/util/FlateEncodeStream.java rename to io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/util/FlateEncodeStream.java index 7877982..29310a0 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/FlateEncodeStream.java +++ b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/util/FlateEncodeStream.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.io.vector.util; +package org.xbib.graphics.io.vector.eps.util; import java.io.OutputStream; import java.util.zip.DeflaterOutputStream; diff --git a/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/util/ImageDataStream.java b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/util/ImageDataStream.java new file mode 100644 index 0000000..497b042 --- /dev/null +++ b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/util/ImageDataStream.java @@ -0,0 +1,141 @@ +package org.xbib.graphics.io.vector.eps.util; + +import java.awt.image.BufferedImage; +import java.awt.image.Raster; +import java.io.IOException; +import java.io.InputStream; +import java.util.LinkedList; +import java.util.Queue; + +public class ImageDataStream extends InputStream { + + private final BufferedImage image; + + private final int width; + + private final int height; + + private final Interleaving interleaving; + + private final Raster raster; + + private final boolean opaque; + + private final Queue byteBuffer; + + private int[] sampleValues; + + private int[] sampleSizes; + + private int x; + + private int y; + + public ImageDataStream(BufferedImage image, Interleaving interleaving) { + this.image = image; + this.interleaving = interleaving; + width = image.getWidth(); + height = image.getHeight(); + x = -1; + y = 0; + Raster alphaRaster = image.getAlphaRaster(); + if (interleaving == Interleaving.ALPHA_ONLY) { + raster = alphaRaster; + } else { + raster = image.getRaster(); + } + opaque = alphaRaster == null; + byteBuffer = new LinkedList<>(); + if (raster != null) { + sampleValues = new int[raster.getNumBands()]; + sampleSizes = raster.getSampleModel().getSampleSize(); + } + } + + public BufferedImage getImage() { + return image; + } + + public Interleaving getInterleaving() { + return interleaving; + } + + @Override + public int read() throws IOException { + if (!byteBuffer.isEmpty()) { + return byteBuffer.poll(); + } else { + if (!nextSample()) { + return -1; + } + int bands = sampleValues.length; + if (interleaving == Interleaving.WITHOUT_ALPHA || + interleaving == Interleaving.ALPHA_ONLY) { + if (interleaving == Interleaving.WITHOUT_ALPHA && !opaque) { + // Ignore alpha band + bands--; + } + for (int band = 0; band < bands; band++) { + bufferSampleValue(band); + } + } else { + if (opaque) { + for (int band = 0; band < bands; band++) { + bufferSampleValue(band); + } + } else { + for (int band = 0; band < bands; band++) { + // Fix order to be ARGB instead of RGBA + if (band == 0) { + bufferSampleValue(bands - 1); + } else { + bufferSampleValue(band - 1); + } + } + } + } + if (!byteBuffer.isEmpty()) { + return byteBuffer.poll(); + } else { + return -1; + } + } + } + + private void bufferSampleValue(int band) { + if (sampleSizes[band] < 8) { + int byteValue = sampleValues[band] & 0xFF; + byteBuffer.offer(byteValue); + } else { + int byteCount = sampleSizes[band] / 8; + for (int i = byteCount - 1; i >= 0; i--) { + int byteValue = (sampleValues[band] >> i * 8) & 0xFF; + byteBuffer.offer(byteValue); + } + } + } + + private boolean nextSample() { + if (interleaving == Interleaving.SAMPLE || interleaving == Interleaving.WITHOUT_ALPHA) { + x++; + if (x >= width) { + x = 0; + y++; + } + } + if (x < 0 || x >= width || y < 0 || y >= height) { + return false; + } else { + raster.getPixel(x, y, sampleValues); + return true; + } + } + + public enum Interleaving { + SAMPLE, + ROW, + WITHOUT_ALPHA, + ALPHA_ONLY + } +} + diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/LineWrapOutputStream.java b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/util/LineWrapOutputStream.java similarity index 95% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/util/LineWrapOutputStream.java rename to io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/util/LineWrapOutputStream.java index 2518e5d..9731eb6 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/LineWrapOutputStream.java +++ b/io-vector-eps/src/main/java/org/xbib/graphics/io/vector/eps/util/LineWrapOutputStream.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.io.vector.util; +package org.xbib.graphics.io.vector.eps.util; import java.io.FilterOutputStream; import java.io.IOException; diff --git a/io-vector-eps/src/main/resources/META-INF/services/org.xbib.graphics.io.vector.VectorGraphics2DProvider b/io-vector-eps/src/main/resources/META-INF/services/org.xbib.graphics.io.vector.VectorGraphics2DProvider new file mode 100644 index 0000000..83d4815 --- /dev/null +++ b/io-vector-eps/src/main/resources/META-INF/services/org.xbib.graphics.io.vector.VectorGraphics2DProvider @@ -0,0 +1 @@ +org.xbib.graphics.io.vector.eps.EPSGraphics2DProvider diff --git a/io-vector/src/test/java/org/xbib/graphics/io/vector/util/ASCII85EncodeStreamTest.java b/io-vector-eps/src/test/java/org/xbib/graphics/io/vector/eps/ASCII85EncodeStreamTest.java similarity index 95% rename from io-vector/src/test/java/org/xbib/graphics/io/vector/util/ASCII85EncodeStreamTest.java rename to io-vector-eps/src/test/java/org/xbib/graphics/io/vector/eps/ASCII85EncodeStreamTest.java index 958de3b..2bc296c 100644 --- a/io-vector/src/test/java/org/xbib/graphics/io/vector/util/ASCII85EncodeStreamTest.java +++ b/io-vector-eps/src/test/java/org/xbib/graphics/io/vector/eps/ASCII85EncodeStreamTest.java @@ -1,7 +1,8 @@ -package org.xbib.graphics.io.vector.util; +package org.xbib.graphics.io.vector.eps; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; +import org.xbib.graphics.io.vector.eps.util.ASCII85EncodeStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/io-vector/src/test/java/org/xbib/graphics/io/vector/eps/EPSProcessorTest.java b/io-vector-eps/src/test/java/org/xbib/graphics/io/vector/eps/EPSProcessorTest.java similarity index 91% rename from io-vector/src/test/java/org/xbib/graphics/io/vector/eps/EPSProcessorTest.java rename to io-vector-eps/src/test/java/org/xbib/graphics/io/vector/eps/EPSProcessorTest.java index 29bb7da..7498d2f 100644 --- a/io-vector/src/test/java/org/xbib/graphics/io/vector/eps/EPSProcessorTest.java +++ b/io-vector-eps/src/test/java/org/xbib/graphics/io/vector/eps/EPSProcessorTest.java @@ -1,7 +1,5 @@ package org.xbib.graphics.io.vector.eps; -import static org.xbib.graphics.io.vector.TestUtils.Template; -import static org.xbib.graphics.io.vector.TestUtils.assertTemplateEquals; import org.junit.jupiter.api.Test; import org.xbib.graphics.io.vector.ProcessorResult; import org.xbib.graphics.io.vector.Command; @@ -64,8 +62,8 @@ public class EPSProcessorTest { @Test public void envelopeForEmptyDocument() throws IOException { String result = process(); - Template actual = new Template(result.split(EOL)); - Template expected = new Template(HEADER); - assertTemplateEquals(expected, actual); + TestUtils.Template actual = new TestUtils.Template(result.split(EOL)); + TestUtils.Template expected = new TestUtils.Template(HEADER); + TestUtils.assertTemplateEquals(expected, actual); } } diff --git a/io-vector-eps/src/test/java/org/xbib/graphics/io/vector/eps/TestUtils.java b/io-vector-eps/src/test/java/org/xbib/graphics/io/vector/eps/TestUtils.java new file mode 100644 index 0000000..6c316f6 --- /dev/null +++ b/io-vector-eps/src/test/java/org/xbib/graphics/io/vector/eps/TestUtils.java @@ -0,0 +1,265 @@ +package org.xbib.graphics.io.vector.eps; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public abstract class TestUtils { + + protected TestUtils() { + throw new UnsupportedOperationException(); + } + + public static void assertTemplateEquals(Template expected, Template actual) { + Iterator itExpected = expected.iterator(); + Iterator itActual = actual.iterator(); + while (itExpected.hasNext() && itActual.hasNext()) { + Object lineExpected = itExpected.next(); + Object lineActual = itActual.next(); + if (lineExpected == null) { + continue; + } + assertTrue(lineActual instanceof String, + String.format("Line is of type %s, expected String.", lineActual.getClass())); + if (lineExpected instanceof String) { + assertEquals(lineExpected, lineActual); + } else if (lineExpected instanceof Pattern) { + Pattern expectedPattern = (Pattern) lineExpected; + Matcher matcher = expectedPattern.matcher((String) lineActual); + assertTrue(matcher.matches(), + String.format("Line didn't match pattern.\nExpected: \"%s\"\nActual: \"%s\"", matcher.pattern(), lineActual)); + } + } + assertEquals(expected.size(), actual.size(), "Wrong number of lines in template."); + } + + private static List parseXML(String xmlString) { + XMLFragment frag; + List fragments = new LinkedList(); + int startPos = 0; + while ((frag = XMLFragment.parse(xmlString, startPos)) != null) { + fragments.add(frag); + startPos = frag.matchEnd; + } + return fragments; + } + + public static void assertXMLEquals(String expected, String actual) { + List expectedFrags = parseXML(expected); + List actualFrags = parseXML(actual); + + Iterator itExpected = expectedFrags.iterator(); + Iterator itActual = actualFrags.iterator(); + while (itExpected.hasNext() && itActual.hasNext()) { + XMLFragment expectedFrag = itExpected.next(); + XMLFragment actualFrag = itActual.next(); + assertEquals(expectedFrag, actualFrag); + } + + assertEquals(expectedFrags.size(), actualFrags.size()); + } + + @SuppressWarnings("serial") + public static class Template extends LinkedList { + public Template(Object[] lines) { + Collections.addAll(this, lines); + } + + public Template(Template[] templates) { + for (Template template : templates) { + addAll(template); + } + } + } + + public static class XMLFragment { + + private static final Pattern CDATA = Pattern.compile("\\s*"); + + private static final Pattern COMMENT = Pattern.compile("\\s*"); + + private static final Pattern TAG_BEGIN = Pattern.compile("\\s*<(/|\\?|!)?\\s*([^\\s>/\\?]+)"); + + private static final Pattern TAG_END = Pattern.compile("\\s*(/|\\?)?>"); + + private static final Pattern TAG_ATTRIBUTE = Pattern.compile("\\s*([^\\s>=]+)=(\"[^\"]*\"|'[^']*')"); + + private static final Pattern DOCTYPE_PART = Pattern.compile("\\s*(\"[^\"]*\"|'[^']*'|[^\\s>]+)"); + + public final String name; + + public final FragmentType type; + + public final Map attributes; + + public final int matchStart; + + public final int matchEnd; + + public XMLFragment(String name, FragmentType type, Map attributes, + int matchStart, int matchEnd) { + this.name = name; + this.type = type; + this.attributes = Collections.unmodifiableMap( + new TreeMap(attributes)); + this.matchStart = matchStart; + this.matchEnd = matchEnd; + } + + public static XMLFragment parse(String xmlString, int matchStart) { + Map attrs = new IdentityHashMap(); + + Matcher cdataMatch = CDATA.matcher(xmlString); + cdataMatch.region(matchStart, xmlString.length()); + if (cdataMatch.lookingAt()) { + attrs.put("value", cdataMatch.group(1)); + return new XMLFragment("", FragmentType.CDATA, attrs, matchStart, cdataMatch.end()); + } + + Matcher commentMatch = COMMENT.matcher(xmlString); + commentMatch.region(matchStart, xmlString.length()); + if (commentMatch.lookingAt()) { + attrs.put("value", commentMatch.group(1).trim()); + return new XMLFragment("", FragmentType.COMMENT, attrs, matchStart, commentMatch.end()); + } + + Matcher beginMatch = TAG_BEGIN.matcher(xmlString); + beginMatch.region(matchStart, xmlString.length()); + if (!beginMatch.lookingAt()) { + return null; + } + int matchEndPrev = beginMatch.end(); + + String modifiers = beginMatch.group(1); + String name = beginMatch.group(2); + boolean endTag = "/".equals(modifiers); + boolean declarationStart = "?".equals(modifiers); + boolean doctype = "!".equals(modifiers) && "DOCTYPE".equals(name); + + if (doctype) { + int partNo = 0; + while (true) { + Matcher attrMatch = DOCTYPE_PART.matcher(xmlString); + attrMatch.region(matchEndPrev, xmlString.length()); + if (!attrMatch.lookingAt()) { + break; + } + matchEndPrev = attrMatch.end(); + + String partValue = attrMatch.group(1); + if (partValue.startsWith("\"") || partValue.startsWith("'")) { + partValue = partValue.substring(1, partValue.length() - 1); + } + + String partId = String.format("doctype %02d", partNo++); + attrs.put(partId, partValue); + } + } else { + while (true) { + Matcher attrMatch = TAG_ATTRIBUTE.matcher(xmlString); + attrMatch.region(matchEndPrev, xmlString.length()); + if (!attrMatch.lookingAt()) { + break; + } + matchEndPrev = attrMatch.end(); + + String attrName = attrMatch.group(1); + String attrValue = attrMatch.group(2); + attrValue = attrValue.substring(1, attrValue.length() - 1); + attrs.put(attrName, attrValue); + } + } + + Matcher endMatch = TAG_END.matcher(xmlString); + endMatch.region(matchEndPrev, xmlString.length()); + if (!endMatch.lookingAt()) { + throw new AssertionError(String.format("No tag end found: %s", xmlString.substring(0, matchEndPrev))); + } + matchEndPrev = endMatch.end(); + + modifiers = endMatch.group(1); + boolean emptyElement = "/".equals(modifiers); + boolean declarationEnd = "?".equals(modifiers); + + FragmentType type = FragmentType.START_TAG; + if (endTag) { + type = FragmentType.END_TAG; + } else if (emptyElement) { + type = FragmentType.EMPTY_ELEMENT; + } else if (declarationStart && declarationEnd) { + type = FragmentType.DECLARATION; + } else if (doctype) { + type = FragmentType.DOCTYPE; + } + + return new XMLFragment(name, type, attrs, matchStart, matchEndPrev); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof XMLFragment)) { + return false; + } + XMLFragment frag = (XMLFragment) o; + if (!type.equals(frag.type) || !name.equals(frag.name)) { + return false; + } + Iterator> itThis = attributes.entrySet().iterator(); + Iterator> itFrag = frag.attributes.entrySet().iterator(); + while (itThis.hasNext() && itFrag.hasNext()) { + Map.Entry attrThis = itThis.next(); + Map.Entry attrFrag = itFrag.next(); + if (!attrThis.getKey().equals(attrFrag.getKey()) || + !attrThis.getValue().equals(attrFrag.getValue())) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return type.hashCode() ^ attributes.hashCode(); + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder("<"); + if (FragmentType.END_TAG.equals(type)) { + s.append("/"); + } else if (FragmentType.DECLARATION.equals(type)) { + s.append("?"); + } + + if (FragmentType.DOCTYPE.equals(type)) { + s.append("!").append(name); + for (String partValue : attributes.values()) { + s.append(" ").append(partValue); + } + } else { + s.append(name); + for (Map.Entry attr : attributes.entrySet()) { + s.append(" ").append(attr.getKey()).append("=\"").append(attr.getValue()).append("\""); + } + } + if (FragmentType.DECLARATION.equals(type)) { + s.append("?"); + } + s.append(">"); + return s.toString(); + } + + public enum FragmentType { + START_TAG, END_TAG, EMPTY_ELEMENT, CDATA, + DECLARATION, DOCTYPE, COMMENT + } + } +} diff --git a/io-vector-pdf/build.gradle b/io-vector-pdf/build.gradle new file mode 100644 index 0000000..b04c262 --- /dev/null +++ b/io-vector-pdf/build.gradle @@ -0,0 +1,3 @@ +dependencies { + api project(':io-vector') +} diff --git a/io-vector-pdf/src/main/java/module-info.java b/io-vector-pdf/src/main/java/module-info.java new file mode 100644 index 0000000..42fa0c2 --- /dev/null +++ b/io-vector-pdf/src/main/java/module-info.java @@ -0,0 +1,6 @@ +module org.xbib.graphics.io.vector.pdf { + exports org.xbib.graphics.io.vector.pdf; + requires transitive org.xbib.graphics.io.vector; + provides org.xbib.graphics.io.vector.VectorGraphics2DProvider with + org.xbib.graphics.io.vector.pdf.PDFGraphics2DProvider; +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/PDFGraphics2D.java b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/PDFGraphics2D.java similarity index 100% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/PDFGraphics2D.java rename to io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/PDFGraphics2D.java diff --git a/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/PDFGraphics2DProvider.java b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/PDFGraphics2DProvider.java new file mode 100644 index 0000000..d93a54b --- /dev/null +++ b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/PDFGraphics2DProvider.java @@ -0,0 +1,15 @@ +package org.xbib.graphics.io.vector.pdf; + +import org.xbib.graphics.io.vector.VectorGraphics2DProvider; + +public class PDFGraphics2DProvider implements VectorGraphics2DProvider { + @Override + public String name() { + return "pdf"; + } + + @Override + public PDFGraphics2D provide(double x, double y, double width, double height) { + return new PDFGraphics2D(x, y, width, height); + } +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/PDFProcessor.java b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/PDFProcessor.java similarity index 100% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/PDFProcessor.java rename to io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/PDFProcessor.java diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/PDFProcessorResult.java b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/PDFProcessorResult.java similarity index 70% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/PDFProcessorResult.java rename to io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/PDFProcessorResult.java index bd37ad1..4e5ef2a 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/PDFProcessorResult.java +++ b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/PDFProcessorResult.java @@ -19,32 +19,50 @@ import org.xbib.graphics.io.vector.commands.SetHintCommand; import org.xbib.graphics.io.vector.commands.SetPaintCommand; import org.xbib.graphics.io.vector.commands.SetStrokeCommand; import org.xbib.graphics.io.vector.commands.SetTransformCommand; -import org.xbib.graphics.io.vector.util.DataUtils; -import org.xbib.graphics.io.vector.util.FlateEncodeStream; -import org.xbib.graphics.io.vector.util.FormattingWriter; -import org.xbib.graphics.io.vector.util.GraphicsUtils; -import org.xbib.graphics.io.vector.util.ImageDataStream; -import org.xbib.graphics.io.vector.util.ImageDataStream.Interleaving; +import org.xbib.graphics.io.vector.pdf.util.FlateEncodeStream; +import org.xbib.graphics.io.vector.pdf.util.ImageDataStream; +import org.xbib.graphics.io.vector.pdf.util.PDFObject; +import org.xbib.graphics.io.vector.pdf.util.Payload; +import org.xbib.graphics.io.vector.pdf.util.Resources; +import org.xbib.graphics.io.vector.pdf.util.FormattingWriter; import org.xbib.graphics.io.vector.PageSize; +import org.xbib.graphics.io.vector.pdf.util.SizePayload; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; import java.awt.Image; import java.awt.Shape; import java.awt.Stroke; +import java.awt.Transparency; +import java.awt.color.ColorSpace; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.PixelGrabber; +import java.awt.image.WritableRaster; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Deque; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import javax.swing.ImageIcon; public class PDFProcessorResult implements ProcessorResult { @@ -64,7 +82,7 @@ public class PDFProcessorResult implements ProcessorResult { /** * Mapping of stroke endcap values from Java to PDF. */ - private static final Map STROKE_ENDCAPS = DataUtils.map( + private static final Map STROKE_ENDCAPS = map( new Integer[]{BasicStroke.CAP_BUTT, BasicStroke.CAP_ROUND, BasicStroke.CAP_SQUARE}, new Integer[]{0, 1, 2} ); @@ -72,7 +90,7 @@ public class PDFProcessorResult implements ProcessorResult { /** * Mapping of line join values for path drawing from Java to PDF. */ - private static final Map STROKE_LINEJOIN = DataUtils.map( + private static final Map STROKE_LINEJOIN = map( new Integer[]{BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND, BasicStroke.JOIN_BEVEL}, new Integer[]{0, 1, 2} ); @@ -113,7 +131,7 @@ public class PDFProcessorResult implements ProcessorResult { this.compressed = compressed; } - public static String toString(PDFObject obj) throws IOException { + private static String toString(PDFObject obj) throws IOException { StringBuilder out = new StringBuilder(); out.append(obj.id).append(" ").append(obj.version).append(" obj") .append(EOL); @@ -141,9 +159,9 @@ public class PDFProcessorResult implements ProcessorResult { if (obj instanceof String) { return "/" + obj.toString(); } else if (obj instanceof float[]) { - return serialize(DataUtils.asList((float[]) obj)); + return serialize(asList((float[]) obj)); } else if (obj instanceof double[]) { - return serialize(DataUtils.asList((double[]) obj)); + return serialize(asList((double[]) obj)); } else if (obj instanceof Object[]) { return serialize(Arrays.asList((Object[]) obj)); } else if (obj instanceof List) { @@ -175,7 +193,7 @@ public class PDFProcessorResult implements ProcessorResult { PDFObject pdfObj = (PDFObject) obj; return pdfObj.id + " " + pdfObj.version + " R"; } else { - return DataUtils.format(obj); + return format(obj); } } @@ -279,8 +297,7 @@ public class PDFProcessorResult implements ProcessorResult { out.append("/").append(fontResourceId).append(" ").append(fontSize) .append(" Tf").append(EOL); } - - return DataUtils.stripTrailing(out.toString(), EOL); + return out.toString().replaceAll("(" + Pattern.quote(EOL) + ")+$", ""); } private static String getOutput(Stroke s) { @@ -320,16 +337,10 @@ public class PDFProcessorResult implements ProcessorResult { private static String getOutput(AffineTransform transform) { double[] matrix = new double[6]; transform.getMatrix(matrix); - return DataUtils.join(" ", matrix); + return Arrays.stream(matrix).mapToObj(String::valueOf).collect(Collectors.joining(" ")); } private static String getOutput(String str, double x, double y) { - - // Save current graphics state - // Undo swapping of y axis - // Render text - // Restore previous graphics state - return "q " + "1 0 0 -1 " + x + " " + y + " cm " + "BT " + getOutput(str) + " Tj ET " + "Q"; } @@ -352,15 +363,7 @@ public class PDFProcessorResult implements ProcessorResult { private static String getOutput(PDFObject image, double x, double y, double width, double height, Resources resources) { - // Query image resource id String resourceId = resources.getId(image); - - // Save graphics state - // Move image to correct position and scale it to (width, height) - // Swap y axis - // Draw image - // Restore old graphics state - return "q " + width + " 0 0 " + height + " " + x + " " + y + " cm " + "1 0 0 -1 0 1 cm " + "/" + resourceId + " Do " + "Q"; } @@ -370,10 +373,10 @@ public class PDFProcessorResult implements ProcessorResult { private void initPage() throws IOException { Map dict; - dict = DataUtils.map(new String[]{"Type"}, new Object[]{"Catalog"}); + dict = map(new String[]{"Type"}, new Object[]{"Catalog"}); PDFObject catalog = addObject(dict, null); List pagesKids = new LinkedList<>(); - dict = DataUtils.map( + dict = map( new String[]{"Type", "Kids", "Count"}, new Object[]{"Pages", pagesKids, 1}); PDFObject pages = addObject(dict, null); @@ -382,7 +385,7 @@ public class PDFProcessorResult implements ProcessorResult { double y = pageSize.getY() * MM_IN_UNITS; double width = pageSize.getWidth() * MM_IN_UNITS; double height = pageSize.getHeight() * MM_IN_UNITS; - dict = DataUtils.map( + dict = map( new String[]{"Type", "Parent", "MediaBox"}, new Object[]{"Page", pages, new double[]{x, y, width, height}}); PDFObject page = addObject(dict, null); @@ -398,11 +401,12 @@ public class PDFProcessorResult implements ProcessorResult { // ignore } } - contentsPayload.write(DataUtils.join("", new Object[]{ - "q", EOL, + String s = String.join("", "q", EOL, getOutput(getCurrentState().getColor()), EOL, - MM_IN_UNITS, " 0 0 ", -MM_IN_UNITS, " 0 ", height, " cm", EOL - }).getBytes(CHARSET)); + Double.toString(MM_IN_UNITS), " 0 0 ", + Double.toString(-MM_IN_UNITS), " 0 ", + Double.toString(height), " cm", EOL); + contentsPayload.write(s.getBytes(CHARSET)); Payload contentLengthPayload = new SizePayload(contents, CHARSET, false); PDFObject contentLength = addObject(null, contentLengthPayload); contents.dict.put("Length", contentLength); @@ -424,10 +428,10 @@ public class PDFProcessorResult implements ProcessorResult { } private PDFObject addObject(Image image) throws IOException { - BufferedImage bufferedImage = GraphicsUtils.toBufferedImage(image); + BufferedImage bufferedImage = toBufferedImage(image); int width = bufferedImage.getWidth(); int height = bufferedImage.getHeight(); - int bitsPerSample = DataUtils.max(bufferedImage.getSampleModel().getSampleSize()); + int bitsPerSample = max(bufferedImage.getSampleModel().getSampleSize()); int bands = bufferedImage.getSampleModel().getNumBands(); String colorSpaceName = (bands == 1) ? "DeviceGray" : "DeviceRGB"; Payload imagePayload = new Payload(true); @@ -440,11 +444,11 @@ public class PDFProcessorResult implements ProcessorResult { // ignore } } - InputStream imageDataStream = new ImageDataStream(bufferedImage, Interleaving.WITHOUT_ALPHA); - DataUtils.transfer(imageDataStream, imagePayload, 1024); + InputStream imageDataStream = new ImageDataStream(bufferedImage, ImageDataStream.Interleaving.WITHOUT_ALPHA); + imageDataStream.transferTo(imagePayload); imagePayload.close(); int length = imagePayload.getBytes().length; - Map imageDict = DataUtils.map( + Map imageDict = map( new String[]{"Type", "Subtype", "Width", "Height", "ColorSpace", "BitsPerComponent", "Length", "Filter"}, new Object[]{"XObject", "Image", width, height, colorSpaceName, @@ -453,7 +457,7 @@ public class PDFProcessorResult implements ProcessorResult { PDFObject imageObject = addObject(imageDict, imagePayload); boolean hasAlpha = bufferedImage.getColorModel().hasAlpha(); if (hasAlpha) { - BufferedImage mask = GraphicsUtils.getAlphaImage(bufferedImage); + BufferedImage mask = getAlphaImage(bufferedImage); PDFObject maskObject = addObject(mask); boolean isBitmask = mask.getSampleModel().getSampleSize(0) == 1; if (isBitmask) { @@ -477,20 +481,19 @@ public class PDFProcessorResult implements ProcessorResult { } long xrefPos = o.tell(); o.writeln("xref"); - o.write(0).write(" ").writeln(objects.size() + 1); + o.write(format(0)).write(" ").writeln(format(objects.size() + 1)); o.format("%010d %05d f ", 0, 65535).writeln(); for (PDFObject obj : objects) { o.format("%010d %05d n ", xref.get(obj), 0).writeln(); } o.flush(); o.writeln("trailer"); - o.writeln(serialize(DataUtils.map( + o.writeln(serialize(map( new String[]{"Size", "Root"}, new Object[]{objects.size() + 1, objects.get(0)} ))); - o.writeln("startxref"); - o.writeln(xrefPos); + o.writeln(format(xrefPos)); o.writeln(FOOTER); o.flush(); } @@ -532,7 +535,7 @@ public class PDFProcessorResult implements ProcessorResult { for (Command command : commands) { if (command instanceof SetHintCommand) { SetHintCommand c = (SetHintCommand) command; - getCurrentState().getHints().put(c.getKey(), c.getValue()); + getCurrentState().getHints().put(c.getHintKey(), c.getValue()); } else if (command instanceof SetBackgroundCommand) { SetBackgroundCommand c = (SetBackgroundCommand) command; getCurrentState().setBackground(c.getValue()); @@ -581,5 +584,202 @@ public class PDFProcessorResult implements ProcessorResult { contentsPayload.write(footer.getBytes(CHARSET)); contentsPayload.close(); } -} + /** + * Creates a mapping from two arrays, one with keys, one with values. + * + * @param Data type of the keys. + * @param Data type of the values. + * @param keys Array containing the keys. + * @param values Array containing the values. + * @return Map with keys and values from the specified arrays. + */ + private static Map map(K[] keys, V[] values) { + if (keys.length != values.length) { + throw new IllegalArgumentException("Cannot create a Map: number of keys and values differs."); + } + // Fill map with keys and values + Map map = new LinkedHashMap<>(keys.length); + for (int i = 0; i < keys.length; i++) { + map.put(keys[i], values[i]); + } + return map; + } + + /** + * Converts an array of {@code float} numbers to a list of {@code Float}s. + * The list will be empty if the array is empty or {@code null}. + * + * @param elements Array of float numbers. + * @return A list with all numbers as {@code Float}. + */ + private static List asList(float[] elements) { + int size = elements != null ? elements.length : 0; + List list = new ArrayList<>(size); + if (elements != null) { + for (Float elem : elements) { + list.add(elem); + } + } + return list; + } + + /** + * Converts an array of {@code double} numbers to a list of {@code Double}s. + * The list will be empty if the array is empty or {@code null}. + * + * @param elements Array of double numbers. + * @return A list with all numbers as {@code Double}. + */ + private static List asList(double[] elements) { + int size = (elements != null) ? elements.length : 0; + List list = new ArrayList<>(size); + if (elements != null) { + for (Double elem : elements) { + list.add(elem); + } + } + return list; + } + + /** + * Returns a formatted string of the specified number. All trailing zeroes + * or decimal points will be stripped. + * + * @param number Number to convert to a string. + * @return A formatted string. + */ + private static String format(Number number) { + String formatted; + if (number instanceof Double || number instanceof Float) { + formatted = Double.toString(number.doubleValue()) + .replaceAll("\\.0+$", "") + .replaceAll("(\\.[0-9]*[1-9])0+$", "$1"); + } else { + formatted = number.toString(); + } + return formatted; + } + + /** + * Returns a formatted string of the specified object. + * + * @param obj Object to convert to a string. + * @return A formatted string. + */ + private static String format(Object obj) { + if (obj instanceof Number) { + return format((Number) obj); + } else { + return obj.toString(); + } + } + + /** + * Returns the largest of all specified values. + * + * @param values Several integer values. + * @return largest value. + */ + public static int max(int... values) { + int max = values[0]; + for (int i = 1; i < values.length; i++) { + if (values[i] > max) { + max = values[i]; + } + } + return max; + } + + /** + * This method returns a buffered image with the contents of an image. + * Taken from http://www.exampledepot.com/egs/java.awt.image/Image2Buf.html + * + * @param image Image to be converted + * @return a buffered image with the contents of the specified image + */ + private static BufferedImage toBufferedImage(Image image) { + if (image instanceof BufferedImage) { + return (BufferedImage) image; + } + image = new ImageIcon(image).getImage(); + boolean hasAlpha = hasAlpha(image); + BufferedImage bimage; + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + try { + int transparency = Transparency.OPAQUE; + if (hasAlpha) { + transparency = Transparency.TRANSLUCENT; + } + GraphicsDevice gs = ge.getDefaultScreenDevice(); + GraphicsConfiguration gc = gs.getDefaultConfiguration(); + bimage = gc.createCompatibleImage(image.getWidth(null), image.getHeight(null), transparency); + } catch (HeadlessException e) { + bimage = null; + } + if (bimage == null) { + int type = BufferedImage.TYPE_INT_RGB; + if (hasAlpha) { + type = BufferedImage.TYPE_INT_ARGB; + } + bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type); + } + Graphics g = bimage.createGraphics(); + g.drawImage(image, 0, 0, null); + g.dispose(); + return bimage; + } + + /** + * This method returns {@code true} if the specified image has the + * possibility to store transparent pixels. + * Inspired by http://www.exampledepot.com/egs/java.awt.image/HasAlpha.html + * + * @param image Image that should be checked for alpha channel. + * @return {@code true} if the specified image can have transparent pixels, + * {@code false} otherwise + */ + private static boolean hasAlpha(Image image) { + ColorModel cm; + if (image instanceof BufferedImage) { + BufferedImage bimage = (BufferedImage) image; + cm = bimage.getColorModel(); + } else { + PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false); + try { + pg.grabPixels(); + } catch (InterruptedException e) { + return false; + } + cm = pg.getColorModel(); + } + return cm.hasAlpha(); + } + + private static BufferedImage getAlphaImage(BufferedImage image) { + WritableRaster alphaRaster = image.getAlphaRaster(); + int width = image.getWidth(); + int height = image.getHeight(); + ColorModel cm; + WritableRaster raster; + ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY); + int[] bits = {8}; + cm = new ComponentColorModel(colorSpace, bits, false, true, + Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + raster = cm.createCompatibleWritableRaster(width, height); + BufferedImage alphaImage = new BufferedImage(cm, raster, false, null); + int[] alphaValues = new int[image.getWidth() * alphaRaster.getNumBands()]; + for (int y = 0; y < image.getHeight(); y++) { + alphaRaster.getPixels(0, y, image.getWidth(), 1, alphaValues); + if (image.getTransparency() == BufferedImage.BITMASK) { + for (int i = 0; i < alphaValues.length; i++) { + if (alphaValues[i] > 0) { + alphaValues[i] = 255; + } + } + } + alphaImage.getRaster().setPixels(0, y, image.getWidth(), 1, alphaValues); + } + return alphaImage; + } +} diff --git a/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/FlateEncodeStream.java b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/FlateEncodeStream.java new file mode 100644 index 0000000..ab9efdd --- /dev/null +++ b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/FlateEncodeStream.java @@ -0,0 +1,11 @@ +package org.xbib.graphics.io.vector.pdf.util; + +import java.io.OutputStream; +import java.util.zip.DeflaterOutputStream; + +public class FlateEncodeStream extends DeflaterOutputStream { + public FlateEncodeStream(OutputStream out) { + super(out); + } +} + diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/FormattingWriter.java b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/FormattingWriter.java similarity index 80% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/util/FormattingWriter.java rename to io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/FormattingWriter.java index 5ca14d0..52bdebf 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/FormattingWriter.java +++ b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/FormattingWriter.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.io.vector.util; +package org.xbib.graphics.io.vector.pdf.util; import java.io.Closeable; import java.io.Flushable; @@ -24,11 +24,6 @@ public class FormattingWriter implements Closeable, Flushable { return this; } - public FormattingWriter write(Number number) throws IOException { - write(DataUtils.format(number)); - return this; - } - public FormattingWriter writeln() throws IOException { write(eolString); return this; @@ -40,12 +35,6 @@ public class FormattingWriter implements Closeable, Flushable { return this; } - public FormattingWriter writeln(Number number) throws IOException { - write(number); - write(eolString); - return this; - } - public FormattingWriter format(String format, Object... args) throws IOException { write(String.format(null, format, args)); return this; diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/GeneratedPayload.java b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/GeneratedPayload.java similarity index 80% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/GeneratedPayload.java rename to io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/GeneratedPayload.java index 2cf8229..d60fcfd 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/GeneratedPayload.java +++ b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/GeneratedPayload.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.io.vector.pdf; +package org.xbib.graphics.io.vector.pdf.util; import java.io.IOException; @@ -17,8 +17,8 @@ public abstract class GeneratedPayload extends Payload { } @Override - public void write(int b) throws IOException { - throw new UnsupportedOperationException("Payload will be calculated and is read only."); + public void write(int b) { + throw new UnsupportedOperationException("Payload will be calculated and is read only"); } protected abstract byte[] generatePayload() throws IOException; diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/ImageDataStream.java b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/ImageDataStream.java similarity index 98% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/util/ImageDataStream.java rename to io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/ImageDataStream.java index 6e98d56..00133b6 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/ImageDataStream.java +++ b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/ImageDataStream.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.io.vector.util; +package org.xbib.graphics.io.vector.pdf.util; import java.awt.image.BufferedImage; import java.awt.image.Raster; diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/PDFObject.java b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/PDFObject.java similarity index 91% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/PDFObject.java rename to io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/PDFObject.java index d831a64..a01b6bc 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/PDFObject.java +++ b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/PDFObject.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.io.vector.pdf; +package org.xbib.graphics.io.vector.pdf.util; import java.util.LinkedHashMap; import java.util.Map; diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/Payload.java b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/Payload.java similarity index 96% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/Payload.java rename to io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/Payload.java index 3daed17..d8300a1 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/Payload.java +++ b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/Payload.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.io.vector.pdf; +package org.xbib.graphics.io.vector.pdf.util; import java.io.ByteArrayOutputStream; import java.io.FilterOutputStream; diff --git a/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/Resources.java b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/Resources.java new file mode 100644 index 0000000..da8977f --- /dev/null +++ b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/Resources.java @@ -0,0 +1,198 @@ +package org.xbib.graphics.io.vector.pdf.util; + +import java.awt.Font; +import java.awt.GraphicsEnvironment; +import java.awt.font.FontRenderContext; +import java.awt.font.TextLayout; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +public class Resources extends PDFObject { + + private static final String KEY_PROC_SET = "ProcSet"; + + private static final String KEY_TRANSPARENCY = "ExtGState"; + + private static final String KEY_FONT = "Font"; + + private static final String KEY_IMAGE = "XObject"; + + private static final String[] VALUE_PROC_SET = {"PDF", "Text", "ImageB", "ImageC", "ImageI"}; + + private static final String PREFIX_FONT = "Fnt"; + + private static final String PREFIX_IMAGE = "Img"; + + private static final String PREFIX_TRANSPARENCY = "Trp"; + + private final Map fonts; + + private final Map images; + + private final Map transparencies; + + private final AtomicInteger currentFontId = new AtomicInteger(); + + private final AtomicInteger currentImageId = new AtomicInteger(); + + private final AtomicInteger currentTransparencyId = new AtomicInteger(); + + public Resources(int id, int version) { + super(id, version, null, null); + fonts = new HashMap<>(); + images = new HashMap<>(); + transparencies = new HashMap<>(); + dict.put(KEY_PROC_SET, VALUE_PROC_SET); + } + + private String getResourceId(Map resources, T resource, + String idPrefix, AtomicInteger idCounter) { + String id = resources.get(resource); + if (id == null) { + id = String.format("%s%d", idPrefix, idCounter.getAndIncrement()); + resources.put(resource, id); + } + return id; + } + + @SuppressWarnings("unchecked") + public String getId(Font font) { + Map> dictEntry = + (Map>) dict.get(KEY_FONT); + if (dictEntry == null) { + dictEntry = new LinkedHashMap<>(); + dict.put(KEY_FONT, dictEntry); + } + font = getPhysicalFont(font); + String resourceId = getResourceId(fonts, font, PREFIX_FONT, currentFontId); + String fontName = font.getPSName(); + String fontEncoding = "WinAnsiEncoding"; + dictEntry.put(resourceId, Map.of("Type", "Font", + "Subtype", "TrueType", + "Encoding", fontEncoding, + "BaseFont", fontName + )); + return resourceId; + } + + @SuppressWarnings("unchecked") + public String getId(PDFObject image) { + Map dictEntry = (Map) dict.get(KEY_IMAGE); + if (dictEntry == null) { + dictEntry = new LinkedHashMap<>(); + dict.put(KEY_IMAGE, dictEntry); + } + String resourceId = getResourceId(images, image, PREFIX_IMAGE, currentImageId); + dictEntry.put(resourceId, image); + return resourceId; + } + + @SuppressWarnings("unchecked") + public String getId(Double transparency) { + Map> dictEntry = + (Map>) dict.get(KEY_TRANSPARENCY); + if (dictEntry == null) { + dictEntry = new LinkedHashMap<>(); + dict.put(KEY_TRANSPARENCY, dictEntry); + } + String resourceId = getResourceId(transparencies, transparency, + PREFIX_TRANSPARENCY, currentTransparencyId); + dictEntry.put(resourceId, Map.of("Type", "ExtGState", + "ca", transparency, + "CA", transparency)); + return resourceId; + } + + /** + * Try to guess physical font from the properties of a logical font, like + * "Dialog", "Serif", "Monospaced" etc. + * + * @param logicalFont Logical font object. + * @param testText Text used to determine font properties. + * @return An object of the first matching physical font. The original font + * object is returned if it was a physical font or no font matched. + */ + public static Font getPhysicalFont(Font logicalFont, String testText) { + String logicalFamily = logicalFont.getFamily(); + if (!isLogicalFontFamily(logicalFamily)) { + return logicalFont; + } + final TextLayout logicalLayout = new TextLayout(testText, logicalFont, FONT_RENDER_CONTEXT); + Queue physicalFonts = new PriorityQueue<>(1, FONT_EXPRESSIVENESS_COMPARATOR); + Font[] allPhysicalFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); + for (Font physicalFont : allPhysicalFonts) { + String physicalFamily = physicalFont.getFamily(); + if (isLogicalFontFamily(physicalFamily)) { + continue; + } + physicalFont = physicalFont.deriveFont(logicalFont.getStyle(), logicalFont.getSize2D()); + TextLayout physicalLayout = new TextLayout(testText, physicalFont, FONT_RENDER_CONTEXT); + if (physicalLayout.getBounds().equals(logicalLayout.getBounds()) && + physicalLayout.getAscent() == logicalLayout.getAscent() && + physicalLayout.getDescent() == logicalLayout.getDescent() && + physicalLayout.getLeading() == logicalLayout.getLeading() && + physicalLayout.getAdvance() == logicalLayout.getAdvance() && + physicalLayout.getVisibleAdvance() == logicalLayout.getVisibleAdvance()) { + physicalFonts.add(physicalFont); + } + } + if (physicalFonts.isEmpty()) { + return logicalFont; + } + return physicalFonts.poll(); + } + + public static Font getPhysicalFont(Font logicalFont) { + return getPhysicalFont(logicalFont, FONT_TEST_STRING); + } + + private static boolean isLogicalFontFamily(String family) { + return (Font.DIALOG.equals(family) || + Font.DIALOG_INPUT.equals(family) || + Font.SANS_SERIF.equals(family) || + Font.SERIF.equals(family) || + Font.MONOSPACED.equals(family)); + } + + private static final FontRenderContext FONT_RENDER_CONTEXT = + new FontRenderContext(null, false, true); + + private static final String FONT_TEST_STRING = + "Falsches Üben von Xylophonmusik quält jeden größeren Zwerg"; + + private static final FontExpressivenessComparator FONT_EXPRESSIVENESS_COMPARATOR = + new FontExpressivenessComparator(); + + private static class FontExpressivenessComparator implements Comparator { + private static final int[] STYLES = { + Font.PLAIN, Font.ITALIC, Font.BOLD, Font.BOLD | Font.ITALIC + }; + + @Override + public int compare(Font font1, Font font2) { + if (font1 == font2) { + return 0; + } + Set variantNames1 = new HashSet<>(); + Set variantNames2 = new HashSet<>(); + for (int style : STYLES) { + variantNames1.add(font1.deriveFont(style).getPSName()); + variantNames2.add(font2.deriveFont(style).getPSName()); + } + if (variantNames1.size() < variantNames2.size()) { + return 1; + } else if (variantNames1.size() > variantNames2.size()) { + return -1; + } + return font1.getName().compareTo(font2.getName()); + } + } + +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/SizePayload.java b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/SizePayload.java similarity index 75% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/SizePayload.java rename to io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/SizePayload.java index 907963e..5b56b59 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/SizePayload.java +++ b/io-vector-pdf/src/main/java/org/xbib/graphics/io/vector/pdf/util/SizePayload.java @@ -1,6 +1,5 @@ -package org.xbib.graphics.io.vector.pdf; +package org.xbib.graphics.io.vector.pdf.util; -import org.xbib.graphics.io.vector.util.DataUtils; import java.io.IOException; public class SizePayload extends GeneratedPayload { @@ -18,8 +17,7 @@ public class SizePayload extends GeneratedPayload { @Override protected byte[] generatePayload() throws IOException { object.payload.close(); - String content = DataUtils.format(object.payload.getBytes().length); + String content = Integer.toString(object.payload.getBytes().length); return content.getBytes(charset); } } - diff --git a/io-vector-pdf/src/main/resources/META-INF/services/org.xbib.graphics.io.vector.VectorGraphics2DProvider b/io-vector-pdf/src/main/resources/META-INF/services/org.xbib.graphics.io.vector.VectorGraphics2DProvider new file mode 100644 index 0000000..afc4ae2 --- /dev/null +++ b/io-vector-pdf/src/main/resources/META-INF/services/org.xbib.graphics.io.vector.VectorGraphics2DProvider @@ -0,0 +1 @@ +org.xbib.graphics.io.vector.pdf.PDFGraphics2DProvider diff --git a/io-vector/src/test/java/org/xbib/graphics/io/vector/pdf/PDFProcessorTest.java b/io-vector-pdf/src/test/java/org/xbib/graphics/io/vector/pdf/PDFProcessorTest.java similarity index 92% rename from io-vector/src/test/java/org/xbib/graphics/io/vector/pdf/PDFProcessorTest.java rename to io-vector-pdf/src/test/java/org/xbib/graphics/io/vector/pdf/PDFProcessorTest.java index f8d1e3e..04c9e7a 100644 --- a/io-vector/src/test/java/org/xbib/graphics/io/vector/pdf/PDFProcessorTest.java +++ b/io-vector-pdf/src/test/java/org/xbib/graphics/io/vector/pdf/PDFProcessorTest.java @@ -1,7 +1,5 @@ package org.xbib.graphics.io.vector.pdf; -import static org.xbib.graphics.io.vector.TestUtils.Template; -import static org.xbib.graphics.io.vector.TestUtils.assertTemplateEquals; import org.junit.jupiter.api.Test; import org.xbib.graphics.io.vector.Command; import org.xbib.graphics.io.vector.PageSize; @@ -32,8 +30,8 @@ public class PDFProcessorTest { @Test public void envelopeForEmptyDocument() throws IOException { String result = process(); - Template actual = new Template(result.split(EOL)); - Template expected = new Template(new Object[]{ + TestUtils.Template actual = new TestUtils.Template(result.split(EOL)); + TestUtils.Template expected = new TestUtils.Template(new Object[]{ HEADER, "1 0 obj", "<<", @@ -103,7 +101,7 @@ public class PDFProcessorTest { Pattern.compile("[1-9]\\d*"), FOOTER }); - assertTemplateEquals(expected, actual); + TestUtils.assertTemplateEquals(expected, actual); } } diff --git a/io-vector-pdf/src/test/java/org/xbib/graphics/io/vector/pdf/TestUtils.java b/io-vector-pdf/src/test/java/org/xbib/graphics/io/vector/pdf/TestUtils.java new file mode 100644 index 0000000..f73e47c --- /dev/null +++ b/io-vector-pdf/src/test/java/org/xbib/graphics/io/vector/pdf/TestUtils.java @@ -0,0 +1,50 @@ +package org.xbib.graphics.io.vector.pdf; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public abstract class TestUtils { + + protected TestUtils() { + throw new UnsupportedOperationException(); + } + + public static void assertTemplateEquals(Template expected, Template actual) { + Iterator itExpected = expected.iterator(); + Iterator itActual = actual.iterator(); + while (itExpected.hasNext() && itActual.hasNext()) { + Object lineExpected = itExpected.next(); + Object lineActual = itActual.next(); + if (lineExpected == null) { + continue; + } + assertTrue(lineActual instanceof String, String.format("Line is of type %s, expected String.", lineActual.getClass())); + if (lineExpected instanceof String) { + assertEquals(lineExpected, lineActual, "not equal, actual is " + actual); + } else if (lineExpected instanceof Pattern) { + Pattern expectedPattern = (Pattern) lineExpected; + Matcher matcher = expectedPattern.matcher((String) lineActual); + assertTrue(matcher.matches(), String.format("Line didn't match pattern.\nExpected: \"%s\"\nActual: \"%s\"", matcher.pattern(), lineActual)); + } + } + assertEquals(expected.size(), actual.size(), "Wrong number of lines in template."); + } + + @SuppressWarnings("serial") + public static class Template extends LinkedList { + public Template(Object[] lines) { + Collections.addAll(this, lines); + } + + public Template(Template[] templates) { + for (Template template : templates) { + addAll(template); + } + } + } +} diff --git a/io-vector-svg/build.gradle b/io-vector-svg/build.gradle new file mode 100644 index 0000000..b04c262 --- /dev/null +++ b/io-vector-svg/build.gradle @@ -0,0 +1,3 @@ +dependencies { + api project(':io-vector') +} diff --git a/io-vector-svg/src/main/java/module-info.java b/io-vector-svg/src/main/java/module-info.java new file mode 100644 index 0000000..2a3d589 --- /dev/null +++ b/io-vector-svg/src/main/java/module-info.java @@ -0,0 +1,6 @@ +module org.xbib.graphics.io.vector.svg { + exports org.xbib.graphics.io.vector.svg; + requires transitive org.xbib.graphics.io.vector; + provides org.xbib.graphics.io.vector.VectorGraphics2DProvider with + org.xbib.graphics.io.vector.svg.SVGGraphics2DProvider; +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/svg/SVGGraphics2D.java b/io-vector-svg/src/main/java/org/xbib/graphics/io/vector/svg/SVGGraphics2D.java similarity index 100% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/svg/SVGGraphics2D.java rename to io-vector-svg/src/main/java/org/xbib/graphics/io/vector/svg/SVGGraphics2D.java diff --git a/io-vector-svg/src/main/java/org/xbib/graphics/io/vector/svg/SVGGraphics2DProvider.java b/io-vector-svg/src/main/java/org/xbib/graphics/io/vector/svg/SVGGraphics2DProvider.java new file mode 100644 index 0000000..dd038ec --- /dev/null +++ b/io-vector-svg/src/main/java/org/xbib/graphics/io/vector/svg/SVGGraphics2DProvider.java @@ -0,0 +1,15 @@ +package org.xbib.graphics.io.vector.svg; + +import org.xbib.graphics.io.vector.VectorGraphics2DProvider; + +public class SVGGraphics2DProvider implements VectorGraphics2DProvider { + @Override + public String name() { + return "eps"; + } + + @Override + public SVGGraphics2D provide(double x, double y, double width, double height) { + return new SVGGraphics2D(x, y, width, height); + } +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/svg/SVGProcessor.java b/io-vector-svg/src/main/java/org/xbib/graphics/io/vector/svg/SVGProcessor.java similarity index 100% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/svg/SVGProcessor.java rename to io-vector-svg/src/main/java/org/xbib/graphics/io/vector/svg/SVGProcessor.java diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/svg/SVGProcessorResult.java b/io-vector-svg/src/main/java/org/xbib/graphics/io/vector/svg/SVGProcessorResult.java similarity index 61% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/svg/SVGProcessorResult.java rename to io-vector-svg/src/main/java/org/xbib/graphics/io/vector/svg/SVGProcessorResult.java index c9d6353..79e6f34 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/svg/SVGProcessorResult.java +++ b/io-vector-svg/src/main/java/org/xbib/graphics/io/vector/svg/SVGProcessorResult.java @@ -6,7 +6,6 @@ import org.w3c.dom.DocumentType; import org.w3c.dom.Element; import org.xbib.graphics.io.vector.GraphicsState; import org.xbib.graphics.io.vector.ProcessorResult; -import org.xbib.graphics.io.vector.util.VectorHints; import org.xbib.graphics.io.vector.commands.AffineTransformCommand; import org.xbib.graphics.io.vector.Command; import org.xbib.graphics.io.vector.commands.CreateCommand; @@ -25,16 +24,23 @@ import org.xbib.graphics.io.vector.commands.SetHintCommand; import org.xbib.graphics.io.vector.commands.SetPaintCommand; import org.xbib.graphics.io.vector.commands.SetStrokeCommand; import org.xbib.graphics.io.vector.commands.SetTransformCommand; -import org.xbib.graphics.io.vector.util.Base64EncodeStream; -import org.xbib.graphics.io.vector.util.DataUtils; -import org.xbib.graphics.io.vector.util.GraphicsUtils; import org.xbib.graphics.io.vector.PageSize; +import org.xbib.graphics.io.vector.svg.util.Base64EncodeStream; +import org.xbib.graphics.io.vector.svg.util.VectorHints; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; import java.awt.Image; import java.awt.Shape; import java.awt.Stroke; +import java.awt.Transparency; +import java.awt.font.FontRenderContext; +import java.awt.font.TextLayout; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.geom.Line2D; @@ -42,17 +48,30 @@ import java.awt.geom.PathIterator; import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.PixelGrabber; +import java.awt.image.Raster; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Comparator; import java.util.Deque; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.PriorityQueue; +import java.util.Queue; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import javax.imageio.ImageIO; +import javax.swing.ImageIcon; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -82,21 +101,24 @@ public class SVGProcessorResult implements ProcessorResult { private static final String CHARSET = "UTF-8"; private static final double DOTS_PER_MM = 2.834646; // 72 dpi + //private static final double DOTS_PER_MM = 11.811024; // 300 dpi /** * Mapping of stroke endcap values from Java to SVG. */ - private static final Map STROKE_ENDCAPS = - DataUtils.map(new Integer[]{BasicStroke.CAP_BUTT, BasicStroke.CAP_ROUND, BasicStroke.CAP_SQUARE}, - new String[]{"butt", "round", "square"} + private static final Map STROKE_ENDCAPS = Map.of( + BasicStroke.CAP_BUTT, "butt", + BasicStroke.CAP_ROUND, "round", + BasicStroke.CAP_SQUARE, "square" ); /** * Mapping of line join values for path drawing from Java to SVG. */ - private static final Map STROKE_LINEJOIN = - DataUtils.map(new Integer[]{BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND, BasicStroke.JOIN_BEVEL}, - new String[]{"miter", "round", "bevel"} + private static final Map STROKE_LINEJOIN = Map.of( + BasicStroke.JOIN_MITER, "miter", + BasicStroke.JOIN_ROUND, "round", + BasicStroke.JOIN_BEVEL, "bevel" ); private final PageSize pageSize; @@ -131,11 +153,10 @@ public class SVGProcessorResult implements ProcessorResult { DOMImplementation domImpl = docBuilder.getDOMImplementation(); DocumentType docType = domImpl.createDocumentType(SVG_DOCTYPE_QNAME, SVG_DOCTYPE_PUBLIC_ID, SVG_DOCTYPE_SYSTEM_ID); doc = domImpl.createDocument(SVG_NAMESPACE_URI, "svg", docType); - // FIXME: Some XML parsers don't support setting standalone to "false" try { doc.setXmlStandalone(false); } catch (AbstractMethodError e) { - throw new IllegalStateException("Your XML parser does not support standalone XML documents."); + throw new IllegalStateException("Your XML parser does not support standalone XML documents"); } root = doc.getDocumentElement(); initRoot(); @@ -145,19 +166,20 @@ public class SVGProcessorResult implements ProcessorResult { private static void appendStyle(StringBuilder style, String attribute, Object value) { style.append(attribute).append(":") - .append(DataUtils.format(value)).append(";"); + .append(format(value)).append(";"); } private static String getOutput(AffineTransform tx) { StringBuilder out = new StringBuilder(); if (AffineTransform.getTranslateInstance(tx.getTranslateX(), tx.getTranslateY()).equals(tx)) { out.append("translate(") - .append(DataUtils.format(tx.getTranslateX())).append(" ") - .append(DataUtils.format(tx.getTranslateY())).append(")"); + .append(format(tx.getTranslateX())).append(" ") + .append(format(tx.getTranslateY())).append(")"); } else { double[] matrix = new double[6]; tx.getMatrix(matrix); - out.append("matrix(").append(DataUtils.join(" ", matrix)).append(")"); + String s = Arrays.stream(matrix).mapToObj(String::valueOf).collect(Collectors.joining(" ")); + out.append("matrix(").append(s).append(")"); } return out.toString(); } @@ -204,49 +226,6 @@ public class SVGProcessorResult implements ProcessorResult { return out.toString(); } - private static String getOutput(Font font) { - StringBuilder out = new StringBuilder(); - if (!GraphicsState.DEFAULT_FONT.getFamily().equals(font.getFamily())) { - String physicalFamily = GraphicsUtils.getPhysicalFont(font).getFamily(); - out.append("font-family:\"").append(physicalFamily).append("\";"); - } - if (font.getSize2D() != GraphicsState.DEFAULT_FONT.getSize2D()) { - out.append("font-size:").append(DataUtils.format(font.getSize2D())).append("px;"); - } - if ((font.getStyle() & Font.ITALIC) != 0) { - out.append("font-style:italic;"); - } - if ((font.getStyle() & Font.BOLD) != 0) { - out.append("font-weight:bold;"); - } - return out.toString(); - } - - private static String getOutput(Image image, boolean lossyAllowed) { - BufferedImage bufferedImage = GraphicsUtils.toBufferedImage(image); - String encoded = encodeImage(bufferedImage, "png"); - if (!GraphicsUtils.usesAlpha(bufferedImage) && lossyAllowed) { - String encodedLossy = encodeImage(bufferedImage, "jpeg"); - if (encodedLossy.length() > 0 && encodedLossy.length() < encoded.length()) { - encoded = encodedLossy; - } - } - return encoded; - } - - private static String encodeImage(BufferedImage bufferedImage, String format) { - ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); - Base64EncodeStream encodeStream = new Base64EncodeStream(byteStream); - try { - ImageIO.write(bufferedImage, format, encodeStream); - encodeStream.close(); - String encoded = byteStream.toString(StandardCharsets.ISO_8859_1); - return String.format("data:image/%s;base64,%s", format, encoded); - } catch (IOException e) { - return ""; - } - } - private GraphicsState getCurrentState() { return states.peek(); } @@ -258,11 +237,12 @@ public class SVGProcessorResult implements ProcessorResult { double height = pageSize.getHeight(); root.setAttribute("xmlns:" + XLINK_NAMESPACE, XLINK_NAMESPACE_URI); root.setAttribute("version", "1.1"); - root.setAttribute("x", DataUtils.format(x / DOTS_PER_MM) + "mm"); - root.setAttribute("y", DataUtils.format(y / DOTS_PER_MM) + "mm"); - root.setAttribute("width", DataUtils.format(width / DOTS_PER_MM) + "mm"); - root.setAttribute("height", DataUtils.format(height / DOTS_PER_MM) + "mm"); - root.setAttribute("viewBox", DataUtils.join(" ", new double[]{x, y, width, height})); + root.setAttribute("x", format(x / DOTS_PER_MM) + "mm"); + root.setAttribute("y", format(y / DOTS_PER_MM) + "mm"); + root.setAttribute("width", format(width / DOTS_PER_MM) + "mm"); + root.setAttribute("height", format(height / DOTS_PER_MM) + "mm"); + String s = Arrays.stream(new double[]{x, y, width, height}).mapToObj(String::valueOf).collect(Collectors.joining(" ")); + root.setAttribute("viewBox", s); } public void write(OutputStream out) throws IOException { @@ -406,7 +386,7 @@ public class SVGProcessorResult implements ProcessorResult { state.setTransform(stateTransform); } else if (command instanceof SetHintCommand) { SetHintCommand c = (SetHintCommand) command; - state.getHints().put(c.getKey(), c.getValue()); + state.getHints().put(c.getHintKey(), c.getValue()); } else if (command instanceof CreateCommand) { try { states.push((GraphicsState) getCurrentState().clone()); @@ -464,7 +444,12 @@ public class SVGProcessorResult implements ProcessorResult { appendStyle(style, "stroke-linejoin", STROKE_LINEJOIN.get(bs.getLineJoin())); } if (bs.getDashArray() != null) { - appendStyle(style, "stroke-dasharray", DataUtils.join(",", bs.getDashArray())); + float[] f = bs.getDashArray(); + String s = IntStream.range(0, f.length) + .mapToDouble(i -> f[i]) + .mapToObj(String::valueOf) + .collect(Collectors.joining(",")); + appendStyle(style, "stroke-dasharray", s); if (bs.getDashPhase() != 0f) { appendStyle(style, "stroke-dashoffset", bs.getDashPhase()); } @@ -489,33 +474,33 @@ public class SVGProcessorResult implements ProcessorResult { if (shape instanceof Line2D) { Line2D s = (Line2D) shape; elem = doc.createElement("line"); - elem.setAttribute("x1", DataUtils.format(s.getX1())); - elem.setAttribute("y1", DataUtils.format(s.getY1())); - elem.setAttribute("x2", DataUtils.format(s.getX2())); - elem.setAttribute("y2", DataUtils.format(s.getY2())); + elem.setAttribute("x1", format(s.getX1())); + elem.setAttribute("y1", format(s.getY1())); + elem.setAttribute("x2", format(s.getX2())); + elem.setAttribute("y2", format(s.getY2())); } else if (shape instanceof Rectangle2D) { Rectangle2D s = (Rectangle2D) shape; elem = doc.createElement("rect"); - elem.setAttribute("x", DataUtils.format(s.getX())); - elem.setAttribute("y", DataUtils.format(s.getY())); - elem.setAttribute("width", DataUtils.format(s.getWidth())); - elem.setAttribute("height", DataUtils.format(s.getHeight())); + elem.setAttribute("x", format(s.getX())); + elem.setAttribute("y", format(s.getY())); + elem.setAttribute("width", format(s.getWidth())); + elem.setAttribute("height", format(s.getHeight())); } else if (shape instanceof RoundRectangle2D) { RoundRectangle2D s = (RoundRectangle2D) shape; elem = doc.createElement("rect"); - elem.setAttribute("x", DataUtils.format(s.getX())); - elem.setAttribute("y", DataUtils.format(s.getY())); - elem.setAttribute("width", DataUtils.format(s.getWidth())); - elem.setAttribute("height", DataUtils.format(s.getHeight())); - elem.setAttribute("rx", DataUtils.format(s.getArcWidth() / 2.0)); - elem.setAttribute("ry", DataUtils.format(s.getArcHeight() / 2.0)); + elem.setAttribute("x", format(s.getX())); + elem.setAttribute("y", format(s.getY())); + elem.setAttribute("width", format(s.getWidth())); + elem.setAttribute("height", format(s.getHeight())); + elem.setAttribute("rx", format(s.getArcWidth() / 2.0)); + elem.setAttribute("ry", format(s.getArcHeight() / 2.0)); } else if (shape instanceof Ellipse2D) { Ellipse2D s = (Ellipse2D) shape; elem = doc.createElement("ellipse"); - elem.setAttribute("cx", DataUtils.format(s.getCenterX())); - elem.setAttribute("cy", DataUtils.format(s.getCenterY())); - elem.setAttribute("rx", DataUtils.format(s.getWidth() / 2.0)); - elem.setAttribute("ry", DataUtils.format(s.getHeight() / 2.0)); + elem.setAttribute("cx", format(s.getCenterX())); + elem.setAttribute("cy", format(s.getCenterY())); + elem.setAttribute("rx", format(s.getWidth() / 2.0)); + elem.setAttribute("ry", format(s.getHeight() / 2.0)); } else { elem = doc.createElement("path"); elem.setAttribute("d", getOutput(shape)); @@ -526,22 +511,276 @@ public class SVGProcessorResult implements ProcessorResult { private Element getElement(String text, double x, double y) { Element elem = doc.createElement("text"); elem.appendChild(doc.createTextNode(text)); - elem.setAttribute("x", DataUtils.format(x)); - elem.setAttribute("y", DataUtils.format(y)); + elem.setAttribute("x", format(x)); + elem.setAttribute("y", format(y)); return elem; } private Element getElement(Image image, double x, double y, double width, double height) { Element elem = doc.createElement("image"); - elem.setAttribute("x", DataUtils.format(x)); - elem.setAttribute("y", DataUtils.format(y)); - elem.setAttribute("width", DataUtils.format(width)); - elem.setAttribute("height", DataUtils.format(height)); + elem.setAttribute("x", format(x)); + elem.setAttribute("y", format(y)); + elem.setAttribute("width", format(width)); + elem.setAttribute("height", format(height)); elem.setAttribute("preserveAspectRatio", "none"); boolean lossyAllowed = getCurrentState().getHints().get(VectorHints.KEY_EXPORT) == VectorHints.VALUE_EXPORT_SIZE; elem.setAttribute("xlink:href", getOutput(image, lossyAllowed)); return elem; } + + private static String getOutput(Font font) { + StringBuilder out = new StringBuilder(); + if (!GraphicsState.DEFAULT_FONT.getFamily().equals(font.getFamily())) { + String physicalFamily = getPhysicalFont(font).getFamily(); + out.append("font-family:\"").append(physicalFamily).append("\";"); + } + if (font.getSize2D() != GraphicsState.DEFAULT_FONT.getSize2D()) { + out.append("font-size:").append(format(font.getSize2D())).append("px;"); + } + if ((font.getStyle() & Font.ITALIC) != 0) { + out.append("font-style:italic;"); + } + if ((font.getStyle() & Font.BOLD) != 0) { + out.append("font-weight:bold;"); + } + return out.toString(); + } + + private static String getOutput(Image image, boolean lossyAllowed) { + BufferedImage bufferedImage = toBufferedImage(image); + String encoded = encodeImage(bufferedImage, "png"); + if (!usesAlpha(bufferedImage) && lossyAllowed) { + String encodedLossy = encodeImage(bufferedImage, "jpeg"); + if (encodedLossy.length() > 0 && encodedLossy.length() < encoded.length()) { + encoded = encodedLossy; + } + } + return encoded; + } + + /** + * This method returns {@code true} if the specified image has at least one + * pixel that is not fully opaque. + * + * @param image Image that should be checked for non-opaque pixels. + * @return {@code true} if the specified image has transparent pixels, + * {@code false} otherwise + */ + private static boolean usesAlpha(Image image) { + if (image == null) { + return false; + } + BufferedImage bimage = toBufferedImage(image); + Raster alphaRaster = bimage.getAlphaRaster(); + if (alphaRaster == null) { + return false; + } + DataBuffer dataBuffer = alphaRaster.getDataBuffer(); + for (int i = 0; i < dataBuffer.getSize(); i++) { + int alpha = dataBuffer.getElem(i); + if (alpha < 255) { + return true; + } + } + return false; + } + + private static String encodeImage(BufferedImage bufferedImage, String format) { + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + Base64EncodeStream encodeStream = new Base64EncodeStream(byteStream); + try { + ImageIO.write(bufferedImage, format, encodeStream); + encodeStream.close(); + String encoded = byteStream.toString(StandardCharsets.ISO_8859_1); + return String.format("data:image/%s;base64,%s", format, encoded); + } catch (IOException e) { + return ""; + } + } + + /** + * Returns a formatted string of the specified number. All trailing zeroes + * or decimal points will be stripped. + * + * @param number Number to convert to a string. + * @return A formatted string. + */ + private static String format(Number number) { + String formatted; + if (number instanceof Double || number instanceof Float) { + formatted = Double.toString(number.doubleValue()) + .replaceAll("\\.0+$", "") + .replaceAll("(\\.[0-9]*[1-9])0+$", "$1"); + } else { + formatted = number.toString(); + } + return formatted; + } + + /** + * Returns a formatted string of the specified object. + * + * @param obj Object to convert to a string. + * @return A formatted string. + */ + private static String format(Object obj) { + if (obj instanceof Number) { + return format((Number) obj); + } else { + return obj.toString(); + } + } + + + /** + * This method returns a buffered image with the contents of an image. + * Taken from http://www.exampledepot.com/egs/java.awt.image/Image2Buf.html + * + * @param image Image to be converted + * @return a buffered image with the contents of the specified image + */ + private static BufferedImage toBufferedImage(Image image) { + if (image instanceof BufferedImage) { + return (BufferedImage) image; + } + image = new ImageIcon(image).getImage(); + boolean hasAlpha = hasAlpha(image); + BufferedImage bimage; + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + try { + int transparency = Transparency.OPAQUE; + if (hasAlpha) { + transparency = Transparency.TRANSLUCENT; + } + GraphicsDevice gs = ge.getDefaultScreenDevice(); + GraphicsConfiguration gc = gs.getDefaultConfiguration(); + bimage = gc.createCompatibleImage(image.getWidth(null), image.getHeight(null), transparency); + } catch (HeadlessException e) { + bimage = null; + } + if (bimage == null) { + int type = BufferedImage.TYPE_INT_RGB; + if (hasAlpha) { + type = BufferedImage.TYPE_INT_ARGB; + } + bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type); + } + Graphics g = bimage.createGraphics(); + g.drawImage(image, 0, 0, null); + g.dispose(); + return bimage; + } + + /** + * This method returns {@code true} if the specified image has the + * possibility to store transparent pixels. + * Inspired by http://www.exampledepot.com/egs/java.awt.image/HasAlpha.html + * + * @param image Image that should be checked for alpha channel. + * @return {@code true} if the specified image can have transparent pixels, + * {@code false} otherwise + */ + private static boolean hasAlpha(Image image) { + ColorModel cm; + if (image instanceof BufferedImage) { + BufferedImage bimage = (BufferedImage) image; + cm = bimage.getColorModel(); + } else { + PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false); + try { + pg.grabPixels(); + } catch (InterruptedException e) { + return false; + } + cm = pg.getColorModel(); + } + return cm.hasAlpha(); + } + + /** + * Try to guess physical font from the properties of a logical font, like + * "Dialog", "Serif", "Monospaced" etc. + * + * @param logicalFont Logical font object. + * @param testText Text used to determine font properties. + * @return An object of the first matching physical font. The original font + * object is returned if it was a physical font or no font matched. + */ + public static Font getPhysicalFont(Font logicalFont, String testText) { + String logicalFamily = logicalFont.getFamily(); + if (!isLogicalFontFamily(logicalFamily)) { + return logicalFont; + } + final TextLayout logicalLayout = new TextLayout(testText, logicalFont, FONT_RENDER_CONTEXT); + Queue physicalFonts = new PriorityQueue<>(1, FONT_EXPRESSIVENESS_COMPARATOR); + Font[] allPhysicalFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); + for (Font physicalFont : allPhysicalFonts) { + String physicalFamily = physicalFont.getFamily(); + if (isLogicalFontFamily(physicalFamily)) { + continue; + } + physicalFont = physicalFont.deriveFont(logicalFont.getStyle(), logicalFont.getSize2D()); + TextLayout physicalLayout = new TextLayout(testText, physicalFont, FONT_RENDER_CONTEXT); + if (physicalLayout.getBounds().equals(logicalLayout.getBounds()) && + physicalLayout.getAscent() == logicalLayout.getAscent() && + physicalLayout.getDescent() == logicalLayout.getDescent() && + physicalLayout.getLeading() == logicalLayout.getLeading() && + physicalLayout.getAdvance() == logicalLayout.getAdvance() && + physicalLayout.getVisibleAdvance() == logicalLayout.getVisibleAdvance()) { + physicalFonts.add(physicalFont); + } + } + if (physicalFonts.isEmpty()) { + return logicalFont; + } + return physicalFonts.poll(); + } + + public static Font getPhysicalFont(Font logicalFont) { + return getPhysicalFont(logicalFont, FONT_TEST_STRING); + } + + private static boolean isLogicalFontFamily(String family) { + return (Font.DIALOG.equals(family) || + Font.DIALOG_INPUT.equals(family) || + Font.SANS_SERIF.equals(family) || + Font.SERIF.equals(family) || + Font.MONOSPACED.equals(family)); + } + + private static final FontRenderContext FONT_RENDER_CONTEXT = + new FontRenderContext(null, false, true); + + private static final String FONT_TEST_STRING = + "Falsches Üben von Xylophonmusik quält jeden größeren Zwerg"; + + private static final FontExpressivenessComparator FONT_EXPRESSIVENESS_COMPARATOR = + new FontExpressivenessComparator(); + + + private static class FontExpressivenessComparator implements Comparator { + private static final int[] STYLES = { + Font.PLAIN, Font.ITALIC, Font.BOLD, Font.BOLD | Font.ITALIC + }; + + public int compare(Font font1, Font font2) { + if (font1 == font2) { + return 0; + } + Set variantNames1 = new HashSet<>(); + Set variantNames2 = new HashSet<>(); + for (int style : STYLES) { + variantNames1.add(font1.deriveFont(style).getPSName()); + variantNames2.add(font2.deriveFont(style).getPSName()); + } + if (variantNames1.size() < variantNames2.size()) { + return 1; + } else if (variantNames1.size() > variantNames2.size()) { + return -1; + } + return font1.getName().compareTo(font2.getName()); + } + } } diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/Base64EncodeStream.java b/io-vector-svg/src/main/java/org/xbib/graphics/io/vector/svg/util/Base64EncodeStream.java similarity index 97% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/util/Base64EncodeStream.java rename to io-vector-svg/src/main/java/org/xbib/graphics/io/vector/svg/util/Base64EncodeStream.java index 4c4ae4e..2dca377 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/Base64EncodeStream.java +++ b/io-vector-svg/src/main/java/org/xbib/graphics/io/vector/svg/util/Base64EncodeStream.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.io.vector.util; +package org.xbib.graphics.io.vector.svg.util; import java.io.FilterOutputStream; import java.io.IOException; diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/VectorHints.java b/io-vector-svg/src/main/java/org/xbib/graphics/io/vector/svg/util/VectorHints.java similarity index 98% rename from io-vector/src/main/java/org/xbib/graphics/io/vector/util/VectorHints.java rename to io-vector-svg/src/main/java/org/xbib/graphics/io/vector/svg/util/VectorHints.java index 6792789..a7ec9c7 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/VectorHints.java +++ b/io-vector-svg/src/main/java/org/xbib/graphics/io/vector/svg/util/VectorHints.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.io.vector.util; +package org.xbib.graphics.io.vector.svg.util; import java.awt.RenderingHints; import java.util.HashSet; diff --git a/io-vector-svg/src/main/resources/META-INF/services/org.xbib.graphics.io.vector.VectorGraphics2DProvider b/io-vector-svg/src/main/resources/META-INF/services/org.xbib.graphics.io.vector.VectorGraphics2DProvider new file mode 100644 index 0000000..de650e2 --- /dev/null +++ b/io-vector-svg/src/main/resources/META-INF/services/org.xbib.graphics.io.vector.VectorGraphics2DProvider @@ -0,0 +1 @@ +org.xbib.graphics.io.vector.svg.SVGGraphics2DProvider diff --git a/io-vector/src/test/java/org/xbib/graphics/io/vector/util/Base64EncodeStreamTest.java b/io-vector-svg/src/test/java/org/xbib/graphics/io/vector/svg/Base64EncodeStreamTest.java similarity index 96% rename from io-vector/src/test/java/org/xbib/graphics/io/vector/util/Base64EncodeStreamTest.java rename to io-vector-svg/src/test/java/org/xbib/graphics/io/vector/svg/Base64EncodeStreamTest.java index 8edea6a..0259ee9 100644 --- a/io-vector/src/test/java/org/xbib/graphics/io/vector/util/Base64EncodeStreamTest.java +++ b/io-vector-svg/src/test/java/org/xbib/graphics/io/vector/svg/Base64EncodeStreamTest.java @@ -1,7 +1,8 @@ -package org.xbib.graphics.io.vector.util; +package org.xbib.graphics.io.vector.svg; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; +import org.xbib.graphics.io.vector.svg.util.Base64EncodeStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/io-vector/src/test/java/org/xbib/graphics/io/vector/svg/SVGProcessorTest.java b/io-vector-svg/src/test/java/org/xbib/graphics/io/vector/svg/SVGProcessorTest.java similarity index 87% rename from io-vector/src/test/java/org/xbib/graphics/io/vector/svg/SVGProcessorTest.java rename to io-vector-svg/src/test/java/org/xbib/graphics/io/vector/svg/SVGProcessorTest.java index 83f7be8..d03dfa0 100644 --- a/io-vector/src/test/java/org/xbib/graphics/io/vector/svg/SVGProcessorTest.java +++ b/io-vector-svg/src/test/java/org/xbib/graphics/io/vector/svg/SVGProcessorTest.java @@ -1,6 +1,5 @@ package org.xbib.graphics.io.vector.svg; -import static org.xbib.graphics.io.vector.TestUtils.assertXMLEquals; import org.junit.jupiter.api.Test; import org.xbib.graphics.io.vector.ProcessorResult; import org.xbib.graphics.io.vector.Command; @@ -20,7 +19,7 @@ public class SVGProcessorTest { private static final String HEADER = "" + EOL + "" + EOL + - "" + EOL; + "" + EOL; private static final String FOOTER = ""; private static final PageSize PAGE_SIZE = new PageSize(0.0, 10.0, 20.0, 30.0); @@ -39,7 +38,7 @@ public class SVGProcessorTest { public void envelopeForEmptyDocument() throws Exception { String result = process(); String expected = HEADER.replaceAll(">$", "/>"); - assertXMLEquals(expected, result); + TestUtils.assertXMLEquals(expected, result); } @Test @@ -51,7 +50,7 @@ public class SVGProcessorTest { HEADER + EOL + " " + EOL + FOOTER; - assertXMLEquals(expected, result); + TestUtils.assertXMLEquals(expected, result); } @Test @@ -63,6 +62,6 @@ public class SVGProcessorTest { HEADER + EOL + " " + EOL + FOOTER; - assertXMLEquals(expected, result); + TestUtils.assertXMLEquals(expected, result); } } diff --git a/io-vector-svg/src/test/java/org/xbib/graphics/io/vector/svg/TestUtils.java b/io-vector-svg/src/test/java/org/xbib/graphics/io/vector/svg/TestUtils.java new file mode 100644 index 0000000..6d38517 --- /dev/null +++ b/io-vector-svg/src/test/java/org/xbib/graphics/io/vector/svg/TestUtils.java @@ -0,0 +1,265 @@ +package org.xbib.graphics.io.vector.svg; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public abstract class TestUtils { + + protected TestUtils() { + throw new UnsupportedOperationException(); + } + + public static void assertTemplateEquals(Template expected, Template actual) { + Iterator itExpected = expected.iterator(); + Iterator itActual = actual.iterator(); + while (itExpected.hasNext() && itActual.hasNext()) { + Object lineExpected = itExpected.next(); + Object lineActual = itActual.next(); + if (lineExpected == null) { + continue; + } + assertTrue(lineActual instanceof String, + String.format("Line is of type %s, expected String.", lineActual.getClass())); + if (lineExpected instanceof String) { + assertEquals(lineExpected, lineActual); + } else if (lineExpected instanceof Pattern) { + Pattern expectedPattern = (Pattern) lineExpected; + Matcher matcher = expectedPattern.matcher((String) lineActual); + assertTrue(matcher.matches(), + String.format("Line didn't match pattern.\nExpected: \"%s\"\nActual: \"%s\"", matcher.pattern(), lineActual)); + } + } + assertEquals(expected.size(), actual.size(), "Wrong number of lines in template."); + } + + private static List parseXML(String xmlString) { + XMLFragment frag; + List fragments = new LinkedList(); + int startPos = 0; + while ((frag = XMLFragment.parse(xmlString, startPos)) != null) { + fragments.add(frag); + startPos = frag.matchEnd; + } + return fragments; + } + + public static void assertXMLEquals(String expected, String actual) { + List expectedFrags = parseXML(expected); + List actualFrags = parseXML(actual); + + Iterator itExpected = expectedFrags.iterator(); + Iterator itActual = actualFrags.iterator(); + while (itExpected.hasNext() && itActual.hasNext()) { + XMLFragment expectedFrag = itExpected.next(); + XMLFragment actualFrag = itActual.next(); + assertEquals(expectedFrag, actualFrag); + } + + assertEquals(expectedFrags.size(), actualFrags.size()); + } + + @SuppressWarnings("serial") + public static class Template extends LinkedList { + public Template(Object[] lines) { + Collections.addAll(this, lines); + } + + public Template(Template[] templates) { + for (Template template : templates) { + addAll(template); + } + } + } + + public static class XMLFragment { + + private static final Pattern CDATA = Pattern.compile("\\s*"); + + private static final Pattern COMMENT = Pattern.compile("\\s*"); + + private static final Pattern TAG_BEGIN = Pattern.compile("\\s*<(/|\\?|!)?\\s*([^\\s>/\\?]+)"); + + private static final Pattern TAG_END = Pattern.compile("\\s*(/|\\?)?>"); + + private static final Pattern TAG_ATTRIBUTE = Pattern.compile("\\s*([^\\s>=]+)=(\"[^\"]*\"|'[^']*')"); + + private static final Pattern DOCTYPE_PART = Pattern.compile("\\s*(\"[^\"]*\"|'[^']*'|[^\\s>]+)"); + + public final String name; + + public final FragmentType type; + + public final Map attributes; + + public final int matchStart; + + public final int matchEnd; + + public XMLFragment(String name, FragmentType type, Map attributes, + int matchStart, int matchEnd) { + this.name = name; + this.type = type; + this.attributes = Collections.unmodifiableMap( + new TreeMap(attributes)); + this.matchStart = matchStart; + this.matchEnd = matchEnd; + } + + public static XMLFragment parse(String xmlString, int matchStart) { + Map attrs = new IdentityHashMap(); + + Matcher cdataMatch = CDATA.matcher(xmlString); + cdataMatch.region(matchStart, xmlString.length()); + if (cdataMatch.lookingAt()) { + attrs.put("value", cdataMatch.group(1)); + return new XMLFragment("", FragmentType.CDATA, attrs, matchStart, cdataMatch.end()); + } + + Matcher commentMatch = COMMENT.matcher(xmlString); + commentMatch.region(matchStart, xmlString.length()); + if (commentMatch.lookingAt()) { + attrs.put("value", commentMatch.group(1).trim()); + return new XMLFragment("", FragmentType.COMMENT, attrs, matchStart, commentMatch.end()); + } + + Matcher beginMatch = TAG_BEGIN.matcher(xmlString); + beginMatch.region(matchStart, xmlString.length()); + if (!beginMatch.lookingAt()) { + return null; + } + int matchEndPrev = beginMatch.end(); + + String modifiers = beginMatch.group(1); + String name = beginMatch.group(2); + boolean endTag = "/".equals(modifiers); + boolean declarationStart = "?".equals(modifiers); + boolean doctype = "!".equals(modifiers) && "DOCTYPE".equals(name); + + if (doctype) { + int partNo = 0; + while (true) { + Matcher attrMatch = DOCTYPE_PART.matcher(xmlString); + attrMatch.region(matchEndPrev, xmlString.length()); + if (!attrMatch.lookingAt()) { + break; + } + matchEndPrev = attrMatch.end(); + + String partValue = attrMatch.group(1); + if (partValue.startsWith("\"") || partValue.startsWith("'")) { + partValue = partValue.substring(1, partValue.length() - 1); + } + + String partId = String.format("doctype %02d", partNo++); + attrs.put(partId, partValue); + } + } else { + while (true) { + Matcher attrMatch = TAG_ATTRIBUTE.matcher(xmlString); + attrMatch.region(matchEndPrev, xmlString.length()); + if (!attrMatch.lookingAt()) { + break; + } + matchEndPrev = attrMatch.end(); + + String attrName = attrMatch.group(1); + String attrValue = attrMatch.group(2); + attrValue = attrValue.substring(1, attrValue.length() - 1); + attrs.put(attrName, attrValue); + } + } + + Matcher endMatch = TAG_END.matcher(xmlString); + endMatch.region(matchEndPrev, xmlString.length()); + if (!endMatch.lookingAt()) { + throw new AssertionError(String.format("No tag end found: %s", xmlString.substring(0, matchEndPrev))); + } + matchEndPrev = endMatch.end(); + + modifiers = endMatch.group(1); + boolean emptyElement = "/".equals(modifiers); + boolean declarationEnd = "?".equals(modifiers); + + FragmentType type = FragmentType.START_TAG; + if (endTag) { + type = FragmentType.END_TAG; + } else if (emptyElement) { + type = FragmentType.EMPTY_ELEMENT; + } else if (declarationStart && declarationEnd) { + type = FragmentType.DECLARATION; + } else if (doctype) { + type = FragmentType.DOCTYPE; + } + + return new XMLFragment(name, type, attrs, matchStart, matchEndPrev); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof XMLFragment)) { + return false; + } + XMLFragment frag = (XMLFragment) o; + if (!type.equals(frag.type) || !name.equals(frag.name)) { + return false; + } + Iterator> itThis = attributes.entrySet().iterator(); + Iterator> itFrag = frag.attributes.entrySet().iterator(); + while (itThis.hasNext() && itFrag.hasNext()) { + Map.Entry attrThis = itThis.next(); + Map.Entry attrFrag = itFrag.next(); + if (!attrThis.getKey().equals(attrFrag.getKey()) || + !attrThis.getValue().equals(attrFrag.getValue())) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return type.hashCode() ^ attributes.hashCode(); + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder("<"); + if (FragmentType.END_TAG.equals(type)) { + s.append("/"); + } else if (FragmentType.DECLARATION.equals(type)) { + s.append("?"); + } + + if (FragmentType.DOCTYPE.equals(type)) { + s.append("!").append(name); + for (String partValue : attributes.values()) { + s.append(" ").append(partValue); + } + } else { + s.append(name); + for (Map.Entry attr : attributes.entrySet()) { + s.append(" ").append(attr.getKey()).append("=\"").append(attr.getValue()).append("\""); + } + } + if (FragmentType.DECLARATION.equals(type)) { + s.append("?"); + } + s.append(">"); + return s.toString(); + } + + public enum FragmentType { + START_TAG, END_TAG, EMPTY_ELEMENT, CDATA, + DECLARATION, DOCTYPE, COMMENT + } + } +} diff --git a/io-vector/build/libs/io-vector-3.0.0.jar b/io-vector/build/libs/io-vector-3.0.0.jar deleted file mode 100644 index a69f94f..0000000 Binary files a/io-vector/build/libs/io-vector-3.0.0.jar and /dev/null differ diff --git a/io-vector/build/tmp/compileJava/source-classes-mapping.txt b/io-vector/build/tmp/compileJava/source-classes-mapping.txt deleted file mode 100644 index 68c2313..0000000 --- a/io-vector/build/tmp/compileJava/source-classes-mapping.txt +++ /dev/null @@ -1,128 +0,0 @@ -org/xbib/graphics/io/vector/commands/SetTransformCommand.java - org.xbib.graphics.io.vector.commands.SetTransformCommand -org/xbib/graphics/io/vector/commands/SetStrokeCommand.java - org.xbib.graphics.io.vector.commands.SetStrokeCommand -org/xbib/graphics/io/vector/filters/StateChangeGroupingFilter.java - org.xbib.graphics.io.vector.filters.StateChangeGroupingFilter -org/xbib/graphics/io/vector/commands/TransformCommand.java - org.xbib.graphics.io.vector.commands.TransformCommand -org/xbib/graphics/io/vector/eps/EPSGraphics2D.java - org.xbib.graphics.io.vector.eps.EPSGraphics2D -org/xbib/graphics/io/vector/util/AlphaToMaskOp.java - org.xbib.graphics.io.vector.util.AlphaToMaskOp -org/xbib/graphics/io/vector/commands/SetFontCommand.java - org.xbib.graphics.io.vector.commands.SetFontCommand -org/xbib/graphics/io/vector/commands/ShearCommand.java - org.xbib.graphics.io.vector.commands.ShearCommand -org/xbib/graphics/io/vector/pdf/Resources.java - org.xbib.graphics.io.vector.pdf.Resources -org/xbib/graphics/io/vector/commands/SetPaintCommand.java - org.xbib.graphics.io.vector.commands.SetPaintCommand -org/xbib/graphics/io/vector/util/FlateEncodeStream.java - org.xbib.graphics.io.vector.util.FlateEncodeStream -org/xbib/graphics/io/vector/commands/DisposeCommand.java - org.xbib.graphics.io.vector.commands.DisposeCommand -org/xbib/graphics/io/vector/commands/RotateCommand.java - org.xbib.graphics.io.vector.commands.RotateCommand -org/xbib/graphics/io/vector/pdf/PDFProcessorResult.java - org.xbib.graphics.io.vector.pdf.PDFProcessorResult -org/xbib/graphics/io/vector/ProcessorResult.java - org.xbib.graphics.io.vector.ProcessorResult -org/xbib/graphics/io/vector/commands/AffineTransformCommand.java - org.xbib.graphics.io.vector.commands.AffineTransformCommand -org/xbib/graphics/io/vector/util/GraphicsUtils.java - org.xbib.graphics.io.vector.util.GraphicsUtils - org.xbib.graphics.io.vector.util.GraphicsUtils$FontExpressivenessComparator -org/xbib/graphics/io/vector/util/VectorHints.java - org.xbib.graphics.io.vector.util.VectorHints - org.xbib.graphics.io.vector.util.VectorHints$Key - org.xbib.graphics.io.vector.util.VectorHints$Value -org/xbib/graphics/io/vector/commands/CreateCommand.java - org.xbib.graphics.io.vector.commands.CreateCommand -org/xbib/graphics/io/vector/commands/StateCommand.java - org.xbib.graphics.io.vector.commands.StateCommand -org/xbib/graphics/io/vector/GraphicsState.java - org.xbib.graphics.io.vector.GraphicsState -org/xbib/graphics/io/vector/util/ImageDataStream.java - org.xbib.graphics.io.vector.util.ImageDataStream - org.xbib.graphics.io.vector.util.ImageDataStream$Interleaving -org/xbib/graphics/io/vector/util/FormattingWriter.java - org.xbib.graphics.io.vector.util.FormattingWriter -org/xbib/graphics/io/vector/commands/ScaleCommand.java - org.xbib.graphics.io.vector.commands.ScaleCommand -org/xbib/graphics/io/vector/commands/FillShapeCommand.java - org.xbib.graphics.io.vector.commands.FillShapeCommand -org/xbib/graphics/io/vector/commands/SetCompositeCommand.java - org.xbib.graphics.io.vector.commands.SetCompositeCommand -org/xbib/graphics/io/vector/eps/EPSProcessorResult.java - org.xbib.graphics.io.vector.eps.EPSProcessorResult -module-info.java - module-info -org/xbib/graphics/io/vector/eps/EPSProcessor.java - org.xbib.graphics.io.vector.eps.EPSProcessor -org/xbib/graphics/io/vector/filters/Filter.java - org.xbib.graphics.io.vector.filters.Filter -org/xbib/graphics/io/vector/filters/GroupingFilter.java - org.xbib.graphics.io.vector.filters.GroupingFilter -org/xbib/graphics/io/vector/svg/SVGProcessorResult.java - org.xbib.graphics.io.vector.svg.SVGProcessorResult -org/xbib/graphics/io/vector/pdf/PDFGraphics2D.java - org.xbib.graphics.io.vector.pdf.PDFGraphics2D -org/xbib/graphics/io/vector/pdf/PDFObject.java - org.xbib.graphics.io.vector.pdf.PDFObject -org/xbib/graphics/io/vector/util/ASCII85EncodeStream.java - org.xbib.graphics.io.vector.util.ASCII85EncodeStream -org/xbib/graphics/io/vector/pdf/PDFProcessor.java - org.xbib.graphics.io.vector.pdf.PDFProcessor -org/xbib/graphics/io/vector/commands/SetHintCommand.java - org.xbib.graphics.io.vector.commands.SetHintCommand -org/xbib/graphics/io/vector/commands/TranslateCommand.java - org.xbib.graphics.io.vector.commands.TranslateCommand -org/xbib/graphics/io/vector/commands/Group.java - org.xbib.graphics.io.vector.commands.Group -org/xbib/graphics/io/vector/VectorGraphicsFormat.java - org.xbib.graphics.io.vector.VectorGraphicsFormat -org/xbib/graphics/io/vector/commands/DrawShapeCommand.java - org.xbib.graphics.io.vector.commands.DrawShapeCommand -org/xbib/graphics/io/vector/filters/FillPaintedShapeAsImageFilter.java - org.xbib.graphics.io.vector.filters.FillPaintedShapeAsImageFilter -org/xbib/graphics/io/vector/pdf/SizePayload.java - org.xbib.graphics.io.vector.pdf.SizePayload -org/xbib/graphics/io/vector/svg/SVGGraphics2D.java - org.xbib.graphics.io.vector.svg.SVGGraphics2D -org/xbib/graphics/io/vector/filters/OptimizeFilter.java - org.xbib.graphics.io.vector.filters.OptimizeFilter -org/xbib/graphics/io/vector/commands/SetClipCommand.java - org.xbib.graphics.io.vector.commands.SetClipCommand -org/xbib/graphics/io/vector/pdf/Payload.java - org.xbib.graphics.io.vector.pdf.Payload -org/xbib/graphics/io/vector/commands/DrawStringCommand.java - org.xbib.graphics.io.vector.commands.DrawStringCommand -org/xbib/graphics/io/vector/util/Base64EncodeStream.java - org.xbib.graphics.io.vector.util.Base64EncodeStream -org/xbib/graphics/io/vector/commands/SetXORModeCommand.java - org.xbib.graphics.io.vector.commands.SetXORModeCommand -org/xbib/graphics/io/vector/commands/SetColorCommand.java - org.xbib.graphics.io.vector.commands.SetColorCommand -org/xbib/graphics/io/vector/Command.java - org.xbib.graphics.io.vector.Command -org/xbib/graphics/io/vector/VectorGraphics2D.java - org.xbib.graphics.io.vector.VectorGraphics2D -org/xbib/graphics/io/vector/pdf/GeneratedPayload.java - org.xbib.graphics.io.vector.pdf.GeneratedPayload -org/xbib/graphics/io/vector/util/LineWrapOutputStream.java - org.xbib.graphics.io.vector.util.LineWrapOutputStream -org/xbib/graphics/io/vector/util/DataUtils.java - org.xbib.graphics.io.vector.util.DataUtils -org/xbib/graphics/io/vector/Processor.java - org.xbib.graphics.io.vector.Processor -org/xbib/graphics/io/vector/commands/DrawImageCommand.java - org.xbib.graphics.io.vector.commands.DrawImageCommand -org/xbib/graphics/io/vector/filters/AbsoluteToRelativeTransformsFilter.java - org.xbib.graphics.io.vector.filters.AbsoluteToRelativeTransformsFilter -org/xbib/graphics/io/vector/svg/SVGProcessor.java - org.xbib.graphics.io.vector.svg.SVGProcessor -org/xbib/graphics/io/vector/PageSize.java - org.xbib.graphics.io.vector.PageSize -org/xbib/graphics/io/vector/commands/SetBackgroundCommand.java - org.xbib.graphics.io.vector.commands.SetBackgroundCommand diff --git a/io-vector/build/tmp/jar/MANIFEST.MF b/io-vector/build/tmp/jar/MANIFEST.MF deleted file mode 100644 index 0ea94c1..0000000 --- a/io-vector/build/tmp/jar/MANIFEST.MF +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -Implementation-Version: 3.0.0 - diff --git a/io-vector/src/main/java/module-info.java b/io-vector/src/main/java/module-info.java index d07255e..cfb2ba2 100644 --- a/io-vector/src/main/java/module-info.java +++ b/io-vector/src/main/java/module-info.java @@ -1,8 +1,6 @@ module org.xbib.graphics.io.vector { exports org.xbib.graphics.io.vector; - exports org.xbib.graphics.io.vector.eps; - exports org.xbib.graphics.io.vector.pdf; - exports org.xbib.graphics.io.vector.svg; - + exports org.xbib.graphics.io.vector.commands; + exports org.xbib.graphics.io.vector.filters; requires transitive java.desktop; } \ No newline at end of file diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/Command.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/Command.java index b452536..cfc68c1 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/Command.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/Command.java @@ -1,5 +1,17 @@ package org.xbib.graphics.io.vector; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.Arc2D; +import java.awt.geom.CubicCurve2D; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Line2D; +import java.awt.geom.Path2D; +import java.awt.geom.QuadCurve2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; + public abstract class Command { private final T value; @@ -8,13 +20,15 @@ public abstract class Command { this.value = value; } + public abstract String getKey(); + public T getValue() { return value; } @Override public String toString() { - return String.format("%s[value=%s]", getClass().getName(), getValue()); + return String.format("%s[value=%s]", getKey(), getValue()); } @Override @@ -25,5 +39,51 @@ public abstract class Command { Command o = (Command) obj; return value == o.value || value.equals(o.value); } + + protected static Shape clone(Shape shape) { + if (shape == null) { + return null; + } + Shape clone; + if (shape instanceof Line2D) { + clone = (shape instanceof Line2D.Float) ? + new Line2D.Float() : new Line2D.Double(); + ((Line2D) clone).setLine((Line2D) shape); + } else if (shape instanceof Rectangle) { + clone = new Rectangle((Rectangle) shape); + } else if (shape instanceof Rectangle2D) { + clone = (shape instanceof Rectangle2D.Float) ? + new Rectangle2D.Float() : new Rectangle2D.Double(); + ((Rectangle2D) clone).setRect((Rectangle2D) shape); + } else if (shape instanceof RoundRectangle2D) { + clone = (shape instanceof RoundRectangle2D.Float) ? + new RoundRectangle2D.Float() : new RoundRectangle2D.Double(); + ((RoundRectangle2D) clone).setRoundRect((RoundRectangle2D) shape); + } else if (shape instanceof Ellipse2D) { + clone = (shape instanceof Ellipse2D.Float) ? + new Ellipse2D.Float() : new Ellipse2D.Double(); + ((Ellipse2D) clone).setFrame(((Ellipse2D) shape).getFrame()); + } else if (shape instanceof Arc2D) { + clone = (shape instanceof Arc2D.Float) ? + new Arc2D.Float() : new Arc2D.Double(); + ((Arc2D) clone).setArc((Arc2D) shape); + } else if (shape instanceof Polygon) { + Polygon p = (Polygon) shape; + clone = new Polygon(p.xpoints, p.ypoints, p.npoints); + } else if (shape instanceof CubicCurve2D) { + clone = (shape instanceof CubicCurve2D.Float) ? + new CubicCurve2D.Float() : new CubicCurve2D.Double(); + ((CubicCurve2D) clone).setCurve((CubicCurve2D) shape); + } else if (shape instanceof QuadCurve2D) { + clone = (shape instanceof QuadCurve2D.Float) ? + new QuadCurve2D.Float() : new QuadCurve2D.Double(); + ((QuadCurve2D) clone).setCurve((QuadCurve2D) shape); + } else if (shape instanceof Path2D.Float) { + clone = new Path2D.Float(shape); + } else { + clone = new Path2D.Double(shape); + } + return clone; + } } diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/GraphicsState.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/GraphicsState.java index c85ec8d..a1e2333 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/GraphicsState.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/GraphicsState.java @@ -1,18 +1,26 @@ package org.xbib.graphics.io.vector; -import org.xbib.graphics.io.vector.util.GraphicsUtils; import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Composite; import java.awt.Font; import java.awt.Paint; +import java.awt.Polygon; +import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.AffineTransform; +import java.awt.geom.Arc2D; +import java.awt.geom.CubicCurve2D; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Line2D; import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Path2D; +import java.awt.geom.QuadCurve2D; import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; import java.util.Objects; public class GraphicsState implements Cloneable { @@ -113,7 +121,7 @@ public class GraphicsState implements Cloneable { return null; } if (tx == null || tx.isIdentity()) { - return GraphicsUtils.clone(s); + return clone(s); } boolean isRectangle = s instanceof Rectangle2D; int nonRectlinearTxMask = AffineTransform.TYPE_GENERAL_TRANSFORM | @@ -150,7 +158,7 @@ public class GraphicsState implements Cloneable { public Object clone() throws CloneNotSupportedException { GraphicsState clone = (GraphicsState) super.clone(); clone.hints = (RenderingHints) hints.clone(); - clone.clip = GraphicsUtils.clone(clip); + clone.clip = clone(clip); clone.transform = new AffineTransform(transform); return clone; } @@ -270,5 +278,50 @@ public class GraphicsState implements Cloneable { stroke.equals(DEFAULT_STROKE) && transform.equals(DEFAULT_TRANSFORM) && xorMode.equals(DEFAULT_XOR_MODE) && clip == DEFAULT_CLIP; } -} + static Shape clone(Shape shape) { + if (shape == null) { + return null; + } + Shape clone; + if (shape instanceof Line2D) { + clone = (shape instanceof Line2D.Float) ? + new Line2D.Float() : new Line2D.Double(); + ((Line2D) clone).setLine((Line2D) shape); + } else if (shape instanceof Rectangle) { + clone = new Rectangle((Rectangle) shape); + } else if (shape instanceof Rectangle2D) { + clone = (shape instanceof Rectangle2D.Float) ? + new Rectangle2D.Float() : new Rectangle2D.Double(); + ((Rectangle2D) clone).setRect((Rectangle2D) shape); + } else if (shape instanceof RoundRectangle2D) { + clone = (shape instanceof RoundRectangle2D.Float) ? + new RoundRectangle2D.Float() : new RoundRectangle2D.Double(); + ((RoundRectangle2D) clone).setRoundRect((RoundRectangle2D) shape); + } else if (shape instanceof Ellipse2D) { + clone = (shape instanceof Ellipse2D.Float) ? + new Ellipse2D.Float() : new Ellipse2D.Double(); + ((Ellipse2D) clone).setFrame(((Ellipse2D) shape).getFrame()); + } else if (shape instanceof Arc2D) { + clone = (shape instanceof Arc2D.Float) ? + new Arc2D.Float() : new Arc2D.Double(); + ((Arc2D) clone).setArc((Arc2D) shape); + } else if (shape instanceof Polygon) { + Polygon p = (Polygon) shape; + clone = new Polygon(p.xpoints, p.ypoints, p.npoints); + } else if (shape instanceof CubicCurve2D) { + clone = (shape instanceof CubicCurve2D.Float) ? + new CubicCurve2D.Float() : new CubicCurve2D.Double(); + ((CubicCurve2D) clone).setCurve((CubicCurve2D) shape); + } else if (shape instanceof QuadCurve2D) { + clone = (shape instanceof QuadCurve2D.Float) ? + new QuadCurve2D.Float() : new QuadCurve2D.Double(); + ((QuadCurve2D) clone).setCurve((QuadCurve2D) shape); + } else if (shape instanceof Path2D.Float) { + clone = new Path2D.Float(shape); + } else { + clone = new Path2D.Double(shape); + } + return clone; + } +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/VectorGraphics2D.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/VectorGraphics2D.java index 702d358..488058f 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/VectorGraphics2D.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/VectorGraphics2D.java @@ -21,7 +21,6 @@ import org.xbib.graphics.io.vector.commands.SetXORModeCommand; import org.xbib.graphics.io.vector.commands.ShearCommand; import org.xbib.graphics.io.vector.commands.TransformCommand; import org.xbib.graphics.io.vector.commands.TranslateCommand; -import org.xbib.graphics.io.vector.util.GraphicsUtils; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Composite; @@ -32,6 +31,7 @@ import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; import java.awt.Image; import java.awt.Paint; import java.awt.Polygon; @@ -40,6 +40,7 @@ import java.awt.RenderingHints; import java.awt.RenderingHints.Key; import java.awt.Shape; import java.awt.Stroke; +import java.awt.Transparency; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.font.TextLayout; @@ -49,22 +50,28 @@ import java.awt.geom.Area; import java.awt.geom.Ellipse2D; import java.awt.geom.Line2D; import java.awt.geom.Path2D; +import java.awt.geom.PathIterator; import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; +import java.awt.image.ColorModel; import java.awt.image.ImageObserver; +import java.awt.image.PixelGrabber; import java.awt.image.RenderedImage; +import java.awt.image.WritableRaster; import java.awt.image.renderable.RenderableImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.text.AttributedCharacterIterator; +import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import javax.swing.ImageIcon; /** * Base for classes that want to implement vector export. @@ -134,28 +141,6 @@ public class VectorGraphics2D extends Graphics2D implements Cloneable { processor.process(getCommands(), pageSize).write(out); } - private static Shape intersectShapes(Shape s1, Shape s2) { - if (s1 instanceof Rectangle2D && s2 instanceof Rectangle2D) { - Rectangle2D r1 = (Rectangle2D) s1; - Rectangle2D r2 = (Rectangle2D) s2; - double x1 = Math.max(r1.getMinX(), r2.getMinX()); - double y1 = Math.max(r1.getMinY(), r2.getMinY()); - double x2 = Math.min(r1.getMaxX(), r2.getMaxX()); - double y2 = Math.min(r1.getMaxY(), r2.getMaxY()); - Rectangle2D intersection = new Rectangle2D.Double(); - if ((x2 < x1) || (y2 < y1)) { - intersection.setFrameFromDiagonal(0, 0, 0, 0); - } else { - intersection.setFrameFromDiagonal(x1, y1, x2, y2); - } - return intersection; - } else { - Area intersection = new Area(s1); - intersection.intersect(new Area(s2)); - return intersection; - } - } - @Override public Object clone() throws CloneNotSupportedException { VectorGraphics2D clone = (VectorGraphics2D) super.clone(); @@ -186,7 +171,7 @@ public class VectorGraphics2D extends Graphics2D implements Cloneable { if ((clipNew == null || debugValidateGraphics.getClip() == null) && clipNew != debugValidateGraphics.getClip()) { throw new IllegalStateException("clip() validation failed: clip(" + clipOld + ", " + s + ") => " + clipNew + " != " + debugValidateGraphics.getClip()); } - if (clipNew != null && !GraphicsUtils.equals(clipNew, debugValidateGraphics.getClip())) { + if (clipNew != null && !equals(clipNew, debugValidateGraphics.getClip())) { throw new IllegalStateException("clip() validation failed: clip(" + clipOld + ", " + s + ") => " + clipNew + " != " + debugValidateGraphics.getClip()); } } @@ -213,31 +198,6 @@ public class VectorGraphics2D extends Graphics2D implements Cloneable { bimg.getWidth(), bimg.getHeight(), null, null); } - /** - * Returns a transformed version of an image. - * - * @param image Image to be transformed - * @param xform Affine transform to be applied - * @return Image with transformed content - */ - private BufferedImage getTransformedImage(Image image, - AffineTransform xform) { - Integer interpolationType = - (Integer) getRenderingHint(RenderingHints.KEY_INTERPOLATION); - if (RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR - .equals(interpolationType)) { - interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR; - } else if (RenderingHints.VALUE_INTERPOLATION_BILINEAR - .equals(interpolationType)) { - interpolationType = AffineTransformOp.TYPE_BILINEAR; - } else { - interpolationType = AffineTransformOp.TYPE_BICUBIC; - } - AffineTransformOp op = new AffineTransformOp(xform, interpolationType); - BufferedImage bufferedImage = GraphicsUtils.toBufferedImage(image); - return op.filter(bufferedImage, null); - } - @Override public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { if (op != null) { @@ -253,7 +213,7 @@ public class VectorGraphics2D extends Graphics2D implements Cloneable { @Override public void drawRenderedImage(RenderedImage img, AffineTransform xform) { - BufferedImage bimg = GraphicsUtils.toBufferedImage(img); + BufferedImage bimg = toBufferedImage(img); drawImage(bimg, xform, null); } @@ -508,7 +468,7 @@ public class VectorGraphics2D extends Graphics2D implements Cloneable { @Override public void translate(int x, int y) { - translate((double) x, (double) y); + translate(x, (double) y); } @Override @@ -562,10 +522,10 @@ public class VectorGraphics2D extends Graphics2D implements Cloneable { if (sx == 1.0 && sy == 1.0) { return; } - AffineTransform txNew = getTransform(); - txNew.scale(sx, sy); + AffineTransform affineTransform = getTransform(); + affineTransform.scale(sx, sy); emit(new ScaleCommand(sx, sy)); - state.setTransform(txNew); + state.setTransform(affineTransform); debugValidateGraphics.scale(sx, sy); if (!getTransform().equals(debugValidateGraphics.getTransform())) { throw new IllegalStateException("scale() validation failed"); @@ -587,8 +547,6 @@ public class VectorGraphics2D extends Graphics2D implements Cloneable { @Override public void copyArea(int x, int y, int width, int height, int dx, int dy) { - // TODO Implement - //throw new UnsupportedOperationException("copyArea() isn't supported by VectorGraphics2D."); } @Override @@ -596,7 +554,7 @@ public class VectorGraphics2D extends Graphics2D implements Cloneable { if (isDisposed()) { return null; } - VectorGraphics2D clone = null; + VectorGraphics2D clone; try { clone = (VectorGraphics2D) this.clone(); } catch (CloneNotSupportedException e) { @@ -618,16 +576,14 @@ public class VectorGraphics2D extends Graphics2D implements Cloneable { } @Override - public void drawArc(int x, int y, int width, int height, int startAngle, - int arcAngle) { + public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { draw(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN)); } @Override public boolean drawImage(Image img, int x, int y, ImageObserver observer) { - return drawImage(img, x, y, img.getWidth(observer), - img.getHeight(observer), null, observer); + return drawImage(img, x, y, img.getWidth(observer), img.getHeight(observer), null, observer); } @Override @@ -649,23 +605,17 @@ public class VectorGraphics2D extends Graphics2D implements Cloneable { if (isDisposed() || img == null) { return true; } - int imageWidth = img.getWidth(observer); int imageHeight = img.getHeight(observer); Rectangle bounds = new Rectangle(x, y, width, height); - if (bgcolor != null) { - // Fill rectangle with bgcolor Color bgcolorOld = getColor(); setColor(bgcolor); fill(bounds); setColor(bgcolorOld); } - emit(new DrawImageCommand(img, imageWidth, imageHeight, x, y, width, height)); - debugValidateGraphics.drawImage(img, x, y, width, height, bgcolor, observer); - return true; } @@ -683,7 +633,6 @@ public class VectorGraphics2D extends Graphics2D implements Cloneable { if (img == null) { return true; } - int sx = Math.min(sx1, sx2); int sy = Math.min(sy1, sy2); int sw = Math.abs(sx2 - sx1); @@ -692,9 +641,7 @@ public class VectorGraphics2D extends Graphics2D implements Cloneable { int dy = Math.min(dy1, dy2); int dw = Math.abs(dx2 - dx1); int dh = Math.abs(dy2 - dy1); - - // Draw image on rectangle - BufferedImage bufferedImg = GraphicsUtils.toBufferedImage(img); + BufferedImage bufferedImg = toBufferedImage(img); Image cropped = bufferedImg.getSubimage(sx, sy, sw, sh); return drawImage(cropped, dx, dy, dw, dh, bgcolor, observer); } @@ -797,7 +744,7 @@ public class VectorGraphics2D extends Graphics2D implements Cloneable { throw new IllegalStateException("setClip() validation failed: clip=null, validation=" + debugValidateGraphics.getClip()); } - } else if (!GraphicsUtils.equals(getClip(), debugValidateGraphics.getClip())) { + } else if (!equals(getClip(), debugValidateGraphics.getClip())) { throw new IllegalStateException("setClip() validation failed: clip=" + getClip() + ", validation=" + debugValidateGraphics.getClip()); } @@ -868,10 +815,6 @@ public class VectorGraphics2D extends Graphics2D implements Cloneable { debugValidateGraphics.setPaintMode(); } - public Color getXORMode() { - return state.getXorMode(); - } - @Override public void setXORMode(Color c1) { if (isDisposed() || c1 == null) { @@ -882,8 +825,8 @@ public class VectorGraphics2D extends Graphics2D implements Cloneable { debugValidateGraphics.setXORMode(c1); } - private void emit(Command command) { - commands.add(command); + public Color getXORMode() { + return state.getXorMode(); } public Iterable> getCommands() { @@ -893,4 +836,171 @@ public class VectorGraphics2D extends Graphics2D implements Cloneable { protected boolean isDisposed() { return disposed; } + + private void emit(Command command) { + commands.add(command); + } + + /** + * Returns a transformed version of an image. + * + * @param image Image to be transformed + * @param xform Affine transform to be applied + * @return Image with transformed content + */ + private BufferedImage getTransformedImage(Image image, AffineTransform xform) { + Integer interpolationType = + (Integer) getRenderingHint(RenderingHints.KEY_INTERPOLATION); + if (RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR + .equals(interpolationType)) { + interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR; + } else if (RenderingHints.VALUE_INTERPOLATION_BILINEAR + .equals(interpolationType)) { + interpolationType = AffineTransformOp.TYPE_BILINEAR; + } else { + interpolationType = AffineTransformOp.TYPE_BICUBIC; + } + AffineTransformOp op = new AffineTransformOp(xform, interpolationType); + BufferedImage bufferedImage = toBufferedImage(image); + return op.filter(bufferedImage, null); + } + + private static boolean equals(Shape shapeA, Shape shapeB) { + PathIterator pathAIterator = shapeA.getPathIterator(null); + PathIterator pathBIterator = shapeB.getPathIterator(null); + if (pathAIterator.getWindingRule() != pathBIterator.getWindingRule()) { + return false; + } + double[] pathASegment = new double[6]; + double[] pathBSegment = new double[6]; + while (!pathAIterator.isDone()) { + int pathASegmentType = pathAIterator.currentSegment(pathASegment); + int pathBSegmentType = pathBIterator.currentSegment(pathBSegment); + if (pathASegmentType != pathBSegmentType) { + return false; + } + for (int segmentIndex = 0; segmentIndex < pathASegment.length; segmentIndex++) { + if (pathASegment[segmentIndex] != pathBSegment[segmentIndex]) { + return false; + } + } + pathAIterator.next(); + pathBIterator.next(); + } + return pathBIterator.isDone(); + } + + /** + * Converts an arbitrary image to a {@code BufferedImage}. + * + * @param image Image that should be converted. + * @return a buffered image containing the image pixels, or the original + * instance if the image already was of type {@code BufferedImage}. + */ + static BufferedImage toBufferedImage(RenderedImage image) { + if (image instanceof BufferedImage) { + return (BufferedImage) image; + } + ColorModel cm = image.getColorModel(); + WritableRaster raster = cm.createCompatibleWritableRaster(image.getWidth(), image.getHeight()); + boolean isRasterPremultiplied = cm.isAlphaPremultiplied(); + Hashtable properties = null; + if (image.getPropertyNames() != null) { + properties = new Hashtable<>(); + for (String key : image.getPropertyNames()) { + properties.put(key, image.getProperty(key)); + } + } + BufferedImage bimage = new BufferedImage(cm, raster, isRasterPremultiplied, properties); + image.copyData(raster); + return bimage; + } + + /** + * This method returns a buffered image with the contents of an image. + * Taken from http://www.exampledepot.com/egs/java.awt.image/Image2Buf.html + * + * @param image Image to be converted + * @return a buffered image with the contents of the specified image + */ + static BufferedImage toBufferedImage(Image image) { + if (image instanceof BufferedImage) { + return (BufferedImage) image; + } + image = new ImageIcon(image).getImage(); + boolean hasAlpha = hasAlpha(image); + BufferedImage bimage; + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + try { + int transparency = Transparency.OPAQUE; + if (hasAlpha) { + transparency = Transparency.TRANSLUCENT; + } + GraphicsDevice gs = ge.getDefaultScreenDevice(); + GraphicsConfiguration gc = gs.getDefaultConfiguration(); + bimage = gc.createCompatibleImage(image.getWidth(null), image.getHeight(null), transparency); + } catch (HeadlessException e) { + bimage = null; + } + if (bimage == null) { + int type = BufferedImage.TYPE_INT_RGB; + if (hasAlpha) { + type = BufferedImage.TYPE_INT_ARGB; + } + bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type); + } + Graphics g = bimage.createGraphics(); + g.drawImage(image, 0, 0, null); + g.dispose(); + return bimage; + } + + + /** + * This method returns {@code true} if the specified image has the + * possibility to store transparent pixels. + * Inspired by http://www.exampledepot.com/egs/java.awt.image/HasAlpha.html + * + * @param image Image that should be checked for alpha channel. + * @return {@code true} if the specified image can have transparent pixels, + * {@code false} otherwise + */ + static boolean hasAlpha(Image image) { + ColorModel cm; + if (image instanceof BufferedImage) { + BufferedImage bimage = (BufferedImage) image; + cm = bimage.getColorModel(); + } else { + PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false); + try { + pg.grabPixels(); + } catch (InterruptedException e) { + return false; + } + cm = pg.getColorModel(); + } + return cm.hasAlpha(); + } + + private static Shape intersectShapes(Shape s1, Shape s2) { + if (s1 instanceof Rectangle2D && s2 instanceof Rectangle2D) { + Rectangle2D r1 = (Rectangle2D) s1; + Rectangle2D r2 = (Rectangle2D) s2; + double x1 = Math.max(r1.getMinX(), r2.getMinX()); + double y1 = Math.max(r1.getMinY(), r2.getMinY()); + double x2 = Math.min(r1.getMaxX(), r2.getMaxX()); + double y2 = Math.min(r1.getMaxY(), r2.getMaxY()); + Rectangle2D intersection = new Rectangle2D.Double(); + if ((x2 < x1) || (y2 < y1)) { + intersection.setFrameFromDiagonal(0, 0, 0, 0); + } else { + intersection.setFrameFromDiagonal(x1, y1, x2, y2); + } + return intersection; + } else { + Area intersection = new Area(s1); + intersection.intersect(new Area(s2)); + return intersection; + } + } } diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/VectorGraphics2DProvider.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/VectorGraphics2DProvider.java new file mode 100644 index 0000000..f3eebe3 --- /dev/null +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/VectorGraphics2DProvider.java @@ -0,0 +1,8 @@ +package org.xbib.graphics.io.vector; + +public interface VectorGraphics2DProvider { + + String name(); + + V provide(double x, double y, double width, double height); +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/VectorGraphicsFormat.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/VectorGraphicsFormat.java deleted file mode 100644 index 887abcb..0000000 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/VectorGraphicsFormat.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.xbib.graphics.io.vector; - -public enum VectorGraphicsFormat { - EPS, PDF, SVG -} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/AffineTransformCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/AffineTransformCommand.java index b2d726f..4c4caf4 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/AffineTransformCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/AffineTransformCommand.java @@ -3,6 +3,7 @@ package org.xbib.graphics.io.vector.commands; import java.awt.geom.AffineTransform; public abstract class AffineTransformCommand extends StateCommand { + public AffineTransformCommand(AffineTransform transform) { super(transform); } diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/CreateCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/CreateCommand.java index 73323d3..c1424e0 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/CreateCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/CreateCommand.java @@ -3,8 +3,13 @@ package org.xbib.graphics.io.vector.commands; import org.xbib.graphics.io.vector.VectorGraphics2D; public class CreateCommand extends StateCommand { + public CreateCommand(VectorGraphics2D graphics) { super(graphics); } -} + @Override + public String getKey() { + return "create"; + } +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/DisposeCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/DisposeCommand.java index d11e178..463cc17 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/DisposeCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/DisposeCommand.java @@ -3,8 +3,13 @@ package org.xbib.graphics.io.vector.commands; import org.xbib.graphics.io.vector.VectorGraphics2D; public class DisposeCommand extends StateCommand { + public DisposeCommand(VectorGraphics2D graphics) { super(graphics); } -} + @Override + public String getKey() { + return "dispose"; + } +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/DrawImageCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/DrawImageCommand.java index 613e994..d8aa5c3 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/DrawImageCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/DrawImageCommand.java @@ -5,15 +5,23 @@ import java.awt.Image; import java.util.Locale; public class DrawImageCommand extends Command { + private final int imageWidth; + private final int imageHeight; + private final double x; + private final double y; + private final double width; + private final double height; - public DrawImageCommand(Image image, int imageWidth, int imageHeight, - double x, double y, double width, double height) { + public DrawImageCommand(Image image, + int imageWidth, int imageHeight, + double x, double y, + double width, double height) { super(image); this.imageWidth = imageWidth; this.imageHeight = imageHeight; @@ -47,11 +55,16 @@ public class DrawImageCommand extends Command { return height; } + @Override + public String getKey() { + return "drawImage"; + } + @Override public String toString() { return String.format((Locale) null, "%s[value=%s, imageWidth=%d, imageHeight=%d, x=%f, y=%f, width=%f, height=%f]", - getClass().getName(), getValue(), + getKey(), getValue(), getImageWidth(), getImageHeight(), getX(), getY(), getWidth(), getHeight()); } diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/DrawShapeCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/DrawShapeCommand.java index cbfff32..73fffb4 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/DrawShapeCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/DrawShapeCommand.java @@ -1,13 +1,16 @@ package org.xbib.graphics.io.vector.commands; import org.xbib.graphics.io.vector.Command; -import org.xbib.graphics.io.vector.util.GraphicsUtils; import java.awt.Shape; public class DrawShapeCommand extends Command { public DrawShapeCommand(Shape shape) { - super(GraphicsUtils.clone(shape)); + super(clone(shape)); + } + + @Override + public String getKey() { + return "drawShape"; } } - diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/DrawStringCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/DrawStringCommand.java index 7a23ebb..527a82b 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/DrawStringCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/DrawStringCommand.java @@ -3,9 +3,10 @@ package org.xbib.graphics.io.vector.commands; import org.xbib.graphics.io.vector.Command; import java.util.Locale; - public class DrawStringCommand extends Command { + private final double x; + private final double y; public DrawStringCommand(String string, double x, double y) { @@ -22,10 +23,14 @@ public class DrawStringCommand extends Command { return y; } + @Override + public String getKey() { + return "drawString"; + } + @Override public String toString() { return String.format((Locale) null, "%s[value=%s, x=%f, y=%f]", - getClass().getName(), getValue(), getX(), getY()); + getKey(), getValue(), getX(), getY()); } } - diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/FillShapeCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/FillShapeCommand.java index ce91250..4d81106 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/FillShapeCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/FillShapeCommand.java @@ -1,13 +1,16 @@ package org.xbib.graphics.io.vector.commands; import org.xbib.graphics.io.vector.Command; -import org.xbib.graphics.io.vector.util.GraphicsUtils; import java.awt.Shape; public class FillShapeCommand extends Command { public FillShapeCommand(Shape shape) { - super(GraphicsUtils.clone(shape)); + super(clone(shape)); + } + + @Override + public String getKey() { + return "fillShape"; } } - diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/Group.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/Group.java index 9143e3c..ef9f361 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/Group.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/Group.java @@ -5,13 +5,18 @@ import java.util.LinkedList; import java.util.List; public class Group extends Command>> { + public Group() { - super(new LinkedList>()); + super(new LinkedList<>()); } public void add(Command command) { List> group = getValue(); group.add(command); } -} + @Override + public String getKey() { + return "group"; + } +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/RotateCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/RotateCommand.java index 433d22b..206401d 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/RotateCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/RotateCommand.java @@ -4,8 +4,11 @@ import java.awt.geom.AffineTransform; import java.util.Locale; public class RotateCommand extends AffineTransformCommand { + private final double theta; + private final double centerX; + private final double centerY; public RotateCommand(double theta, double centerX, double centerY) { @@ -27,11 +30,16 @@ public class RotateCommand extends AffineTransformCommand { return centerY; } + @Override + public String getKey() { + return "rotate"; + } + @Override public String toString() { return String.format((Locale) null, "%s[theta=%f, centerX=%f, centerY=%f, value=%s]", - getClass().getName(), getTheta(), getCenterX(), getCenterY(), + getKey(), getTheta(), getCenterX(), getCenterY(), getValue()); } } diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/ScaleCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/ScaleCommand.java index 6d436cb..df41e49 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/ScaleCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/ScaleCommand.java @@ -4,7 +4,9 @@ import java.awt.geom.AffineTransform; import java.util.Locale; public class ScaleCommand extends AffineTransformCommand { + private final double scaleX; + private final double scaleY; public ScaleCommand(double scaleX, double scaleY) { @@ -21,11 +23,15 @@ public class ScaleCommand extends AffineTransformCommand { return scaleY; } + @Override + public String getKey() { + return "scale"; + } + @Override public String toString() { return String.format((Locale) null, - "%s[scaleX=%f, scaleY=%f, value=%s]", getClass().getName(), - getScaleX(), getScaleY(), getValue()); + "%s[scaleX=%f, scaleY=%f, value=%s]", + getKey(), getScaleX(), getScaleY(), getValue()); } } - diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetBackgroundCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetBackgroundCommand.java index 2a0c497..d74c8f8 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetBackgroundCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetBackgroundCommand.java @@ -3,8 +3,13 @@ package org.xbib.graphics.io.vector.commands; import java.awt.Color; public class SetBackgroundCommand extends StateCommand { + public SetBackgroundCommand(Color color) { super(color); } -} + @Override + public String getKey() { + return "setBackground"; + } +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetClipCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetClipCommand.java index 8bc0d28..f96fea7 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetClipCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetClipCommand.java @@ -3,8 +3,13 @@ package org.xbib.graphics.io.vector.commands; import java.awt.Shape; public class SetClipCommand extends StateCommand { + public SetClipCommand(Shape shape) { super(shape); } -} + @Override + public String getKey() { + return "setClip"; + } +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetColorCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetColorCommand.java index eb41bcf..191a30d 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetColorCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetColorCommand.java @@ -3,8 +3,13 @@ package org.xbib.graphics.io.vector.commands; import java.awt.Color; public class SetColorCommand extends StateCommand { + public SetColorCommand(Color color) { super(color); } -} + @Override + public String getKey() { + return "setColor"; + } +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetCompositeCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetCompositeCommand.java index 143ec4a..d3f01fb 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetCompositeCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetCompositeCommand.java @@ -3,8 +3,13 @@ package org.xbib.graphics.io.vector.commands; import java.awt.Composite; public class SetCompositeCommand extends StateCommand { + public SetCompositeCommand(Composite composite) { super(composite); } -} + @Override + public String getKey() { + return "setComposite"; + } +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetFontCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetFontCommand.java index 996bbdc..b78d6b5 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetFontCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetFontCommand.java @@ -3,8 +3,13 @@ package org.xbib.graphics.io.vector.commands; import java.awt.Font; public class SetFontCommand extends StateCommand { + public SetFontCommand(Font font) { super(font); } -} + @Override + public String getKey() { + return "setFont"; + } +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetHintCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetHintCommand.java index a056790..4b42781 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetHintCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetHintCommand.java @@ -3,6 +3,7 @@ package org.xbib.graphics.io.vector.commands; import java.util.Locale; public class SetHintCommand extends StateCommand { + private final Object key; public SetHintCommand(Object hintKey, Object hintValue) { @@ -10,15 +11,18 @@ public class SetHintCommand extends StateCommand { key = hintKey; } - public Object getKey() { + public Object getHintKey() { return key; } + @Override + public String getKey() { + return "setHint"; + } + @Override public String toString() { return String.format((Locale) null, - "%s[key=%s, value=%s]", getClass().getName(), - getKey(), getValue()); + "%s[key=%s, value=%s]", getKey(), getHintKey(), getValue()); } } - diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetPaintCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetPaintCommand.java index f3d3ab8..ea3eb60 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetPaintCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetPaintCommand.java @@ -3,8 +3,14 @@ package org.xbib.graphics.io.vector.commands; import java.awt.Paint; public class SetPaintCommand extends StateCommand { + public SetPaintCommand(Paint paint) { super(paint); } + + @Override + public String getKey() { + return "setPaint"; + } } diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetStrokeCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetStrokeCommand.java index da91cef..041fed0 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetStrokeCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetStrokeCommand.java @@ -3,8 +3,13 @@ package org.xbib.graphics.io.vector.commands; import java.awt.Stroke; public class SetStrokeCommand extends StateCommand { + public SetStrokeCommand(Stroke stroke) { super(stroke); } -} + @Override + public String getKey() { + return "setStroke"; + } +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetTransformCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetTransformCommand.java index 180ecdf..4eaf10d 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetTransformCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetTransformCommand.java @@ -3,8 +3,13 @@ package org.xbib.graphics.io.vector.commands; import java.awt.geom.AffineTransform; public class SetTransformCommand extends StateCommand { + public SetTransformCommand(AffineTransform transform) { super(new AffineTransform(transform)); } -} + @Override + public String getKey() { + return "setTransform"; + } +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetXORModeCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetXORModeCommand.java index e472bdf..0754c80 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetXORModeCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/SetXORModeCommand.java @@ -3,8 +3,13 @@ package org.xbib.graphics.io.vector.commands; import java.awt.Color; public class SetXORModeCommand extends StateCommand { + public SetXORModeCommand(Color mode) { super(mode); } -} + @Override + public String getKey() { + return "setXORMode"; + } +} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/ShearCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/ShearCommand.java index 25c9d60..91099ca 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/ShearCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/ShearCommand.java @@ -4,7 +4,9 @@ import java.awt.geom.AffineTransform; import java.util.Locale; public class ShearCommand extends AffineTransformCommand { + private final double shearX; + private final double shearY; public ShearCommand(double shearX, double shearY) { @@ -21,11 +23,16 @@ public class ShearCommand extends AffineTransformCommand { return shearY; } + @Override + public String getKey() { + return "shear"; + } + @Override public String toString() { return String.format((Locale) null, - "%s[shearX=%f, shearY=%f, value=%s]", getClass().getName(), - getShearX(), getShearY(), getValue()); + "%s[shearX=%f, shearY=%f, value=%s]", + getKey(), getShearX(), getShearY(), getValue()); } } diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/StateCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/StateCommand.java index cc4b0b8..f287c6b 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/StateCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/StateCommand.java @@ -3,6 +3,7 @@ package org.xbib.graphics.io.vector.commands; import org.xbib.graphics.io.vector.Command; public abstract class StateCommand extends Command { + public StateCommand(T value) { super(value); } diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/TransformCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/TransformCommand.java index 0e7ba54..a0bc319 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/TransformCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/TransformCommand.java @@ -3,6 +3,7 @@ package org.xbib.graphics.io.vector.commands; import java.awt.geom.AffineTransform; public class TransformCommand extends AffineTransformCommand { + private final AffineTransform transform; public TransformCommand(AffineTransform transform) { @@ -10,8 +11,12 @@ public class TransformCommand extends AffineTransformCommand { this.transform = new AffineTransform(transform); } + @Override + public String getKey() { + return "transform"; + } + public AffineTransform getTransform() { return transform; } } - diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/TranslateCommand.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/TranslateCommand.java index 6b48654..9130d70 100644 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/TranslateCommand.java +++ b/io-vector/src/main/java/org/xbib/graphics/io/vector/commands/TranslateCommand.java @@ -4,7 +4,9 @@ import java.awt.geom.AffineTransform; import java.util.Locale; public class TranslateCommand extends AffineTransformCommand { + private final double deltaX; + private final double deltaY; public TranslateCommand(double x, double y) { @@ -21,11 +23,15 @@ public class TranslateCommand extends AffineTransformCommand { return deltaY; } + @Override + public String getKey() { + return "translate"; + } + @Override public String toString() { return String.format((Locale) null, - "%s[deltaX=%f, deltaY=%f, value=%s]", getClass().getName(), - getDeltaX(), getDeltaY(), getValue()); + "%s[deltaX=%f, deltaY=%f, value=%s]", + getKey(), getDeltaX(), getDeltaY(), getValue()); } } - diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/Resources.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/Resources.java deleted file mode 100644 index 82ffaa8..0000000 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/pdf/Resources.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.xbib.graphics.io.vector.pdf; - -import org.xbib.graphics.io.vector.util.DataUtils; -import org.xbib.graphics.io.vector.util.GraphicsUtils; -import java.awt.Font; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -public class Resources extends PDFObject { - - private static final String KEY_PROC_SET = "ProcSet"; - private static final String KEY_TRANSPARENCY = "ExtGState"; - private static final String KEY_FONT = "Font"; - private static final String KEY_IMAGE = "XObject"; - - private static final String[] VALUE_PROC_SET = {"PDF", "Text", "ImageB", "ImageC", "ImageI"}; - - private static final String PREFIX_FONT = "Fnt"; - private static final String PREFIX_IMAGE = "Img"; - private static final String PREFIX_TRANSPARENCY = "Trp"; - - private final Map fonts; - private final Map images; - private final Map transparencies; - - private final AtomicInteger currentFontId = new AtomicInteger(); - private final AtomicInteger currentImageId = new AtomicInteger(); - private final AtomicInteger currentTransparencyId = new AtomicInteger(); - - public Resources(int id, int version) { - super(id, version, null, null); - fonts = new HashMap<>(); - images = new HashMap<>(); - transparencies = new HashMap<>(); - dict.put(KEY_PROC_SET, VALUE_PROC_SET); - } - - private String getResourceId(Map resources, T resource, - String idPrefix, AtomicInteger idCounter) { - String id = resources.get(resource); - if (id == null) { - id = String.format("%s%d", idPrefix, idCounter.getAndIncrement()); - resources.put(resource, id); - } - return id; - } - - @SuppressWarnings("unchecked") - public String getId(Font font) { - Map> dictEntry = - (Map>) dict.get(KEY_FONT); - if (dictEntry == null) { - dictEntry = new LinkedHashMap<>(); - dict.put(KEY_FONT, dictEntry); - } - font = GraphicsUtils.getPhysicalFont(font); - String resourceId = getResourceId(fonts, font, PREFIX_FONT, currentFontId); - String fontName = font.getPSName(); - // TODO: Determine font encoding (e.g. MacRomanEncoding, MacExpertEncoding, WinAnsiEncoding) - String fontEncoding = "WinAnsiEncoding"; - dictEntry.put(resourceId, DataUtils.map( - new String[]{"Type", "Subtype", "Encoding", "BaseFont"}, - new Object[]{"Font", "TrueType", fontEncoding, fontName} - )); - return resourceId; - } - - @SuppressWarnings("unchecked") - public String getId(PDFObject image) { - Map dictEntry = (Map) dict.get(KEY_IMAGE); - if (dictEntry == null) { - dictEntry = new LinkedHashMap<>(); - dict.put(KEY_IMAGE, dictEntry); - } - String resourceId = getResourceId(images, image, PREFIX_IMAGE, currentImageId); - dictEntry.put(resourceId, image); - return resourceId; - } - - @SuppressWarnings("unchecked") - public String getId(Double transparency) { - Map> dictEntry = - (Map>) dict.get(KEY_TRANSPARENCY); - if (dictEntry == null) { - dictEntry = new LinkedHashMap<>(); - dict.put(KEY_TRANSPARENCY, dictEntry); - } - String resourceId = getResourceId(transparencies, transparency, - PREFIX_TRANSPARENCY, currentTransparencyId); - dictEntry.put(resourceId, DataUtils.map( - new String[]{"Type", "ca", "CA"}, - new Object[]{"ExtGState", transparency, transparency} - )); - return resourceId; - } -} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/DataUtils.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/util/DataUtils.java deleted file mode 100644 index 357aa01..0000000 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/DataUtils.java +++ /dev/null @@ -1,240 +0,0 @@ -package org.xbib.graphics.io.vector.util; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; - -/** - * Abstract class that contains utility functions for working with data - * collections like maps or lists. - */ -public abstract class DataUtils { - /** - * Default constructor that prevents creation of class. - */ - protected DataUtils() { - throw new UnsupportedOperationException(); - } - - /** - * Creates a mapping from two arrays, one with keys, one with values. - * - * @param Data type of the keys. - * @param Data type of the values. - * @param keys Array containing the keys. - * @param values Array containing the values. - * @return Map with keys and values from the specified arrays. - */ - public static Map map(K[] keys, V[] values) { - // Check for valid parameters - if (keys.length != values.length) { - throw new IllegalArgumentException( - "Cannot create a Map: " + - "The number of keys and values differs."); - } - // Fill map with keys and values - Map map = new LinkedHashMap(keys.length); - for (int i = 0; i < keys.length; i++) { - K key = keys[i]; - V value = values[i]; - map.put(key, value); - } - return map; - } - - /** - * Returns a string containing all elements concatenated by a specified - * separator. - * - * @param separator Separator string. - * @param elements List of elements that should be concatenated. - * @return a concatenated string. - */ - public static String join(String separator, List elements) { - if (elements == null || elements.size() == 0) { - return ""; - } - StringBuilder sb = new StringBuilder(elements.size() * 3); - int i = 0; - for (Object elem : elements) { - if (separator.length() > 0 && i++ > 0) { - sb.append(separator); - } - sb.append(format(elem)); - } - return sb.toString(); - } - - /** - * Returns a string containing all elements concatenated by a specified - * separator. - * - * @param separator Separator string. - * @param elements Array of elements that should be concatenated. - * @return a concatenated string. - */ - public static String join(String separator, Object[] elements) { - if (elements == null || elements.length == 0) { - return ""; - } - return join(separator, Arrays.asList(elements)); - } - - /** - * Returns a string containing all double numbers concatenated by a - * specified separator. - * - * @param separator Separator string. - * @param elements Array of double numbers that should be concatenated. - * @return a concatenated string. - */ - public static String join(String separator, double[] elements) { - if (elements == null || elements.length == 0) { - return ""; - } - List list = new ArrayList(elements.length); - for (Double element : elements) { - list.add(element); - } - return join(separator, list); - } - - /** - * Returns a string containing all float numbers concatenated by a - * specified separator. - * - * @param separator Separator string. - * @param elements Array of float numbers that should be concatenated. - * @return a concatenated string. - */ - public static String join(String separator, float[] elements) { - if (elements == null || elements.length == 0) { - return ""; - } - List list = new ArrayList(elements.length); - for (Float element : elements) { - list.add(element); - } - return join(separator, list); - } - - /** - * Returns the largest of all specified values. - * - * @param values Several integer values. - * @return largest value. - */ - public static int max(int... values) { - int max = values[0]; - for (int i = 1; i < values.length; i++) { - if (values[i] > max) { - max = values[i]; - } - } - return max; - } - - /** - * Copies data from an input stream to an output stream using a buffer of - * specified size. - * - * @param in Input stream. - * @param out Output stream. - * @param bufferSize Size of the copy buffer. - * @throws IOException when an error occurs while copying. - */ - public static void transfer(InputStream in, OutputStream out, int bufferSize) - throws IOException { - byte[] buffer = new byte[bufferSize]; - int bytesRead; - while ((bytesRead = in.read(buffer)) != -1) { - out.write(buffer, 0, bytesRead); - } - } - - /** - * Returns a formatted string of the specified number. All trailing zeroes - * or decimal points will be stripped. - * - * @param number Number to convert to a string. - * @return A formatted string. - */ - public static String format(Number number) { - String formatted; - if (number instanceof Double || number instanceof Float) { - formatted = Double.toString(number.doubleValue()) - .replaceAll("\\.0+$", "") - .replaceAll("(\\.[0-9]*[1-9])0+$", "$1"); - } else { - formatted = number.toString(); - } - return formatted; - } - - /** - * Returns a formatted string of the specified object. - * - * @param obj Object to convert to a string. - * @return A formatted string. - */ - public static String format(Object obj) { - if (obj instanceof Number) { - return format((Number) obj); - } else { - return obj.toString(); - } - } - - /** - * Converts an array of {@code float} numbers to a list of {@code Float}s. - * The list will be empty if the array is empty or {@code null}. - * - * @param elements Array of float numbers. - * @return A list with all numbers as {@code Float}. - */ - public static List asList(float[] elements) { - int size = (elements != null) ? elements.length : 0; - List list = new ArrayList<>(size); - if (elements != null) { - for (Float elem : elements) { - list.add(elem); - } - } - return list; - } - - /** - * Converts an array of {@code double} numbers to a list of {@code Double}s. - * The list will be empty if the array is empty or {@code null}. - * - * @param elements Array of double numbers. - * @return A list with all numbers as {@code Double}. - */ - public static List asList(double[] elements) { - int size = (elements != null) ? elements.length : 0; - List list = new ArrayList<>(size); - if (elements != null) { - for (Double elem : elements) { - list.add(elem); - } - } - return list; - } - - /** - * Removes the specified trailing pattern from a string. - * - * @param s string. - * @param substr trailing pattern. - * @return A string without the trailing pattern. - */ - public static String stripTrailing(String s, String substr) { - return s.replaceAll("(" + Pattern.quote(substr) + ")+$", ""); - } -} diff --git a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/GraphicsUtils.java b/io-vector/src/main/java/org/xbib/graphics/io/vector/util/GraphicsUtils.java deleted file mode 100644 index 35a0e67..0000000 --- a/io-vector/src/main/java/org/xbib/graphics/io/vector/util/GraphicsUtils.java +++ /dev/null @@ -1,411 +0,0 @@ -package org.xbib.graphics.io.vector.util; - -import java.awt.Font; -import java.awt.Graphics; -import java.awt.GraphicsConfiguration; -import java.awt.GraphicsDevice; -import java.awt.GraphicsEnvironment; -import java.awt.HeadlessException; -import java.awt.Image; -import java.awt.Polygon; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.Transparency; -import java.awt.color.ColorSpace; -import java.awt.font.FontRenderContext; -import java.awt.font.TextLayout; -import java.awt.geom.Arc2D; -import java.awt.geom.CubicCurve2D; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Line2D; -import java.awt.geom.Path2D; -import java.awt.geom.PathIterator; -import java.awt.geom.QuadCurve2D; -import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; -import java.awt.image.BufferedImage; -import java.awt.image.ColorModel; -import java.awt.image.ComponentColorModel; -import java.awt.image.DataBuffer; -import java.awt.image.PixelGrabber; -import java.awt.image.Raster; -import java.awt.image.RenderedImage; -import java.awt.image.WritableRaster; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.PriorityQueue; -import java.util.Queue; -import java.util.Set; -import javax.swing.ImageIcon; - -/** - * Abstract class that contains utility functions for working with graphics. - * For example, this includes font handling. - */ -public abstract class GraphicsUtils { - private static final FontRenderContext FONT_RENDER_CONTEXT = - new FontRenderContext(null, false, true); - private static final String FONT_TEST_STRING = - "Falsches Üben von Xylophonmusik quält jeden größeren Zwerg"; - private static final FontExpressivenessComparator FONT_EXPRESSIVENESS_COMPARATOR = - new FontExpressivenessComparator(); - - /** - * Default constructor that prevents creation of class. - */ - protected GraphicsUtils() { - throw new UnsupportedOperationException(); - } - - /** - * This method returns {@code true} if the specified image has the - * possibility to store transparent pixels. - * Inspired by http://www.exampledepot.com/egs/java.awt.image/HasAlpha.html - * - * @param image Image that should be checked for alpha channel. - * @return {@code true} if the specified image can have transparent pixels, - * {@code false} otherwise - */ - public static boolean hasAlpha(Image image) { - ColorModel cm; - // If buffered image, the color model is readily available - if (image instanceof BufferedImage) { - BufferedImage bimage = (BufferedImage) image; - cm = bimage.getColorModel(); - } else { - // Use a pixel grabber to retrieve the image's color model; - // grabbing a single pixel is usually sufficient - PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false); - try { - pg.grabPixels(); - } catch (InterruptedException e) { - return false; - } - // Get the image's color model - cm = pg.getColorModel(); - } - return cm.hasAlpha(); - } - - /** - * This method returns {@code true} if the specified image has at least one - * pixel that is not fully opaque. - * - * @param image Image that should be checked for non-opaque pixels. - * @return {@code true} if the specified image has transparent pixels, - * {@code false} otherwise - */ - public static boolean usesAlpha(Image image) { - if (image == null) { - return false; - } - BufferedImage bimage = toBufferedImage(image); - Raster alphaRaster = bimage.getAlphaRaster(); - if (alphaRaster == null) { - return false; - } - DataBuffer dataBuffer = alphaRaster.getDataBuffer(); - for (int i = 0; i < dataBuffer.getSize(); i++) { - int alpha = dataBuffer.getElem(i); - if (alpha < 255) { - return true; - } - } - return false; - } - - /** - * Converts an arbitrary image to a {@code BufferedImage}. - * - * @param image Image that should be converted. - * @return a buffered image containing the image pixels, or the original - * instance if the image already was of type {@code BufferedImage}. - */ - public static BufferedImage toBufferedImage(RenderedImage image) { - if (image instanceof BufferedImage) { - return (BufferedImage) image; - } - - ColorModel cm = image.getColorModel(); - WritableRaster raster = cm.createCompatibleWritableRaster( - image.getWidth(), image.getHeight()); - boolean isRasterPremultiplied = cm.isAlphaPremultiplied(); - Hashtable properties = null; - if (image.getPropertyNames() != null) { - properties = new Hashtable(); - for (String key : image.getPropertyNames()) { - properties.put(key, image.getProperty(key)); - } - } - - BufferedImage bimage = new BufferedImage(cm, raster, - isRasterPremultiplied, properties); - image.copyData(raster); - return bimage; - } - - /** - * This method returns a buffered image with the contents of an image. - * Taken from http://www.exampledepot.com/egs/java.awt.image/Image2Buf.html - * - * @param image Image to be converted - * @return a buffered image with the contents of the specified image - */ - public static BufferedImage toBufferedImage(Image image) { - if (image instanceof BufferedImage) { - return (BufferedImage) image; - } - // This code ensures that all the pixels in the image are loaded - image = new ImageIcon(image).getImage(); - // Determine if the image has transparent pixels - boolean hasAlpha = hasAlpha(image); - - // Create a buffered image with a format that's compatible with the - // screen - BufferedImage bimage; - GraphicsEnvironment ge = GraphicsEnvironment - .getLocalGraphicsEnvironment(); - try { - // Determine the type of transparency of the new buffered image - int transparency = Transparency.OPAQUE; - if (hasAlpha) { - transparency = Transparency.TRANSLUCENT; - } - // Create the buffered image - GraphicsDevice gs = ge.getDefaultScreenDevice(); - GraphicsConfiguration gc = gs.getDefaultConfiguration(); - bimage = gc.createCompatibleImage( - image.getWidth(null), image.getHeight(null), transparency); - } catch (HeadlessException e) { - // The system does not have a screen - bimage = null; - } - if (bimage == null) { - // Create a buffered image using the default color model - int type = BufferedImage.TYPE_INT_RGB; - if (hasAlpha) { - type = BufferedImage.TYPE_INT_ARGB; - } - bimage = new BufferedImage( - image.getWidth(null), image.getHeight(null), type); - } - // Copy image to buffered image - Graphics g = bimage.createGraphics(); - // Paint the image onto the buffered image - g.drawImage(image, 0, 0, null); - g.dispose(); - return bimage; - } - - public static Shape clone(Shape shape) { - if (shape == null) { - return null; - } - Shape clone; - if (shape instanceof Line2D) { - clone = (shape instanceof Line2D.Float) ? - new Line2D.Float() : new Line2D.Double(); - ((Line2D) clone).setLine((Line2D) shape); - } else if (shape instanceof Rectangle) { - clone = new Rectangle((Rectangle) shape); - } else if (shape instanceof Rectangle2D) { - clone = (shape instanceof Rectangle2D.Float) ? - new Rectangle2D.Float() : new Rectangle2D.Double(); - ((Rectangle2D) clone).setRect((Rectangle2D) shape); - } else if (shape instanceof RoundRectangle2D) { - clone = (shape instanceof RoundRectangle2D.Float) ? - new RoundRectangle2D.Float() : new RoundRectangle2D.Double(); - ((RoundRectangle2D) clone).setRoundRect((RoundRectangle2D) shape); - } else if (shape instanceof Ellipse2D) { - clone = (shape instanceof Ellipse2D.Float) ? - new Ellipse2D.Float() : new Ellipse2D.Double(); - ((Ellipse2D) clone).setFrame(((Ellipse2D) shape).getFrame()); - } else if (shape instanceof Arc2D) { - clone = (shape instanceof Arc2D.Float) ? - new Arc2D.Float() : new Arc2D.Double(); - ((Arc2D) clone).setArc((Arc2D) shape); - } else if (shape instanceof Polygon) { - Polygon p = (Polygon) shape; - clone = new Polygon(p.xpoints, p.ypoints, p.npoints); - } else if (shape instanceof CubicCurve2D) { - clone = (shape instanceof CubicCurve2D.Float) ? - new CubicCurve2D.Float() : new CubicCurve2D.Double(); - ((CubicCurve2D) clone).setCurve((CubicCurve2D) shape); - } else if (shape instanceof QuadCurve2D) { - clone = (shape instanceof QuadCurve2D.Float) ? - new QuadCurve2D.Float() : new QuadCurve2D.Double(); - ((QuadCurve2D) clone).setCurve((QuadCurve2D) shape); - } else if (shape instanceof Path2D.Float) { - clone = new Path2D.Float(shape); - } else { - clone = new Path2D.Double(shape); - } - return clone; - } - - private static boolean isLogicalFontFamily(String family) { - return (Font.DIALOG.equals(family) || - Font.DIALOG_INPUT.equals(family) || - Font.SANS_SERIF.equals(family) || - Font.SERIF.equals(family) || - Font.MONOSPACED.equals(family)); - } - - /** - * Try to guess physical font from the properties of a logical font, like - * "Dialog", "Serif", "Monospaced" etc. - * - * @param logicalFont Logical font object. - * @param testText Text used to determine font properties. - * @return An object of the first matching physical font. The original font - * object is returned if it was a physical font or no font matched. - */ - public static Font getPhysicalFont(Font logicalFont, String testText) { - String logicalFamily = logicalFont.getFamily(); - if (!isLogicalFontFamily(logicalFamily)) { - return logicalFont; - } - - final TextLayout logicalLayout = - new TextLayout(testText, logicalFont, FONT_RENDER_CONTEXT); - - // Create a list of matches sorted by font expressiveness (in descending order) - Queue physicalFonts = - new PriorityQueue(1, FONT_EXPRESSIVENESS_COMPARATOR); - - Font[] allPhysicalFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); - for (Font physicalFont : allPhysicalFonts) { - String physicalFamily = physicalFont.getFamily(); - // Skip logical fonts - if (isLogicalFontFamily(physicalFamily)) { - continue; - } - - // Derive identical variant of physical font - physicalFont = physicalFont.deriveFont( - logicalFont.getStyle(), logicalFont.getSize2D()); - TextLayout physicalLayout = - new TextLayout(testText, physicalFont, FONT_RENDER_CONTEXT); - - // Compare various properties of physical and logical font - if (physicalLayout.getBounds().equals(logicalLayout.getBounds()) && - physicalLayout.getAscent() == logicalLayout.getAscent() && - physicalLayout.getDescent() == logicalLayout.getDescent() && - physicalLayout.getLeading() == logicalLayout.getLeading() && - physicalLayout.getAdvance() == logicalLayout.getAdvance() && - physicalLayout.getVisibleAdvance() == logicalLayout.getVisibleAdvance()) { - // Store matching font in list - physicalFonts.add(physicalFont); - } - } - - // Return a valid font even when no matching font could be found - if (physicalFonts.isEmpty()) { - return logicalFont; - } - - return physicalFonts.poll(); - } - - public static Font getPhysicalFont(Font logicalFont) { - return getPhysicalFont(logicalFont, FONT_TEST_STRING); - } - - public static BufferedImage getAlphaImage(BufferedImage image) { - WritableRaster alphaRaster = image.getAlphaRaster(); - int width = image.getWidth(); - int height = image.getHeight(); - - ColorModel cm; - WritableRaster raster; - // TODO Handle bitmap masks (work on ImageDataStream is necessary) - /* - if (image.getTransparency() == BufferedImage.BITMASK) { - byte[] arr = {(byte) 0, (byte) 255}; - - cm = new IndexColorModel(1, 2, arr, arr, arr); - raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, - width, height, 1, 1, null); - } else {*/ - ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY); - int[] bits = {8}; - cm = new ComponentColorModel(colorSpace, bits, false, true, - Transparency.OPAQUE, DataBuffer.TYPE_BYTE); - raster = cm.createCompatibleWritableRaster(width, height); - //} - - BufferedImage alphaImage = new BufferedImage(cm, raster, false, null); - - int[] alphaValues = new int[image.getWidth() * alphaRaster.getNumBands()]; - for (int y = 0; y < image.getHeight(); y++) { - alphaRaster.getPixels(0, y, image.getWidth(), 1, alphaValues); - // FIXME Don't force 8-bit alpha channel (see TODO above) - if (image.getTransparency() == BufferedImage.BITMASK) { - for (int i = 0; i < alphaValues.length; i++) { - if (alphaValues[i] > 0) { - alphaValues[i] = 255; - } - } - } - alphaImage.getRaster().setPixels(0, y, image.getWidth(), 1, alphaValues); - } - - return alphaImage; - } - - public static boolean equals(Shape shapeA, Shape shapeB) { - PathIterator pathAIterator = shapeA.getPathIterator(null); - PathIterator pathBIterator = shapeB.getPathIterator(null); - - if (pathAIterator.getWindingRule() != pathBIterator.getWindingRule()) { - return false; - } - double[] pathASegment = new double[6]; - double[] pathBSegment = new double[6]; - while (!pathAIterator.isDone()) { - int pathASegmentType = pathAIterator.currentSegment(pathASegment); - int pathBSegmentType = pathBIterator.currentSegment(pathBSegment); - if (pathASegmentType != pathBSegmentType) { - return false; - } - for (int segmentIndex = 0; segmentIndex < pathASegment.length; segmentIndex++) { - if (pathASegment[segmentIndex] != pathBSegment[segmentIndex]) { - return false; - } - } - - pathAIterator.next(); - pathBIterator.next(); - } - // When the iterator of shapeA is done and shapeA equals shapeB, the iterator of shapeB must also be done - if (!pathBIterator.isDone()) { - return false; - } - return true; - } - - private static class FontExpressivenessComparator implements Comparator { - private static final int[] STYLES = { - Font.PLAIN, Font.ITALIC, Font.BOLD, Font.BOLD | Font.ITALIC - }; - - public int compare(Font font1, Font font2) { - if (font1 == font2) { - return 0; - } - Set variantNames1 = new HashSet(); - Set variantNames2 = new HashSet(); - for (int style : STYLES) { - variantNames1.add(font1.deriveFont(style).getPSName()); - variantNames2.add(font2.deriveFont(style).getPSName()); - } - if (variantNames1.size() < variantNames2.size()) { - return 1; - } else if (variantNames1.size() > variantNames2.size()) { - return -1; - } - return font1.getName().compareTo(font2.getName()); - } - } -} diff --git a/io-vector/src/test/java/org/xbib/graphics/io/vector/GraphicsStateTest.java b/io-vector/src/test/java/org/xbib/graphics/io/vector/GraphicsStateTest.java index 0155651..1cab5bb 100644 --- a/io-vector/src/test/java/org/xbib/graphics/io/vector/GraphicsStateTest.java +++ b/io-vector/src/test/java/org/xbib/graphics/io/vector/GraphicsStateTest.java @@ -1,14 +1,28 @@ package org.xbib.graphics.io.vector; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotSame; import org.junit.jupiter.api.Test; import java.awt.Color; import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.Shape; import java.awt.geom.AffineTransform; +import java.awt.geom.Arc2D; +import java.awt.geom.CubicCurve2D; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Line2D; +import java.awt.geom.Path2D; +import java.awt.geom.PathIterator; +import java.awt.geom.QuadCurve2D; import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; +import java.lang.reflect.InvocationTargetException; public class GraphicsStateTest { @@ -52,4 +66,75 @@ public class GraphicsStateTest { assertNotSame(state, clone); assertEquals(state, clone); } + + + @Test + public void testCloneShape() + throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { + Class[] shapeClasses = { + Line2D.Float.class, + Line2D.Double.class, + Rectangle.class, + Rectangle2D.Float.class, + Rectangle2D.Double.class, + RoundRectangle2D.Float.class, + RoundRectangle2D.Double.class, + Ellipse2D.Float.class, + Ellipse2D.Double.class, + Arc2D.Float.class, + Arc2D.Double.class, + Polygon.class, + CubicCurve2D.Float.class, + CubicCurve2D.Double.class, + QuadCurve2D.Float.class, + QuadCurve2D.Double.class, + Path2D.Float.class, + Path2D.Double.class + }; + for (Class shapeClass : shapeClasses) { + Shape shape = (Shape) shapeClass.getDeclaredConstructor().newInstance(); + Shape clone = GraphicsState.clone(shape); + assertNotNull(clone); + assertShapeEquals(shape, clone); + } + } + + private static void assertShapeEquals(Shape expected, Shape actual) { + if ((expected instanceof Line2D) && (actual instanceof Line2D)) { + assertEquals(((Line2D) expected).getP1(), ((Line2D) actual).getP1()); + assertEquals(((Line2D) expected).getP2(), ((Line2D) actual).getP2()); + } else if ((expected instanceof Polygon) && (actual instanceof Polygon)) { + int n = ((Polygon) actual).npoints; + assertEquals(((Polygon) expected).npoints, n); + if (n > 0) { + assertArrayEquals(((Polygon) expected).xpoints, ((Polygon) actual).xpoints); + assertArrayEquals(((Polygon) expected).ypoints, ((Polygon) actual).ypoints); + } + } else if ((expected instanceof QuadCurve2D) && (actual instanceof QuadCurve2D)) { + assertEquals(((QuadCurve2D) expected).getP1(), ((QuadCurve2D) actual).getP1()); + assertEquals(((QuadCurve2D) expected).getCtrlPt(), ((QuadCurve2D) actual).getCtrlPt()); + assertEquals(((QuadCurve2D) expected).getP2(), ((QuadCurve2D) actual).getP2()); + } else if ((expected instanceof CubicCurve2D) && (actual instanceof CubicCurve2D)) { + assertEquals(((CubicCurve2D) expected).getP1(), ((CubicCurve2D) actual).getP1()); + assertEquals(((CubicCurve2D) expected).getCtrlP1(), ((CubicCurve2D) actual).getCtrlP1()); + assertEquals(((CubicCurve2D) expected).getCtrlP2(), ((CubicCurve2D) actual).getCtrlP2()); + assertEquals(((CubicCurve2D) expected).getP2(), ((CubicCurve2D) actual).getP2()); + } else if ((expected instanceof Path2D) && (actual instanceof Path2D)) { + PathIterator itExpected = expected.getPathIterator(null); + PathIterator itActual = actual.getPathIterator(null); + double[] segmentExpected = new double[6]; + double[] segmentActual = new double[6]; + for (; !itExpected.isDone() || !itActual.isDone(); itExpected.next(), itActual.next()) { + assertEquals(itExpected.getWindingRule(), itActual.getWindingRule()); + itExpected.currentSegment(segmentExpected); + itActual.currentSegment(segmentActual); + assertArrayEquals(segmentExpected, segmentActual, DELTA); + } + } else { + assertEquals(expected, actual); + } + } + + private static final double DELTA = 1e-15; + } diff --git a/io-vector/src/test/java/org/xbib/graphics/io/vector/VectorGraphics2DTest.java b/io-vector/src/test/java/org/xbib/graphics/io/vector/VectorGraphics2DTest.java index cd6c93d..3770bd5 100644 --- a/io-vector/src/test/java/org/xbib/graphics/io/vector/VectorGraphics2DTest.java +++ b/io-vector/src/test/java/org/xbib/graphics/io/vector/VectorGraphics2DTest.java @@ -1,13 +1,21 @@ package org.xbib.graphics.io.vector; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.xbib.graphics.io.vector.VectorGraphics2D.hasAlpha; +import static org.xbib.graphics.io.vector.VectorGraphics2D.toBufferedImage; import org.junit.jupiter.api.Test; import org.xbib.graphics.io.vector.commands.CreateCommand; import org.xbib.graphics.io.vector.commands.DisposeCommand; import java.awt.Color; import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.awt.image.FilteredImageSource; +import java.awt.image.RGBImageFilter; import java.util.Iterator; public class VectorGraphics2DTest { @@ -53,4 +61,40 @@ public class VectorGraphics2DTest { assertTrue(lastCommand instanceof DisposeCommand); assertEquals(Color.BLUE, ((DisposeCommand) lastCommand).getValue().getColor()); } + + + @Test + public void testToBufferedImage() { + Image[] images = { + new BufferedImage(320, 240, BufferedImage.TYPE_INT_ARGB), + new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB), + Toolkit.getDefaultToolkit().createImage(new FilteredImageSource( + new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB).getSource(), + new RGBImageFilter() { + @Override + public int filterRGB(int x, int y, int rgb) { + return rgb & 0xff; + } + } + )) + }; + + for (Image image : images) { + BufferedImage bimage = toBufferedImage(image); + assertNotNull(bimage); + assertEquals(BufferedImage.class, bimage.getClass()); + assertEquals(image.getWidth(null), bimage.getWidth()); + assertEquals(image.getHeight(null), bimage.getHeight()); + } + } + + @Test + public void testHasAlpha() { + Image image; + image = new BufferedImage(320, 240, BufferedImage.TYPE_INT_ARGB); + assertTrue(hasAlpha(image)); + image = new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB); + assertFalse(hasAlpha(image)); + } + } diff --git a/io-vector/src/test/java/org/xbib/graphics/io/filters/AbsoluteToRelativeTransformsFilterTest.java b/io-vector/src/test/java/org/xbib/graphics/io/vector/filters/AbsoluteToRelativeTransformsFilterTest.java similarity index 96% rename from io-vector/src/test/java/org/xbib/graphics/io/filters/AbsoluteToRelativeTransformsFilterTest.java rename to io-vector/src/test/java/org/xbib/graphics/io/vector/filters/AbsoluteToRelativeTransformsFilterTest.java index 77d4d1f..fb9da58 100644 --- a/io-vector/src/test/java/org/xbib/graphics/io/filters/AbsoluteToRelativeTransformsFilterTest.java +++ b/io-vector/src/test/java/org/xbib/graphics/io/vector/filters/AbsoluteToRelativeTransformsFilterTest.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.io.filters; +package org.xbib.graphics.io.vector.filters; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -9,7 +9,6 @@ import org.xbib.graphics.io.vector.commands.DisposeCommand; import org.xbib.graphics.io.vector.commands.SetTransformCommand; import org.xbib.graphics.io.vector.commands.TransformCommand; import org.xbib.graphics.io.vector.commands.TranslateCommand; -import org.xbib.graphics.io.vector.filters.AbsoluteToRelativeTransformsFilter; import java.awt.geom.AffineTransform; import java.util.ArrayList; import java.util.Arrays; diff --git a/io-vector/src/test/java/org/xbib/graphics/io/filters/FillPaintedShapeAsImageFilterTest.java b/io-vector/src/test/java/org/xbib/graphics/io/vector/filters/FillPaintedShapeAsImageFilterTest.java similarity index 94% rename from io-vector/src/test/java/org/xbib/graphics/io/filters/FillPaintedShapeAsImageFilterTest.java rename to io-vector/src/test/java/org/xbib/graphics/io/vector/filters/FillPaintedShapeAsImageFilterTest.java index b442ad0..c0f071a 100644 --- a/io-vector/src/test/java/org/xbib/graphics/io/filters/FillPaintedShapeAsImageFilterTest.java +++ b/io-vector/src/test/java/org/xbib/graphics/io/vector/filters/FillPaintedShapeAsImageFilterTest.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.io.filters; +package org.xbib.graphics.io.vector.filters; import static org.hamcrest.CoreMatchers.any; import static org.hamcrest.MatcherAssert.assertThat; @@ -12,7 +12,6 @@ import org.xbib.graphics.io.vector.commands.DrawImageCommand; import org.xbib.graphics.io.vector.commands.FillShapeCommand; import org.xbib.graphics.io.vector.commands.RotateCommand; import org.xbib.graphics.io.vector.commands.SetPaintCommand; -import org.xbib.graphics.io.vector.filters.FillPaintedShapeAsImageFilter; import java.awt.Color; import java.awt.GradientPaint; import java.awt.geom.Rectangle2D; diff --git a/io-vector/src/test/java/org/xbib/graphics/io/filters/FilterTest.java b/io-vector/src/test/java/org/xbib/graphics/io/vector/filters/FilterTest.java similarity index 97% rename from io-vector/src/test/java/org/xbib/graphics/io/filters/FilterTest.java rename to io-vector/src/test/java/org/xbib/graphics/io/vector/filters/FilterTest.java index f0f7281..ff4800b 100644 --- a/io-vector/src/test/java/org/xbib/graphics/io/filters/FilterTest.java +++ b/io-vector/src/test/java/org/xbib/graphics/io/vector/filters/FilterTest.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.io.filters; +package org.xbib.graphics.io.vector.filters; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -9,7 +9,6 @@ import org.xbib.graphics.io.vector.commands.DrawShapeCommand; import org.xbib.graphics.io.vector.commands.SetColorCommand; import org.xbib.graphics.io.vector.commands.SetStrokeCommand; import org.xbib.graphics.io.vector.commands.SetTransformCommand; -import org.xbib.graphics.io.vector.filters.Filter; import java.awt.BasicStroke; import java.awt.Color; import java.awt.geom.AffineTransform; diff --git a/io-vector/src/test/java/org/xbib/graphics/io/filters/GroupingFilterTest.java b/io-vector/src/test/java/org/xbib/graphics/io/vector/filters/GroupingFilterTest.java similarity index 94% rename from io-vector/src/test/java/org/xbib/graphics/io/filters/GroupingFilterTest.java rename to io-vector/src/test/java/org/xbib/graphics/io/vector/filters/GroupingFilterTest.java index 16edfd5..5528dbc 100644 --- a/io-vector/src/test/java/org/xbib/graphics/io/filters/GroupingFilterTest.java +++ b/io-vector/src/test/java/org/xbib/graphics/io/vector/filters/GroupingFilterTest.java @@ -1,4 +1,4 @@ -package org.xbib.graphics.io.filters; +package org.xbib.graphics.io.vector.filters; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; @@ -9,8 +9,6 @@ import org.xbib.graphics.io.vector.commands.SetColorCommand; import org.xbib.graphics.io.vector.commands.SetStrokeCommand; import org.xbib.graphics.io.vector.commands.SetTransformCommand; import org.xbib.graphics.io.vector.commands.StateCommand; -import org.xbib.graphics.io.vector.filters.Filter; -import org.xbib.graphics.io.vector.filters.GroupingFilter; import java.awt.BasicStroke; import java.awt.Color; import java.awt.geom.AffineTransform; diff --git a/io-vector/src/test/java/org/xbib/graphics/io/vector/util/DataUtilsTest.java b/io-vector/src/test/java/org/xbib/graphics/io/vector/util/DataUtilsTest.java deleted file mode 100644 index cb8ce55..0000000 --- a/io-vector/src/test/java/org/xbib/graphics/io/vector/util/DataUtilsTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.xbib.graphics.io.vector.util; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.jupiter.api.Test; - -public class DataUtilsTest { - - @Test - public void stripTrailingSpaces() { - String result = DataUtils.stripTrailing(" foo bar! ", " "); - String expected = " foo bar!"; - assertEquals(expected, result); - } - - @Test - public void stripTrailingSpacesInMultilineString() { - String result = DataUtils.stripTrailing(" foo bar! \n ", " "); - String expected = " foo bar! \n"; - assertEquals(expected, result); - } - - @Test - public void stripComplexSubstring() { - String result = DataUtils.stripTrailing("+bar foo+bar+bar+bar", "+bar"); - String expected = "+bar foo"; - assertEquals(expected, result); - } -} diff --git a/io-vector/src/test/java/org/xbib/graphics/io/vector/util/GraphicsUtilsTest.java b/io-vector/src/test/java/org/xbib/graphics/io/vector/util/GraphicsUtilsTest.java deleted file mode 100644 index 3672382..0000000 --- a/io-vector/src/test/java/org/xbib/graphics/io/vector/util/GraphicsUtilsTest.java +++ /dev/null @@ -1,142 +0,0 @@ -package org.xbib.graphics.io.vector.util; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNotSame; -import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.jupiter.api.Test; -import java.awt.Font; -import java.awt.Image; -import java.awt.Polygon; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.Toolkit; -import java.awt.geom.Arc2D; -import java.awt.geom.CubicCurve2D; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Line2D; -import java.awt.geom.Path2D; -import java.awt.geom.PathIterator; -import java.awt.geom.QuadCurve2D; -import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; -import java.awt.image.BufferedImage; -import java.awt.image.FilteredImageSource; -import java.awt.image.RGBImageFilter; -import java.lang.reflect.InvocationTargetException; - -/** - * On Linux, the package msttcorefonts need to be installed. - */ -public class GraphicsUtilsTest { - private static final double DELTA = 1e-15; - - private static void assertShapeEquals(Shape expected, Shape actual) { - if ((expected instanceof Line2D) && (actual instanceof Line2D)) { - assertEquals(((Line2D) expected).getP1(), ((Line2D) actual).getP1()); - assertEquals(((Line2D) expected).getP2(), ((Line2D) actual).getP2()); - } else if ((expected instanceof Polygon) && (actual instanceof Polygon)) { - int n = ((Polygon) actual).npoints; - assertEquals(((Polygon) expected).npoints, n); - if (n > 0) { - assertArrayEquals(((Polygon) expected).xpoints, ((Polygon) actual).xpoints); - assertArrayEquals(((Polygon) expected).ypoints, ((Polygon) actual).ypoints); - } - } else if ((expected instanceof QuadCurve2D) && (actual instanceof QuadCurve2D)) { - assertEquals(((QuadCurve2D) expected).getP1(), ((QuadCurve2D) actual).getP1()); - assertEquals(((QuadCurve2D) expected).getCtrlPt(), ((QuadCurve2D) actual).getCtrlPt()); - assertEquals(((QuadCurve2D) expected).getP2(), ((QuadCurve2D) actual).getP2()); - } else if ((expected instanceof CubicCurve2D) && (actual instanceof CubicCurve2D)) { - assertEquals(((CubicCurve2D) expected).getP1(), ((CubicCurve2D) actual).getP1()); - assertEquals(((CubicCurve2D) expected).getCtrlP1(), ((CubicCurve2D) actual).getCtrlP1()); - assertEquals(((CubicCurve2D) expected).getCtrlP2(), ((CubicCurve2D) actual).getCtrlP2()); - assertEquals(((CubicCurve2D) expected).getP2(), ((CubicCurve2D) actual).getP2()); - } else if ((expected instanceof Path2D) && (actual instanceof Path2D)) { - PathIterator itExpected = expected.getPathIterator(null); - PathIterator itActual = actual.getPathIterator(null); - double[] segmentExpected = new double[6]; - double[] segmentActual = new double[6]; - for (; !itExpected.isDone() || !itActual.isDone(); itExpected.next(), itActual.next()) { - assertEquals(itExpected.getWindingRule(), itActual.getWindingRule()); - itExpected.currentSegment(segmentExpected); - itActual.currentSegment(segmentActual); - assertArrayEquals(segmentExpected, segmentActual, DELTA); - } - } else { - assertEquals(expected, actual); - } - } - - @Test - public void testToBufferedImage() { - Image[] images = { - new BufferedImage(320, 240, BufferedImage.TYPE_INT_ARGB), - new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB), - Toolkit.getDefaultToolkit().createImage(new FilteredImageSource( - new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB).getSource(), - new RGBImageFilter() { - @Override - public int filterRGB(int x, int y, int rgb) { - return rgb & 0xff; - } - } - )) - }; - - for (Image image : images) { - BufferedImage bimage = GraphicsUtils.toBufferedImage(image); - assertNotNull(bimage); - assertEquals(BufferedImage.class, bimage.getClass()); - assertEquals(image.getWidth(null), bimage.getWidth()); - assertEquals(image.getHeight(null), bimage.getHeight()); - } - } - - @Test - public void testHasAlpha() { - Image image; - image = new BufferedImage(320, 240, BufferedImage.TYPE_INT_ARGB); - assertTrue(GraphicsUtils.hasAlpha(image)); - image = new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB); - assertFalse(GraphicsUtils.hasAlpha(image)); - } - - @Test - public void testPhysicalFont() { - Font font = new Font("Monospaced", Font.PLAIN, 12); - assertNotSame(font, GraphicsUtils.getPhysicalFont(font)); - } - - @Test - public void testCloneShape() - throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { - Class[] shapeClasses = { - Line2D.Float.class, - Line2D.Double.class, - Rectangle.class, - Rectangle2D.Float.class, - Rectangle2D.Double.class, - RoundRectangle2D.Float.class, - RoundRectangle2D.Double.class, - Ellipse2D.Float.class, - Ellipse2D.Double.class, - Arc2D.Float.class, - Arc2D.Double.class, - Polygon.class, - CubicCurve2D.Float.class, - CubicCurve2D.Double.class, - QuadCurve2D.Float.class, - QuadCurve2D.Double.class, - Path2D.Float.class, - Path2D.Double.class - }; - for (Class shapeClass : shapeClasses) { - Shape shape = (Shape) shapeClass.getDeclaredConstructor().newInstance(); - Shape clone = GraphicsUtils.clone(shape); - assertNotNull(clone); - assertShapeEquals(shape, clone); - } - } -} diff --git a/io-vector/src/test/java/org/xbib/graphics/io/visual/AbstractTest.java b/io-vector/src/test/java/org/xbib/graphics/io/visual/AbstractTest.java index 2dc575a..eb3f089 100644 --- a/io-vector/src/test/java/org/xbib/graphics/io/visual/AbstractTest.java +++ b/io-vector/src/test/java/org/xbib/graphics/io/visual/AbstractTest.java @@ -1,8 +1,5 @@ package org.xbib.graphics.io.visual; -import org.xbib.graphics.io.vector.eps.EPSGraphics2D; -import org.xbib.graphics.io.vector.pdf.PDFGraphics2D; -import org.xbib.graphics.io.vector.svg.SVGGraphics2D; import org.xbib.graphics.io.vector.PageSize; import java.awt.Color; import java.awt.Graphics2D; @@ -20,22 +17,22 @@ public abstract class AbstractTest { private final BufferedImage reference; - private final EPSGraphics2D epsGraphics; + //private final EPSGraphics2D epsGraphics; - private final PDFGraphics2D pdfGraphics; + //private final PDFGraphics2D pdfGraphics; - private final SVGGraphics2D svgGraphics; + //private final SVGGraphics2D svgGraphics; public AbstractTest() throws IOException { int width = 150; int height = 150; pageSize = new PageSize(0.0, 0.0, width, height); - epsGraphics = new EPSGraphics2D(0, 0, width, height); - draw(epsGraphics); - pdfGraphics = new PDFGraphics2D(0, 0, width, height); - draw(pdfGraphics); - svgGraphics = new SVGGraphics2D(0, 0, width, height); - draw(svgGraphics); + //epsGraphics = new EPSGraphics2D(0, 0, width, height); + //draw(epsGraphics); + //pdfGraphics = new PDFGraphics2D(0, 0, width, height); + //draw(pdfGraphics); + //svgGraphics = new SVGGraphics2D(0, 0, width, height); + //draw(svgGraphics); reference = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D referenceGraphics = reference.createGraphics(); referenceGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); @@ -59,7 +56,7 @@ public abstract class AbstractTest { return reference; } - public InputStream getEPS() { + /*public InputStream getEPS() { try { return new ByteArrayInputStream(epsGraphics.getBytes()); } catch (IOException e) { @@ -81,6 +78,5 @@ public abstract class AbstractTest { } catch (IOException e) { return null; } - } - + }*/ } diff --git a/io-vector/src/test/java/org/xbib/graphics/io/visual/TestBrowser.java b/io-vector/src/test/java/org/xbib/graphics/io/visual/TestBrowser.java index 0a8ab8b..be6b3c2 100644 --- a/io-vector/src/test/java/org/xbib/graphics/io/visual/TestBrowser.java +++ b/io-vector/src/test/java/org/xbib/graphics/io/visual/TestBrowser.java @@ -111,16 +111,16 @@ public class TestBrowser extends JFrame { ImageDisplayPanel imageDisplayPanel; switch (imageComparisonPanel.getImageFormat()) { case EPS: - imageDisplayPanel = new ImageDisplayPanel(null, test.getEPS()); - imageComparisonPanel.setRightComponent(imageDisplayPanel); + //imageDisplayPanel = new ImageDisplayPanel(null, test.getEPS()); + //imageComparisonPanel.setRightComponent(imageDisplayPanel); break; case PDF: - imageDisplayPanel = new ImageDisplayPanel(null, test.getPDF()); - imageComparisonPanel.setRightComponent(imageDisplayPanel); + //imageDisplayPanel = new ImageDisplayPanel(null, test.getPDF()); + //imageComparisonPanel.setRightComponent(imageDisplayPanel); break; case SVG: - imageDisplayPanel = new ImageDisplayPanel(null, test.getSVG()); - imageComparisonPanel.setRightComponent(imageDisplayPanel); + //imageDisplayPanel = new ImageDisplayPanel(null, test.getSVG()); + //imageComparisonPanel.setRightComponent(imageDisplayPanel); break; default: throw new IllegalArgumentException("Unknown image format: " + imageComparisonPanel.getImageFormat()); diff --git a/layout-pdfbox/src/main/java/module-info.java b/layout-pdfbox/src/main/java/module-info.java new file mode 100644 index 0000000..be99e53 --- /dev/null +++ b/layout-pdfbox/src/main/java/module-info.java @@ -0,0 +1,10 @@ +module org.xbib.graphics.layout.pdfbox { + exports org.xbib.graphics.layout.pdfbox.elements; + exports org.xbib.graphics.layout.pdfbox.elements.render; + exports org.xbib.graphics.layout.pdfbox.shape; + exports org.xbib.graphics.layout.pdfbox.text; + exports org.xbib.graphics.layout.pdfbox.text.annotations; + exports org.xbib.graphics.layout.pdfbox.util; + requires transitive org.apache.pdfbox; + requires transitive java.desktop; +} diff --git a/layout-pdfbox/src/main/java/org/xbib/graphics/layout/pdfbox/text/ControlCharacters.java b/layout-pdfbox/src/main/java/org/xbib/graphics/layout/pdfbox/text/ControlCharacters.java index bc68dbe..8348756 100644 --- a/layout-pdfbox/src/main/java/org/xbib/graphics/layout/pdfbox/text/ControlCharacters.java +++ b/layout-pdfbox/src/main/java/org/xbib/graphics/layout/pdfbox/text/ControlCharacters.java @@ -239,8 +239,7 @@ public class ControlCharacters { } - private static class MetricsControlCharacterFactory implements - ControlCharacterFactory { + public static class MetricsControlCharacterFactory implements ControlCharacterFactory { private final static Pattern PATTERN = Pattern .compile("(? 0) { offset += consumed; pendinglen -= consumed; - assert pendinglen >= 0; } } else { // nothing to fed ? premature ending ? @@ -118,18 +123,14 @@ public class BufferedStreamFeeder implements Closeable { } remain -= n; } - assert remain == 0; return nbytes; } /** * If there are not pending bytes to be consumed, tries to fill the buffer * reading bytes from the stream. - *

* If EOF is reached, sets eof=TRUE and calls close() - *

* Find in pendinglen the amounts of bytes read. - *

* If IOException, throws a PngjInputException */ protected void refillBufferIfAppropiate() { diff --git a/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/ChunkReader.java b/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/ChunkReader.java index 29c790c..81b56c1 100644 --- a/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/ChunkReader.java +++ b/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/ChunkReader.java @@ -1,6 +1,5 @@ package org.xbib.graphics.imageio.plugins.png.pngj; -import java.util.logging.Logger; import org.xbib.graphics.imageio.plugins.png.pngj.chunks.ChunkRaw; /** @@ -19,7 +18,6 @@ import org.xbib.graphics.imageio.plugins.png.pngj.chunks.ChunkRaw; * (usually is) long lived. */ public abstract class ChunkReader implements IBytesConsumer { - private static final Logger LOGGER = Logger.getLogger(ChunkReader.class.getName()); /** * see {@link ChunkReaderMode} @@ -130,8 +128,6 @@ public abstract class ChunkReader implements IBytesConsumer { } } else if (mode == ChunkReaderMode.PROCESS) { processData(read, buf, off, bytesForData); - } else { - // mode == ChunkReaderMode.SKIP; nothing to do } read += bytesForData; off += bytesForData; @@ -155,7 +151,6 @@ public abstract class ChunkReader implements IBytesConsumer { } chunkRaw.checkCrc(errorBehav == ErrorBehaviour.STRICT); } - LOGGER.fine("Chunk done"); chunkDone(); } } @@ -164,7 +159,7 @@ public abstract class ChunkReader implements IBytesConsumer { } /** - * Chunks has been read + * Chunks has been read. * * @return true if we have read all chunk, including trailing CRC */ @@ -177,7 +172,6 @@ public abstract class ChunkReader implements IBytesConsumer { * starting reading. * * @param crcCheck - * @see also #setErrorBehav(ErrorBehaviour) */ public void setCrcCheck(boolean crcCheck) { if (read != 0 && crcCheck && !this.crcCheck) { diff --git a/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/ChunkSeqReader.java b/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/ChunkSeqReader.java index 939ca89..426ce3e 100644 --- a/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/ChunkSeqReader.java +++ b/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/ChunkSeqReader.java @@ -6,8 +6,6 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.Arrays; -import java.util.logging.Level; -import java.util.logging.Logger; import org.xbib.graphics.imageio.plugins.png.pngj.ChunkReader.ChunkReaderMode; import org.xbib.graphics.imageio.plugins.png.pngj.chunks.ChunkHelper; @@ -19,7 +17,6 @@ import org.xbib.graphics.imageio.plugins.png.pngj.chunks.ChunkHelper; * idat deflate */ public abstract class ChunkSeqReader implements IBytesConsumer, Closeable { - private static final Logger LOGGER = Logger.getLogger(ChunkSeqReader.class.getName()); private final byte[] expectedSignature; private final int signatureLength; @@ -62,18 +59,9 @@ public abstract class ChunkSeqReader implements IBytesConsumer, Closeable { /** * Consumes (in general, partially) a number of bytes. A single call never * involves more than one chunk. - *

* When the signature is read, it calls checkSignature() - *

* When the start of a chunk is detected, it calls * {@link #startNewChunk(int, String, long)} - *

- * When data from a chunk is being read, it delegates to - * {@link ChunkReader#feedBytes(byte[], int, int)} - *

- * The caller might want to call this method more than once in succesion - *

- * This should rarely be overriden * * @param buffer * @param offset Offset in buffer @@ -155,7 +143,6 @@ public abstract class ChunkSeqReader implements IBytesConsumer, Closeable { len -= n; off += n; } - assert len == 0; return 0; } @@ -179,9 +166,6 @@ public abstract class ChunkSeqReader implements IBytesConsumer, Closeable { * {@link #createChunkReaderForNewChunk(String, int, long, boolean)} */ protected void startNewChunk(int len, String id, long offset) { - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.fine("New chunk: " + id + " " + len + " off:" + offset); - } // check id an length if (id.length() != 4 || !ChunkHelper.CHUNK_ID_PAT.matcher(id).matches()) { throw new PngjInputException("Bad chunk id: " + id); @@ -272,8 +256,6 @@ public abstract class ChunkSeqReader implements IBytesConsumer, Closeable { String msg = "Bad first chunk: " + chunkR.getChunkRaw().id + " expected: " + firstChunkId(); if (errorBehaviour.c < ErrorBehaviour.SUPER_LENIENT.c) { throw new PngjInputException(msg); - } else { - LOGGER.warning(msg); } } } @@ -444,21 +426,17 @@ public abstract class ChunkSeqReader implements IBytesConsumer, Closeable { /** * Reads all content from an input stream. Helper method, only for callback * mode - *

- * Caller should call isDone() to assert all expected chunks have been read - *

+ * Caller should call isDone() to assure all expected chunks have been read * Warning: this does not close this object, unless ended * - * @param is + * @param is input stream * @param closeStream Closes the input stream when done (or if error) */ public void feedFromInputStream(InputStream is, boolean closeStream) { BufferedStreamFeeder sf = new BufferedStreamFeeder(is); - sf.setCloseStream(closeStream); - try { + try (sf) { + sf.setCloseStream(closeStream); sf.feedAll(this); - } finally { - sf.close(); } } diff --git a/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/IdatSet.java b/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/IdatSet.java index 92d7973..0296df6 100644 --- a/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/IdatSet.java +++ b/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/IdatSet.java @@ -1,19 +1,16 @@ package org.xbib.graphics.imageio.plugins.png.pngj; import java.util.Arrays; -import java.util.logging.Logger; import java.util.zip.Checksum; import java.util.zip.Inflater; /** * This object process the concatenation of IDAT chunks. - *

* It extends {@link DeflatedChunksSet}, adding the intelligence to unfilter * rows, and to understand row lenghts in terms of ImageInfo and (eventually) * Deinterlacer */ public class IdatSet extends DeflatedChunksSet { - private static final Logger LOGGER = Logger.getLogger(IdatSet.class.getName()); protected byte[] rowUnfiltered; protected byte[] rowUnfilteredPrev; @@ -36,11 +33,6 @@ public class IdatSet extends DeflatedChunksSet { /** * Special constructor with preallocated buffer. - *

- *

- * Same as {@link #IdatSet(String, ImageInfo, Deinterlacer)}, but you can - * pass a Inflater (will be reset internally), and a buffer (will be used - * only if size is enough) */ public IdatSet(String id, boolean callbackMode, ImageInfo iminfo, Deinterlacer deinterlacer, Inflater inf, byte[] buffer) { @@ -49,7 +41,6 @@ public class IdatSet extends DeflatedChunksSet { this.imgInfo = iminfo; this.deinterlacer = deinterlacer; this.rowinfo = new RowInfo(iminfo, deinterlacer); - LOGGER.fine("Creating IDAT set "); } /** diff --git a/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/PngReader.java b/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/PngReader.java index 0944277..f9e052e 100644 --- a/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/PngReader.java +++ b/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/PngReader.java @@ -3,7 +3,6 @@ package org.xbib.graphics.imageio.plugins.png.pngj; import java.io.Closeable; import java.io.File; import java.io.InputStream; -import java.util.logging.Logger; import java.util.zip.Adler32; import java.util.zip.CRC32; import org.xbib.graphics.imageio.plugins.png.pngj.chunks.ChunkLoadBehaviour; @@ -15,41 +14,35 @@ import org.xbib.graphics.imageio.plugins.png.pngj.chunks.PngMetadata; /** * Reads a PNG image (pixels and/or metadata) from a file or stream. - *

* Each row is read as an {@link ImageLineInt} object (one int per sample), but * this can be changed by setting a different ImageLineFactory - *

* Internally, this wraps a {@link ChunkSeqReaderPng} with a * {@link BufferedStreamFeeder} - *

- * The reading sequence is as follows:
+ * The reading sequence is as follows: * 1. At construction time, the header and IHDR chunk are read (basic image - * info)
+ * info) * 2. Afterwards you can set some additional global options. Eg. - * {@link #setCrcCheckDisabled()}.
+ * {@link #setCrcCheckDisabled()}. * 3. Optional: If you call getMetadata() or getChunksLisk() before start * reading the rows, all the chunks before IDAT are then loaded and available - *
* 4a. The rows are read in order by calling {@link #readRow()}. You can also * call {@link #readRow(int)} to skip rows -but you can't go backwards, at least * not with this implementation. This method returns a {@link IImageLine} object * which can be casted to the concrete class. This class returns by default a - * {@link ImageLineInt}, but this can be changed.
+ * {@link ImageLineInt}, but this can be changed. * 4b. Alternatively, you can read all rows, or a subset, in a single call: * {@link #readRows()}, {@link #readRows(int, int, int)} ,etc. In general this * consumes more memory, but for interlaced images this is equally efficient, - * and more so if reading a small subset of rows.
+ * and more so if reading a small subset of rows. * 5. Reading of the last row automatically loads the trailing chunks, and ends - * the reader.
+ * the reader. * 6. end() also loads the trailing chunks, if not done, and finishes cleanly * the reading and closes the stream. - *

* See also {@link PngReaderInt} (esentially the same as this, and slightly * preferred) and {@link PngReaderByte} (uses byte instead of int to store the * samples). */ public class PngReader implements Closeable { - private static final Logger LOGGER = Logger.getLogger(PngReader.class.getName()); // some performance/defensive limits /** @@ -551,17 +544,17 @@ public class PngReader implements Closeable { /** * Releases resources, and closes stream if corresponds. Idempotent, secure, * no exceptions. - *

* This can be also called for abort. It is recommended to call this in case - * of exceptions + * of exceptions. */ + @Override public void close() { try { if (chunkseq != null) { chunkseq.close(); } } catch (Exception e) { - LOGGER.warning("error closing chunk sequence:" + e.getMessage()); + // ignore } if (streamFeeder != null) { streamFeeder.close(); diff --git a/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/PngWriter.java b/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/PngWriter.java index 42ac918..8da92d8 100644 --- a/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/PngWriter.java +++ b/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/PngWriter.java @@ -4,7 +4,6 @@ import java.io.Closeable; import java.io.File; import java.io.OutputStream; import java.util.List; -import java.util.logging.Logger; import org.xbib.graphics.imageio.plugins.png.pngj.chunks.ChunkCopyBehaviour; import org.xbib.graphics.imageio.plugins.png.pngj.chunks.ChunkPredicate; import org.xbib.graphics.imageio.plugins.png.pngj.chunks.ChunksList; @@ -59,8 +58,6 @@ public class PngWriter implements Closeable { protected StringBuilder debuginfo = new StringBuilder(); - private static final Logger LOGGER = Logger.getLogger(PngWriter.class.getName()); - /** * Opens a file for writing. *

@@ -196,10 +193,9 @@ public class PngWriter implements Closeable { /** * Queues an ancillary chunk for writing. - *

* If a "equivalent" chunk is already queued (see * {@link ChunkHelper#equivalent(PngChunk, PngChunk)), this overwrites it. - *

The chunk will be written as late as possible, unless the priority is + * The chunk will be written as late as possible, unless the priority is * set. * * @param chunk @@ -253,9 +249,6 @@ public class PngWriter implements Closeable { * @see #copyChunksFrom(ChunksList, int) for more info */ public void copyChunksFrom(ChunksList chunks, ChunkPredicate predicate) { - if (copyFromList != null && chunks != null) { - LOGGER.warning("copyChunksFrom should only be called once"); - } if (predicate == null) { throw new PngjOutputException("copyChunksFrom requires a predicate"); } @@ -318,7 +311,7 @@ public class PngWriter implements Closeable { try { os.close(); } catch (Exception e) { - LOGGER.warning("Error closing writer " + e.toString()); + // ignore } } } diff --git a/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/chunks/ChunkRaw.java b/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/chunks/ChunkRaw.java index a94464d..cad7394 100644 --- a/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/chunks/ChunkRaw.java +++ b/png/src/main/java/org/xbib/graphics/imageio/plugins/png/pngj/chunks/ChunkRaw.java @@ -2,7 +2,6 @@ package org.xbib.graphics.imageio.plugins.png.pngj.chunks; import java.io.ByteArrayInputStream; import java.io.OutputStream; -import java.util.logging.Logger; import java.util.zip.CRC32; import org.xbib.graphics.imageio.plugins.png.pngj.PngHelperInternal; import org.xbib.graphics.imageio.plugins.png.pngj.PngjBadCrcException; @@ -16,7 +15,6 @@ import org.xbib.graphics.imageio.plugins.png.pngj.PngjOutputException; * See http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html */ public class ChunkRaw { - private static final Logger LOGGER = Logger.getLogger(ChunkRaw.class.getName()); /** * The length counts only the data field, not itself, the chunk type code, * or the CRC. Zero is a valid length. Although encoders and decoders should @@ -124,8 +122,6 @@ public class ChunkRaw { crcComputed); if (throwExcep) { throw new PngjBadCrcException(msg); - } else { - LOGGER.warning(msg); } } } diff --git a/png/src/main/resources/META-INF/services/javax.imageio.spi.ImageWriterSpi b/png/src/main/resources/META-INF/services/javax.imageio.spi.ImageWriterSpi index 883ad6e..e69de29 100644 --- a/png/src/main/resources/META-INF/services/javax.imageio.spi.ImageWriterSpi +++ b/png/src/main/resources/META-INF/services/javax.imageio.spi.ImageWriterSpi @@ -1 +0,0 @@ -o \ No newline at end of file diff --git a/png/src/test/java/org/xbib/graphics/imageio/plugins/png/BufferedImageTypesTest.java b/png/src/test/java/org/xbib/graphics/imageio/plugins/png/BufferedImageTypesTest.java index 3d4c062..8c71aa9 100644 --- a/png/src/test/java/org/xbib/graphics/imageio/plugins/png/BufferedImageTypesTest.java +++ b/png/src/test/java/org/xbib/graphics/imageio/plugins/png/BufferedImageTypesTest.java @@ -1,6 +1,8 @@ package org.xbib.graphics.imageio.plugins.png; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestTemplate; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.runners.Parameterized; import org.xbib.graphics.imageio.plugins.png.pngj.FilterType; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; @@ -8,36 +10,31 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.Collection; +import java.util.Arrays; import java.util.List; import javax.imageio.ImageIO; +@ExtendWith(ParameterizedExtension.class) public class BufferedImageTypesTest { static final int WIDTH = 1024; static final int HEIGTH = 1024; - static final int STROKE_WIDTH = 30; + //static final int STROKE_WIDTH = 30; - static final int LINES = 200; + //static final int LINES = 200; - BufferedImage image; + private final BufferedImage image; - String name; - - public BufferedImageTypesTest(String name, int imageType) { - this.name = name; - image = new BufferedImage(WIDTH, HEIGTH, imageType); - new SampleImagePainter().paintImage(image); - } + private final String name; //@Parameters(name = "{0}") - public static Collection parameters() throws Exception { - String[] types = new String[]{"4BYTE_ABGR", "INT_ARGB", "3BYTE_BGR", "INT_BGR", - "INT_RGB", "BYTE_INDEXED", "BYTE_GRAY"}; - List parameters = new ArrayList(); - for (String type : types) { + @Parameterized.Parameters + public static List data() throws Exception { + List parameters = new ArrayList<>(); + for (String type : Arrays.asList("4BYTE_ABGR", "INT_ARGB", "3BYTE_BGR", "INT_BGR", + "INT_RGB", "BYTE_INDEXED", "BYTE_GRAY")) { Field field = BufferedImage.class.getDeclaredField("TYPE_" + type); int imageType = (Integer) field.get(null); parameters.add(new Object[]{type.toLowerCase(), imageType}); @@ -45,14 +42,19 @@ public class BufferedImageTypesTest { return parameters; } - @Test + public BufferedImageTypesTest(String name, int imageType) { + this.name = name; + this.image = new BufferedImage(WIDTH, HEIGTH, imageType); + new SampleImagePainter().paintImage(image); + } + + @TestTemplate public void compareImage() throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); float quality = 4f / 9 - 1; new PNGWriter().writePNG(image, bos, -quality, FilterType.FILTER_NONE); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); BufferedImage readBack = ImageIO.read(bis); - boolean success = false; try { ImageAssert.assertImagesEqual(image, readBack); diff --git a/png/src/test/java/org/xbib/graphics/imageio/plugins/png/CustomByteIndexImageTypesTest.java b/png/src/test/java/org/xbib/graphics/imageio/plugins/png/CustomByteIndexImageTypesTest.java index 3d8ffdd..1463ae8 100644 --- a/png/src/test/java/org/xbib/graphics/imageio/plugins/png/CustomByteIndexImageTypesTest.java +++ b/png/src/test/java/org/xbib/graphics/imageio/plugins/png/CustomByteIndexImageTypesTest.java @@ -1,6 +1,8 @@ package org.xbib.graphics.imageio.plugins.png; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestTemplate; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.runners.Parameterized; import org.xbib.graphics.imageio.plugins.png.pngj.FilterType; import java.awt.Color; import java.awt.Graphics2D; @@ -16,10 +18,10 @@ import java.awt.image.WritableRaster; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import javax.imageio.ImageIO; +@ExtendWith(ParameterizedExtension.class) public class CustomByteIndexImageTypesTest { private final int ncolors; @@ -32,21 +34,21 @@ public class CustomByteIndexImageTypesTest { } //@Parameters(name = "colors{0}/size{1}") - public static Collection parameters() { - List result = new ArrayList(); + @Parameterized.Parameters + public static List parameters() { + List result = new ArrayList<>(); for (int ncolors : new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 255, 256}) { for (int size = 1; size <= 8; size++) { - result.add(new Object[]{ncolors, size}); + result.add(new Object[] { ncolors, size} ); } } - return result; } - @Test + @TestTemplate public void testCustomIndexedImage() throws Exception { byte[] colors = new byte[ncolors]; for (int i = 0; i < ncolors; i++) { @@ -62,7 +64,6 @@ public class CustomByteIndexImageTypesTest { nbits = (int) Math.pow(2, nextPower); } } - IndexColorModel icm = new IndexColorModel(nbits, ncolors, colors, colors, colors); SampleModel sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, size, size, nbits); int pixelsPerByte = 8 / nbits; @@ -77,11 +78,9 @@ public class CustomByteIndexImageTypesTest { graphics.setColor(Color.WHITE); graphics.fillRect(16, 0, 16, 32); graphics.dispose(); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); float quality = 5f / 9 - 1; new PNGWriter().writePNG(bi, bos, -quality, FilterType.FILTER_NONE); - BufferedImage read = ImageIO.read(new ByteArrayInputStream(bos.toByteArray())); ImageAssert.assertImagesEqual(bi, read); } diff --git a/png/src/test/java/org/xbib/graphics/imageio/plugins/png/CustomUShortImageTypesTest.java b/png/src/test/java/org/xbib/graphics/imageio/plugins/png/CustomUShortImageTypesTest.java index b101298..47edc65 100644 --- a/png/src/test/java/org/xbib/graphics/imageio/plugins/png/CustomUShortImageTypesTest.java +++ b/png/src/test/java/org/xbib/graphics/imageio/plugins/png/CustomUShortImageTypesTest.java @@ -1,6 +1,8 @@ package org.xbib.graphics.imageio.plugins.png; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestTemplate; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.runners.Parameterized; import org.xbib.graphics.imageio.plugins.png.pngj.FilterType; import java.awt.Color; import java.awt.Graphics2D; @@ -14,6 +16,7 @@ import java.util.List; import javax.imageio.ImageIO; import javax.imageio.ImageTypeSpecifier; +@ExtendWith(ParameterizedExtension.class) public class CustomUShortImageTypesTest { private final int nbits; @@ -25,18 +28,18 @@ public class CustomUShortImageTypesTest { } //@Parameters(name = "bits{0}/size{1}") + @Parameterized.Parameters public static Collection parameters() { - List result = new ArrayList(); + List result = new ArrayList<>(); for (int nbits : new int[]{1, 2, 4, 8, 16}) { for (int size = 1; size <= 32; size++) { result.add(new Object[]{nbits, size}); } } - return result; } - @Test + @TestTemplate public void testCustomUShortImage() throws Exception { BufferedImage bi = ImageTypeSpecifier.createGrayscale(nbits, DataBuffer.TYPE_USHORT, false) .createBufferedImage(size, size); @@ -46,11 +49,9 @@ public class CustomUShortImageTypesTest { graphics.setColor(Color.WHITE); graphics.fillRect(16, 0, 16, 32); graphics.dispose(); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); float quality = 5f / 9 - 1; new PNGWriter().writePNG(bi, bos, -quality, FilterType.FILTER_NONE); - BufferedImage read = ImageIO.read(new ByteArrayInputStream(bos.toByteArray())); ImageAssert.assertImagesEqual(bi, read); } diff --git a/png/src/test/java/org/xbib/graphics/imageio/plugins/png/ImageAssert.java b/png/src/test/java/org/xbib/graphics/imageio/plugins/png/ImageAssert.java index fd38bb8..3b72016 100644 --- a/png/src/test/java/org/xbib/graphics/imageio/plugins/png/ImageAssert.java +++ b/png/src/test/java/org/xbib/graphics/imageio/plugins/png/ImageAssert.java @@ -22,7 +22,6 @@ public class ImageAssert { // structure back // assertEquals(original.getSampleModel(), image.getSampleModel()); // assertEquals(original.getColorModel(), image.getColorModel()); - for (int x = 0; x < original.getWidth(); x++) { for (int y = 0; y < original.getHeight(); y++) { int rgbOriginal = original.getRGB(x, y); @@ -54,11 +53,8 @@ public class ImageAssert { } }); + @SuppressWarnings("serial") Panel p = new Panel() { - - /** serialVersionUID field */ - private static final long serialVersionUID = 1L; - { setPreferredSize(new Dimension(image.getWidth(), image.getHeight())); } diff --git a/png/src/test/java/org/xbib/graphics/imageio/plugins/png/PNGWriterTest.java b/png/src/test/java/org/xbib/graphics/imageio/plugins/png/PNGWriterTest.java index da02933..d5f6017 100644 --- a/png/src/test/java/org/xbib/graphics/imageio/plugins/png/PNGWriterTest.java +++ b/png/src/test/java/org/xbib/graphics/imageio/plugins/png/PNGWriterTest.java @@ -9,7 +9,7 @@ import org.xbib.graphics.imageio.plugins.png.pngj.chunks.PngMetadata; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; -import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; import java.util.Map; @@ -22,8 +22,8 @@ public class PNGWriterTest { PNGWriter writer = new PNGWriter(); OutputStream out = null; try { - // read test image - BufferedImage read = ImageIO.read(new File("sample.jpeg")); + InputStream inputStream = getClass().getResourceAsStream("sample.jpeg"); + BufferedImage read = ImageIO.read(inputStream); File pngOut = new File("build/test.png"); out = new FileOutputStream(pngOut); writer.writePNG(read, out, 1, FilterType.FILTER_NONE); @@ -46,7 +46,8 @@ public class PNGWriterTest { final String software = "ImageIO-Ext"; final String author = "Me"; try { - BufferedImage read = ImageIO.read(new File("sample.jpeg")); + InputStream inputStream = getClass().getResourceAsStream("sample.jpeg"); + BufferedImage read = ImageIO.read(inputStream); pngOut = new File("build/test.png"); out = new FileOutputStream(pngOut); Map textMetadata = new HashMap(); diff --git a/png/src/test/java/org/xbib/graphics/imageio/plugins/png/ParameterizedExtension.java b/png/src/test/java/org/xbib/graphics/imageio/plugins/png/ParameterizedExtension.java new file mode 100644 index 0000000..db79c13 --- /dev/null +++ b/png/src/test/java/org/xbib/graphics/imageio/plugins/png/ParameterizedExtension.java @@ -0,0 +1,226 @@ +package org.xbib.graphics.imageio.plugins.png; + +import static java.util.Collections.singletonList; +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.toList; +import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; +import org.junit.jupiter.api.extension.TestInstancePostProcessor; +import org.junit.jupiter.api.extension.TestTemplateInvocationContext; +import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider; +import org.junit.platform.commons.util.CollectionUtils; +import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.runners.Parameterized; +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +public class ParameterizedExtension implements TestTemplateInvocationContextProvider { + + private final static ExtensionContext.Namespace PARAMETERS = ExtensionContext.Namespace.create( + ParameterizedExtension.class); + + /** + * Indicate whether we can provide parameterized support. + * This requires the testClass to either have a static {@code @Parameters} method + * and correct {@code @Parameter} and their corresponding values + * or to have a constructor that could be injected. + */ + public boolean supportsTestTemplate(ExtensionContext context) { + return hasParametersMethod(context) && validInjectionMix(context); + } + + private static boolean validInjectionMix(ExtensionContext context) { + List fields = parametersFields(context); + boolean hasParameterFields = !fields.isEmpty(); + boolean hasCorrectParameterFields = areParametersFormedCorrectly(fields); + boolean hasArgsConstructor = hasArgsConstructor(context); + if (hasArgsConstructor) { + return !hasParameterFields; + } + else { + return !hasParameterFields || hasCorrectParameterFields; + } + } + + @Override + public Stream provideTestTemplateInvocationContexts(ExtensionContext context) { + return context.getParent().flatMap(ParameterizedExtension::parameters).map( + o -> testTemplateContextsFromParameters(o, context)).orElse(Stream.empty()); + } + + private static boolean areParametersFormedCorrectly(List fields) { + List parameterValues = parameterIndexes(fields); + List duplicateIndexes = duplicatedIndexes(parameterValues); + boolean hasAllIndexes = indexRangeComplete(parameterValues); + return hasAllIndexes && duplicateIndexes.isEmpty(); + } + + private static List parameterIndexes(List fields) { + return fields.stream() + .map(f -> f.getAnnotation(Parameterized.Parameter.class)) + .map(Parameterized.Parameter::value) + .collect(toList()); + } + + private static List duplicatedIndexes(List parameterValues) { + return parameterValues.stream().collect(groupingBy(identity())).entrySet().stream() + .filter(e -> e.getValue().size() > 1) + .map(Map.Entry::getKey) + .collect(toList()); + } + + private static Boolean indexRangeComplete(List parameterValues) { + return parameterValues.stream() + .max(Integer::compareTo) + .map(i -> parameterValues.containsAll(IntStream.range(0, i).boxed().collect(toList()))) + .orElse(false); + } + + private static Optional> parameters(ExtensionContext context) { + return context.getStore(PARAMETERS).getOrComputeIfAbsent("parameterMethod", + k -> new ParameterWrapper(callParameters(context)), ParameterWrapper.class).getValue(); + + } + + private static Optional> callParameters(ExtensionContext context) { + return findParametersMethod(context) + .map(m -> ReflectionUtils.invokeMethod(m, null)) + .map(ParameterizedExtension::convertParametersMethodReturnType); + } + + private static boolean hasParametersMethod(ExtensionContext context) { + return findParametersMethod(context).isPresent(); + } + + private static Optional findParametersMethod(ExtensionContext extensionContext) { + return extensionContext.getTestClass() + .flatMap(ParameterizedExtension::ensureSingleParametersMethod) + .filter(ReflectionUtils::isPublic); + } + + private static Optional ensureSingleParametersMethod(Class testClass) { + return ReflectionUtils.findMethods(testClass, + m -> m.isAnnotationPresent(Parameterized.Parameters.class)).stream().findFirst(); + } + + private static Stream testTemplateContextsFromParameters(Collection o, + ExtensionContext context) { + List fields = parametersFields(context); + boolean hasParameterFields = !fields.isEmpty(); + boolean hasCorrectParameterFields = areParametersFormedCorrectly(fields); + if (!hasParameterFields) { + return o.stream().map(ParameterizedExtension::parameterResolver); + } + else if (hasCorrectParameterFields) { + return o.stream().map(ParameterizedExtension::contextFactory); + } + return Stream.empty(); + } + + private static TestTemplateInvocationContext parameterResolver(Object[] objects) { + List parameterResolvers = singletonList(new ParameterResolver() { + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + final Executable declaringExecutable = parameterContext.getDeclaringExecutable(); + return declaringExecutable instanceof Constructor + && declaringExecutable.getParameterCount() == objects.length; + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return objects[parameterContext.getIndex()]; + } + }); + + return templateWithExtensions(parameterResolvers); + } + + private static TestTemplateInvocationContext contextFactory(Object[] parameters) { + return templateWithExtensions(singletonList(new InjectionExtension(parameters))); + } + + private static class InjectionExtension implements TestInstancePostProcessor { + + private final Object[] parameters; + + public InjectionExtension(Object[] parameters) { + this.parameters = parameters; + } + + @Override + public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception { + List parameters = parametersFields(context); + if (!parameters.isEmpty() && parameters.size() != this.parameters.length) { + throw unMatchedAmountOfParametersException(); + } + for (Field param : parameters) { + Parameterized.Parameter annotation = param.getAnnotation(Parameterized.Parameter.class); + int paramIndex = annotation.value(); + param.set(testInstance, this.parameters[paramIndex]); + } + } + } + + private static TestTemplateInvocationContext templateWithExtensions(List extensions) { + return new TestTemplateInvocationContext() { + @Override + public List getAdditionalExtensions() { + return extensions; + } + }; + } + + private static boolean hasArgsConstructor(ExtensionContext context) { + return context.getTestClass() + .map(ReflectionUtils::getDeclaredConstructor) + .filter(c -> c.getParameterCount() > 0) + .isPresent(); + } + + private static List parametersFields(ExtensionContext context) { + Stream fieldStream = context.getTestClass() + .map(Class::getDeclaredFields).stream().flatMap(Stream::of); + return fieldStream.filter(f -> f.isAnnotationPresent(Parameterized.Parameter.class)).filter( + ReflectionUtils::isPublic).collect(toList()); + } + + private static ParameterResolutionException unMatchedAmountOfParametersException() { + return new ParameterResolutionException("The amount of parametersFields in the constructor doesn't match those in the provided parametersFields"); + } + + private static Collection convertParametersMethodReturnType(Object obj) { + return CollectionUtils.toStream(obj).map(o -> { + if (o instanceof Object[]) { + return (Object[]) o; + } + return new Object[] { o }; + }).collect(toList()); + } + + private static class ParameterWrapper { + + private final Optional> value; + + public ParameterWrapper(Optional> value) { + this.value = value; + } + + public Optional> getValue() { + return value; + } + } +} diff --git a/png/src/test/java/org/xbib/graphics/imageio/plugins/png/PngSuiteImagesTest.java b/png/src/test/java/org/xbib/graphics/imageio/plugins/png/PngSuiteImagesTest.java index 06bcbb4..77a9c80 100644 --- a/png/src/test/java/org/xbib/graphics/imageio/plugins/png/PngSuiteImagesTest.java +++ b/png/src/test/java/org/xbib/graphics/imageio/plugins/png/PngSuiteImagesTest.java @@ -1,7 +1,9 @@ package org.xbib.graphics.imageio.plugins.png; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestTemplate; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.runners.Parameterized; import org.xbib.graphics.imageio.plugins.png.pngj.FilterType; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; @@ -12,10 +14,10 @@ import java.io.FilenameFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.List; import javax.imageio.ImageIO; +@ExtendWith(ParameterizedExtension.class) public class PngSuiteImagesTest { private final File sourceFile; @@ -25,11 +27,11 @@ public class PngSuiteImagesTest { } //@Parameters(name = "{0}") - public static Collection parameters() { - List result = new ArrayList(); + @Parameterized.Parameters + public static List parameters() { + List result = new ArrayList<>(); File source = new File("./src/test/resources/pngsuite"); File[] files = source.listFiles(new FilenameFilter() { - @Override public boolean accept(File dir, String name) { return name.endsWith(".png"); @@ -39,17 +41,16 @@ public class PngSuiteImagesTest { for (File file : files) { result.add(new Object[]{file}); } - return result; } - @Test + @TestTemplate public void testRoundTripFilterNone() throws Exception { BufferedImage input = ImageIO.read(sourceFile); roundTripPNGJ(input); } - @Test + @TestTemplate public void testRoundTripTiledImage() throws Exception { BufferedImage input = ImageIO.read(sourceFile); roundTripPNGJ(input); @@ -70,15 +71,8 @@ public class PngSuiteImagesTest { private void writeToFile(File file, byte[] bytes) throws IOException { File parent = file.getParentFile(); parent.mkdirs(); - FileOutputStream fos = null; - try { - fos = new FileOutputStream(file); + try (FileOutputStream fos = new FileOutputStream(file)) { fos.write(bytes); - } finally { - if (fos != null) { - fos.close(); - } } } - } diff --git a/png/src/test/resources/org/xbib/graphics/imageio/plugins/png/sample.jpeg b/png/src/test/resources/org/xbib/graphics/imageio/plugins/png/sample.jpeg new file mode 100644 index 0000000..0cfe84e Binary files /dev/null and b/png/src/test/resources/org/xbib/graphics/imageio/plugins/png/sample.jpeg differ diff --git a/png/src/test/resources/pngsuite/basn0g01.png b/png/src/test/resources/pngsuite/basn0g01.png new file mode 100644 index 0000000..e31e1c7 Binary files /dev/null and b/png/src/test/resources/pngsuite/basn0g01.png differ diff --git a/png/src/test/resources/pngsuite/basn0g02.png b/png/src/test/resources/pngsuite/basn0g02.png new file mode 100644 index 0000000..68809dd Binary files /dev/null and b/png/src/test/resources/pngsuite/basn0g02.png differ diff --git a/png/src/test/resources/pngsuite/basn0g04.png b/png/src/test/resources/pngsuite/basn0g04.png new file mode 100644 index 0000000..6fa089c Binary files /dev/null and b/png/src/test/resources/pngsuite/basn0g04.png differ diff --git a/png/src/test/resources/pngsuite/basn0g08.png b/png/src/test/resources/pngsuite/basn0g08.png new file mode 100644 index 0000000..bf522ee Binary files /dev/null and b/png/src/test/resources/pngsuite/basn0g08.png differ diff --git a/png/src/test/resources/pngsuite/basn0g16.png b/png/src/test/resources/pngsuite/basn0g16.png new file mode 100644 index 0000000..318ebca Binary files /dev/null and b/png/src/test/resources/pngsuite/basn0g16.png differ diff --git a/png/src/test/resources/pngsuite/basn2c08.png b/png/src/test/resources/pngsuite/basn2c08.png new file mode 100644 index 0000000..21d2f91 Binary files /dev/null and b/png/src/test/resources/pngsuite/basn2c08.png differ diff --git a/png/src/test/resources/pngsuite/basn2c16.png b/png/src/test/resources/pngsuite/basn2c16.png new file mode 100644 index 0000000..1bd4a4d Binary files /dev/null and b/png/src/test/resources/pngsuite/basn2c16.png differ diff --git a/png/src/test/resources/pngsuite/basn3p01.png b/png/src/test/resources/pngsuite/basn3p01.png new file mode 100644 index 0000000..a21db59 Binary files /dev/null and b/png/src/test/resources/pngsuite/basn3p01.png differ diff --git a/png/src/test/resources/pngsuite/basn3p02.png b/png/src/test/resources/pngsuite/basn3p02.png new file mode 100644 index 0000000..1d0ab61 Binary files /dev/null and b/png/src/test/resources/pngsuite/basn3p02.png differ diff --git a/png/src/test/resources/pngsuite/basn3p04.png b/png/src/test/resources/pngsuite/basn3p04.png new file mode 100644 index 0000000..6dc6eac Binary files /dev/null and b/png/src/test/resources/pngsuite/basn3p04.png differ diff --git a/png/src/test/resources/pngsuite/basn3p08.png b/png/src/test/resources/pngsuite/basn3p08.png new file mode 100644 index 0000000..0e07f48 Binary files /dev/null and b/png/src/test/resources/pngsuite/basn3p08.png differ diff --git a/png/src/test/resources/pngsuite/basn4a08.png b/png/src/test/resources/pngsuite/basn4a08.png new file mode 100644 index 0000000..3bb0dd0 Binary files /dev/null and b/png/src/test/resources/pngsuite/basn4a08.png differ diff --git a/png/src/test/resources/pngsuite/basn4a16.png b/png/src/test/resources/pngsuite/basn4a16.png new file mode 100644 index 0000000..6dbee9f Binary files /dev/null and b/png/src/test/resources/pngsuite/basn4a16.png differ diff --git a/png/src/test/resources/pngsuite/basn6a08.png b/png/src/test/resources/pngsuite/basn6a08.png new file mode 100644 index 0000000..6106230 Binary files /dev/null and b/png/src/test/resources/pngsuite/basn6a08.png differ diff --git a/png/src/test/resources/pngsuite/basn6a16.png b/png/src/test/resources/pngsuite/basn6a16.png new file mode 100644 index 0000000..a9bf3cb Binary files /dev/null and b/png/src/test/resources/pngsuite/basn6a16.png differ diff --git a/png/src/test/resources/pngsuite/readme.txt b/png/src/test/resources/pngsuite/readme.txt new file mode 100644 index 0000000..8c19bbd --- /dev/null +++ b/png/src/test/resources/pngsuite/readme.txt @@ -0,0 +1,36 @@ + +pngsuite +-------- +(c) Willem van Schaik, 1999 + +Permission to use, copy, and distribute these images for any purpose and +without fee is hereby granted. + +These 15 images are part of the much larger PngSuite test-set of +images, available for developers of PNG supporting software. The +complete set, available at http:/www.schaik.com/pngsuite/, contains +a variety of images to test interlacing, gamma settings, ancillary +chunks, etc. + +The images in this directory represent the basic PNG color-types: +grayscale (1-16 bit deep), full color (8 or 16 bit), paletted +(1-8 bit) and grayscale or color images with alpha channel. You +can use them to test the proper functioning of PNG software. + + filename depth type + ------------ ------ -------------- + basn0g01.png 1-bit grayscale + basn0g02.png 2-bit grayscale + basn0g04.png 4-bit grayscale + basn0g08.png 8-bit grayscale + basn0g16.png 16-bit grayscale + basn2c08.png 8-bit truecolor + basn2c16.png 16-bit truecolor + basn3p01.png 1-bit paletted + basn3p02.png 2-bit paletted + basn3p04.png 4-bit paletted + basn3p08.png 8-bit paletted + basn4a08.png 8-bit gray with alpha + basn4a16.png 16-bit gray with alpha + basn6a08.png 8-bit RGBA + basn6a16.png 16-bit RGBA \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 262e08d..8b7245f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,9 @@ include 'png' include 'io-vector' +include 'io-vector-eps' +include 'io-vector-pdf' +include 'io-vector-svg' +include 'io-pdfbox' +include 'layout-pdfbox' include 'chart' include 'barcode' -include 'layout-pdfbox' -include 'graphics2d-pdfbox' \ No newline at end of file