[ 
https://issues.apache.org/jira/browse/PDFBOX-4820?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17094136#comment-17094136
 ] 

Tilman Hausherr commented on PDFBOX-4820:
-----------------------------------------

If you want to use a SNAPSHOT in maven you'll have to add this repository to 
your pom.xml like this:
{code:java}
    <repositories>
        <repository>
            <id>apache.snapshots</id>
            <url>https://repository.apache.org/snapshots/</url>
        </repository>        
        <repository>
            <id>snapshots</id>
            
<url>https://repository.apache.org/content/repositories/snapshots</url>
        </repository>
    </repositories>{code}
we do  release usually every 3 or 4 months and we just has a release 2 months 
ago.

As a work-around you could detect this type of broken annotations and not 
render them, by passing an AnnotationsFilter to PDFRenderer, until the next 
release.

The code should be somewhat like this (I didn't test it, and I just woke up):
{code:java}
AnnotationFilter annotationFilter = new AnnotationFilter()
     {
         @Override
         public boolean accept(PDAnnotation annotation)
         {
             PDAppearanceDictionary appearance = annotation.getAppearance();
             if (appearance != null)
             {
                 PDAppearanceEntry normalAppearance = 
appearance.getNormalAppearance();
                 if (normalAppearance != null)
                 {
                     PDAppearanceStream appearanceStream = 
normalAppearance.getAppearanceStream();
                     if (appearanceStream != null && appearanceStream.getBBox() 
!= null)
                     {
                         if (appearanceStream.getBBox().getWidth() <= 0 || 
appearanceStream.getBBox().getHeight() <= 0)
                         {
                             return false;
                         }
                     }
                 }
             }
             return true;
         }
     };
{code}
 

> Multiplying two matrices produces illegal values
> ------------------------------------------------
>
>                 Key: PDFBOX-4820
>                 URL: https://issues.apache.org/jira/browse/PDFBOX-4820
>             Project: PDFBox
>          Issue Type: Bug
>          Components: Rendering
>    Affects Versions: 2.0.19
>            Reporter: jiangpeiheng
>            Priority: Major
>         Attachments: bit_coin.pdf
>
>
> Hi, pdfbox developers
> I meet an exception during rendering the PDF in the attachment. It seems that 
> this exception occors while rendering the first and the last page of this 
> PDF. The exception is:
> {code:java}
> 20/04/28 03:45:01 ERROR RenderHandler: [PDF_RENDER_CORE_HANDLER]渲染单页异常, 
> pageIndex:1, traceId:test-trace, e:
> java.lang.IllegalArgumentException: Multiplying two matrices produces illegal 
> values at     org.apache.pdfbox.util.Matrix.multiply(Matrix.java:408) at 
> org.apache.pdfbox.util.Matrix.concatenate(Matrix.java:261) at 
> org.apache.pdfbox.contentstream.PDFStreamEngine.processAnnotation(PDFStreamEngine.java:321)
>  at 
> org.apache.pdfbox.contentstream.PDFStreamEngine.showAnnotation(PDFStreamEngine.java:425)
>  at 
> org.apache.pdfbox.rendering.PageDrawer.showAnnotation(PageDrawer.java:1394) 
> at org.apache.pdfbox.rendering.PageDrawer.drawPage(PageDrawer.java:274) at 
> org.apache.pdfbox.rendering.PDFRenderer.renderImage(PDFRenderer.java:321) at 
> org.apache.pdfbox.rendering.PDFRenderer.renderImage(PDFRenderer.java:243) at 
> org.apache.pdfbox.rendering.PDFRenderer.renderImageWithDPI(PDFRenderer.java:215)
>  at 
> com.bytedance.esign.pdfrender.handler.RenderHandler.renderSinglePage(RenderHandler.java:175)
>  at 
> com.bytedance.esign.pdfrender.handler.RenderHandler.render(RenderHandler.java:119)
>  at 
> com.bytedance.esign.pdfrender.handler.RenderHandlerTest.renderTest(RenderHandlerTest.java:32)
>  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at 
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
> at 
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>  at java.lang.reflect.Method.invoke(Method.java:498) at 
> org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
>  at 
> org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
>  at 
> org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
>  at 
> org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
>  at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at 
> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
>  at 
> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
>  at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at 
> org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at 
> org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at 
> org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at 
> org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at 
> org.junit.runners.ParentRunner.run(ParentRunner.java:363) at 
> org.junit.runner.JUnitCore.run(JUnitCore.java:137) at 
> com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
>  at 
> com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
>  at 
> com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
>  at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
> {code}
> And here is my rendering code:
> {code:java}
> package com.bytedance.esign.pdfrender.handler;
> import com.google.common.collect.Lists;
> import com.google.common.collect.Maps;
> import lombok.Data;
> import lombok.ToString;
> import lombok.experimental.Accessors;
> import lombok.extern.slf4j.Slf4j;
> import org.apache.pdfbox.io.MemoryUsageSetting;
> import org.apache.pdfbox.pdmodel.PDDocument;
> import org.apache.pdfbox.rendering.PDFRenderer;
> import javax.imageio.ImageIO;
> import java.awt.image.BufferedImage;
> import java.io.ByteArrayInputStream;
> import java.io.ByteArrayOutputStream;
> import java.io.IOException;
> import java.util.Collections;
> import java.util.List;
> import java.util.Map;
> import java.util.stream.Collectors;
> import java.util.stream.IntStream;
> /**
>  * 切图相关的Handler
>  *
>  * @author jiangpeiheng create on 2020/4/27
>  */
> @Slf4j
> public class RenderHandler {
>     private static final String LOG_PERFIX = "PDF_RENDER_CORE_HANDLER";
>     // some settings for rendering
>     private static final int IMAGE_DPI = 200;
>     private static final String IMAGE_FORMAT = "jpg";
>     private RenderHandler() {
>     }
>     @Data
>     @Accessors(chain = true)
>     public static class RenderTask {
>         /**
>          * pdf源文件byte数组
>          */
>         @ToString.Exclude
>         private byte[] pdfBytes;
>         /**
>          * 用于追踪文件渲染关联的id
>          */
>         private String traceId;
>         /**
>          * 起始渲染页,从0开始
>          */
>         private int start;
>         /**
>          * 终止渲染页,不包含该页
>          */
>         private int end;
>     }
>     @Data
>     @Accessors(chain = true)
>     public static class RenderResult {
>         /**
>          * 渲染完成的页面
>          */
>         @ToString.Exclude
>         private Map<Integer, byte[]> images = Maps.newHashMap();
>         /**
>          * 用于追踪文件渲染关联的id
>          */
>         private String traceId;
>         /**
>          * 渲染失败的页面
>          */
>         private List<Integer> failedPages = Lists.newArrayList();
>         /**
>          * 总页数
>          */
>         private int totalPageCount;
>         /**
>          * 渲染成功页数
>          */
>         private int successPageCount;
>         /**
>          * 渲染失败页数
>          */
>         private int failedPageCount;
>     }
>     /**
>      * 针对pdf文件进行渲染
>      *
>      * @param task 渲染任务
>      * @return
>      */
>     public static RenderResult render(RenderTask task) {
>         long startTime = System.currentTimeMillis();
>         RenderResult result = initResult(task);
>         try (
>                 PDDocument doc = load(task.getPdfBytes())
>         ) {
>             log.info("[{}]载入PDDocument耗时:{}",
>                     LOG_PERFIX, System.currentTimeMillis() - startTime);
>             PDFRenderer renderer = new PDFRenderer(doc);
>             for (int i = task.start; i <= task.end; i++) {
>                 recordTransferedImage(result, renderSinglePage(task, 
> renderer, i), i);
>             }
>         } catch (Exception e) {
>             log.error("[{}]渲染PDF异常, task:{}, e:",
>                     LOG_PERFIX, task, e);
>             result = buildFailedResult(task);
>         } finally {
>             log.info("[{}]渲染PDF完成, task:{}, result:{}, cost:{}",
>                     LOG_PERFIX, task, result,
>                     System.currentTimeMillis() - startTime);
>         }
>         return result;
>     }
>     /**
>      * 初始化RenderResult
>      *
>      * @param task
>      * @return
>      */
>     private static RenderResult initResult(RenderTask task) {
>         return new RenderResult()
>                 .setTraceId(task.traceId)
>                 .setTotalPageCount(getPageCountByRange(task.start, task.end));
>     }
>     /**
>      * 记录单页渲染结果
>      *
>      * @param result
>      * @param image
>      * @param pageIndex
>      */
>     private static void recordTransferedImage(RenderResult result, byte[] 
> image, int pageIndex) {
>         if (image == null) {
>             // 渲染失败
>             result.failedPages.add(pageIndex);
>             result.failedPageCount++;
>         } else {
>             // 渲染成功
>             result.images.put(pageIndex, image);
>             result.successPageCount++;
>         }
>     }
>     /**
>      * 渲染单页
>      *
>      * @param task
>      * @param renderer
>      * @param pageIndex
>      * @return
>      */
>     private static byte[] renderSinglePage(RenderTask task, PDFRenderer 
> renderer, int pageIndex) {
>         try {
>             // 渲染第一页,则这里传入的pageIndex需要减1
>             return transformImage(renderer.renderImageWithDPI(pageIndex - 1, 
> IMAGE_DPI));
>         } catch (Exception e) {
>             log.error("[{}]渲染单页异常, pageIndex:{}, traceId:{}, e:",
>                     LOG_PERFIX, pageIndex, task.getTraceId(), e);
>             return null;
>         }
>     }
>     /**
>      * BufferedImage -> byte[]
>      *
>      * @param bim
>      * @return
>      * @throws IOException
>      */
>     private static byte[] transformImage(BufferedImage bim) throws 
> IOException {
>         ByteArrayOutputStream os = new ByteArrayOutputStream();
>         ImageIO.write(bim, IMAGE_FORMAT, os);
>         return os.toByteArray();
>     }
>     /**
>      * byte[] -> PDDocument
>      *
>      * @param docBytes
>      * @return
>      * @throws IOException
>      */
>     private static PDDocument load(byte[] docBytes) throws IOException {
>         return PDDocument.load(new ByteArrayInputStream(docBytes),
>                 MemoryUsageSetting.setupTempFileOnly());
>     }
>     /**
>      * 渲染主流程失败时,直接构建失败的result
>      *
>      * @param task
>      * @return
>      */
>     private static RenderResult buildFailedResult(RenderTask task) {
>         return new RenderResult()
>                 .setImages(Collections.emptyMap())
>                 .setFailedPages(IntStream.rangeClosed(task.start, task.end)
>                         .boxed()
>                         .collect(Collectors.toList()))
>                 .setTotalPageCount(getPageCountByRange(task.start, task.end))
>                 .setTraceId(task.traceId);
>     }
>     /**
>      * 根据页码范围获取页数
>      *
>      * @param start
>      * @param end
>      * @return
>      */
>     private static int getPageCountByRange(int start, int end) {
>         return end - start + 1;
>     }
> }
> {code}
> And here is my unit test code:
> {code:java}
> package com.bytedance.esign.pdfrender.handler;
> import lombok.extern.slf4j.Slf4j;
> import org.apache.commons.io.IOUtils;
> import org.junit.Test;
> import java.io.FileInputStream;
> import java.io.FileNotFoundException;
> import java.io.FileOutputStream;
> import java.io.IOException;
> import java.util.Map;
> /**
>  * @author jiangpeiheng create on 2020/4/27
>  */
> @Slf4j
> public class RenderHandlerTest {
>     private static final String BASE_DIR_PATH = 
> "/Users/jiangpeiheng/myhome/work_stuff/esign/optimize/pdfrender/";
>     private static final String OUTPUT_DIR_PATH = BASE_DIR_PATH + "output/";
>     private static final String INPUT_PDF_PATH = BASE_DIR_PATH + 
> "bit_coin.pdf";
>     private static final String OUTPUT_PIC_PATH_PREFIX = OUTPUT_DIR_PATH + 
> "output_pic_";
>     @Test
>     public void renderTest() throws Exception {
>         byte[] input = IOUtils.toByteArray(new 
> FileInputStream(INPUT_PDF_PATH));
>         RenderHandler.RenderTask task = new RenderHandler.RenderTask()
>                 .setPdfBytes(input)
>                 .setTraceId("test-trace")
>                 .setStart(1)
>                 .setEnd(20);
>         RenderHandler.RenderResult result = RenderHandler.render(task);
>         result.getImages().forEach((pageIndex, image) -> {
>             try (
>                     FileOutputStream fos = new 
> FileOutputStream(OUTPUT_PIC_PATH_PREFIX + pageIndex + ".jpg");
>             ) {
>                 fos.write(image);
>             } catch (Exception e) {
>                 log.error("output process error");
>             }
>         });
>     }
> }
> {code}
> I'm looking forward to your kindly response.
> Thank you
> Jiang Peiheng



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to