vandeseer / easytable

Small table drawing library built upon Apache PDFBox
MIT License
239 stars 91 forks source link

A heap of errors when running your simple code example #158

Closed bjornharvold closed 6 months ago

bjornharvold commented 6 months ago

Cheers for this lovely project. Found it after Pdfbox released 3.0.1 and boxable was not supporting the new way of doing native fonts. 🍺

What I am seeing:

13:11:38.106 [main] INFO travel.wink.mail.pdf.service.PDFServiceIntegrationTest -- Testing PDFService.createSecurePDFWithTabularData...
13:11:38.228 [main] WARN org.apache.pdfbox.pdmodel.font.FileSystemFontProvider -- 2 new fonts found, font cache will be re-built
13:11:38.228 [main] WARN org.apache.pdfbox.pdmodel.font.FileSystemFontProvider -- Building on-disk font cache, this may take a while
13:11:38.411 [main] WARN org.apache.pdfbox.pdmodel.font.FileSystemFontProvider -- Could not load font file: /Users/crash/Library/Fonts/Robika.otf
java.io.IOException: Invalid character code 0xFFFF02C3
    at org.apache.fontbox.ttf.CmapSubtable.processSubtype12(CmapSubtable.java:258)
    at org.apache.fontbox.ttf.CmapSubtable.initSubtable(CmapSubtable.java:110)
    at org.apache.fontbox.ttf.CmapTable.read(CmapTable.java:87)
    at org.apache.fontbox.ttf.TrueTypeFont.readTable(TrueTypeFont.java:365)
    at org.apache.fontbox.ttf.TTFParser.parseTables(TTFParser.java:165)
    at org.apache.fontbox.ttf.TTFParser.parse(TTFParser.java:144)
    at org.apache.fontbox.ttf.OTFParser.parse(OTFParser.java:56)
    at org.apache.fontbox.ttf.OTFParser.parse(OTFParser.java:27)
    at org.apache.fontbox.ttf.TTFParser.parse(TTFParser.java:66)
    at org.apache.fontbox.ttf.OTFParser.parse(OTFParser.java:50)
    at org.apache.pdfbox.pdmodel.font.FileSystemFontProvider.addTrueTypeFont(FileSystemFontProvider.java:685)
    at org.apache.pdfbox.pdmodel.font.FileSystemFontProvider.scanFonts(FileSystemFontProvider.java:392)
    at org.apache.pdfbox.pdmodel.font.FileSystemFontProvider.<init>(FileSystemFontProvider.java:367)
    at org.apache.pdfbox.pdmodel.font.FontMapperImpl$DefaultFontProvider.<clinit>(FontMapperImpl.java:139)
    at org.apache.pdfbox.pdmodel.font.FontMapperImpl.getProvider(FontMapperImpl.java:158)
    at org.apache.pdfbox.pdmodel.font.FontMapperImpl.findFont(FontMapperImpl.java:416)
    at org.apache.pdfbox.pdmodel.font.FontMapperImpl.findFontBoxFont(FontMapperImpl.java:379)
    at org.apache.pdfbox.pdmodel.font.FontMapperImpl.getFontBoxFont(FontMapperImpl.java:353)
    at org.apache.pdfbox.pdmodel.font.PDType1Font.<init>(PDType1Font.java:127)
    at org.vandeseer.easytable.structure.Table.<clinit>(Table.java:20)
    at travel.wink.mail.pdf.service.PDFServiceIntegrationTest.testSecurePDF(PDFServiceIntegrationTest.java:59)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85)
    at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47)
    at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
    at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
13:11:38.442 [main] ERROR org.apache.fontbox.ttf.GlyphSubstitutionTable -- The expected SubstFormat for ExtensionSubstFormat1 subtable is 19 but should be 1
13:11:38.442 [main] ERROR org.apache.fontbox.ttf.GlyphSubstitutionTable -- The expected SubstFormat for ExtensionSubstFormat1 subtable is 20 but should be 1
13:11:38.442 [main] ERROR org.apache.fontbox.ttf.GlyphSubstitutionTable -- The expected SubstFormat for ExtensionSubstFormat1 subtable is 21 but should be 1
13:11:38.442 [main] ERROR org.apache.fontbox.ttf.GlyphSubstitutionTable -- The expected SubstFormat for ExtensionSubstFormat1 subtable is 22 but should be 1
13:11:38.442 [main] ERROR org.apache.fontbox.ttf.GlyphSubstitutionTable -- The expected SubstFormat for ExtensionSubstFormat1 subtable is 23 but should be 1
13:11:39.464 [main] ERROR org.apache.fontbox.ttf.GlyphSubstitutionTable -- The expected SubstFormat for ExtensionSubstFormat1 subtable is 7 but should be 1
13:11:39.491 [main] ERROR org.apache.fontbox.ttf.GlyphSubstitutionTable -- The expected SubstFormat for ExtensionSubstFormat1 subtable is 7 but should be 1
13:11:39.522 [main] ERROR org.apache.fontbox.ttf.GlyphSubstitutionTable -- The expected SubstFormat for ExtensionSubstFormat1 subtable is 7 but should be 1
13:11:39.549 [main] ERROR org.apache.fontbox.ttf.GlyphSubstitutionTable -- The expected SubstFormat for ExtensionSubstFormat1 subtable is 7 but should be 1

I get this error for a bunch of other fonts:

The PDF does get created but I am sure I am doing something wrong OR there is something wrong with the library.

Setup

Unit test

@Test
    void givenTabularData_whenCreatingPdf_thenVerify() throws Exception {
        log.info("Testing PDFService.createSecurePDFWithTabularData...");

        final Table myTable = Table.builder()
                .font(HELVETICA)
                .addColumnsOfWidth(200, 200)
                .padding(2)
                .addRow(Row.builder()
                        .add(TextCell.builder().text("One One").borderWidth(4).borderColorLeft(Color.MAGENTA).backgroundColor(Color.WHITE).build())
                        .add(TextCell.builder().text("One Two").borderWidth(0).backgroundColor(Color.YELLOW).build())
                        .build())
                .addRow(Row.builder()
                        .padding(10)
                        .add(TextCell.builder().text("Two One").textColor(Color.RED).build())
                        .add(TextCell.builder().text("Two Two")
                                .borderWidthRight(1f)
                                .borderStyleRight(BorderStyle.DOTTED)
                                .horizontalAlignment(HorizontalAlignment.RIGHT)
                                .build())
                        .build())
                .build();

        try (PDDocument pdf = this.pdfService.createSecurePDFWithTabularData(myTable)) {
            assertNotNull(pdf, "pdf should not be null");
            pdf.save(new File("//Users/crash/Downloads/table.pdf"));
        }

        log.info("Testing PDFService.createSecurePDFWithTabularData SUCCESS");
    }

Code:

@Override
    public PDDocument createSecurePDFWithTabularData(
            Table table
    ) throws IOException {
        PDDocument document = new PDDocument();
        PDPage page = new PDPage();
        document.addPage(page);

        try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
            // Set up the drawer
            TableDrawer tableDrawer = TableDrawer.builder()
                    .contentStream(contentStream)
                    .startX(20f)
                    .startY(page.getMediaBox().getUpperRightY() - 20f)
                    .table(table)
                    .build();

            // And go for it!
            tableDrawer.draw();
        }

        return document;
    }
vandeseer commented 6 months ago

Hey @bjornharvold, the unit and integration tests all run through, so I think it's not an issue of the library. What happens when creating a simple PDF document without using easytable?

bjornharvold commented 6 months ago

Hi @vandeseer

You are right. I used their Hello World example and get the same messages.

Closing. 🍺