You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@pdfbox.apache.org by "jiangpeiheng (Jira)" <ji...@apache.org> on 2020/04/27 19:58:00 UTC

[jira] [Updated] (PDFBOX-4820) Multiplying two matrices produces illegal values

     [ https://issues.apache.org/jira/browse/PDFBOX-4820?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

jiangpeiheng updated PDFBOX-4820:
---------------------------------
    Description: 
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

  was:
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: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


> 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: dev-unsubscribe@pdfbox.apache.org
For additional commands, e-mail: dev-help@pdfbox.apache.org