写入PDF文件时,图像上绘制的形状会反转 [英] Shapes drawn on an image is inverted when written into PDF file

查看:176
本文介绍了写入PDF文件时,图像上绘制的形状会反转的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个PDF文件,我将其转换为图像.能够在图像上书写,但是当我尝试将形状/线保存到pdf中时,关键点不是它们的位置,而是形状被反转.

这是我画的.

这是保存的PDF文件.

我真的很抱歉,但这是我能做的最短的代码,以解决问题.

我知道这个问题不好,但我希望有人能提供帮助.

感谢您 Tilman Hausherr 的耐心等候.

   package pdfwriter;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;

public class Example {

    private static class MyImagePanel extends JPanel {

        final BufferedImage image;
        final float scale = .38f;
        AffineTransform atg;
        Point start = new Point();
        Point end = new Point();
        boolean isNewLine = true;
        static ArrayList<Line2D> lines = new ArrayList<>();
        static PDDocument document;

        public MyImagePanel() throws IOException {

            document = PDDocument.load(new File("path"));
            PDFRenderer renderer = new PDFRenderer(document);
            image = renderer.renderImageWithDPI(0, 200, ImageType.RGB);

            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseReleased(MouseEvent e) {
                    if (end != start) {
                        Line2D line = new Line2D.Float(start.x, start.y, end.x, end.y);
                        lines.add(line);
                        Point2D p = calcCoordinates(e);
                        start = new Point();
                        start.x = (int) p.getX();
                        start.y = (int) p.getY();
                        repaint();
                    }

                }
            });
            addMouseMotionListener(new MouseMotionAdapter() {
                @Override
                public void mouseMoved(MouseEvent e) {
                    Point2D p = calcCoordinates(e);
                    end = new Point();

                    end.x = (int) p.getX();
                    end.y = (int) p.getY();
                    repaint();
                }
            });
        }

        private Point2D calcCoordinates(MouseEvent e) {
            Point p = new Point(e.getX(), e.getY());
            try {
                return atg.inverseTransform(p, null);
            } catch (NoninvertibleTransformException ex) {
                return p;
            }
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            Graphics2D g2D = (Graphics2D) g.create();

            double affineX = (getWidth() - scale * image.getWidth()) / 2;
            double affineY = (getHeight() - scale * image.getHeight()) / 2;

            AffineTransform at = new AffineTransform();
            at.translate(affineX, affineY);
            at.scale(scale, scale);

            AffineTransform atf = g2D.getTransform();
            atf.concatenate(at);

            atg = (AffineTransform) atf.clone();

            g2D.setTransform(atf);

            g2D.drawImage(image, 0, 0, this);
            try {
                g2D.drawLine(start.x, start.y, end.x, end.y);
            } catch (NullPointerException e) {

            }

            for (Line2D l : lines) {
                g2D.draw(l);
            }

            g2D.dispose();
        }

        public static void save() {

            try {
                PDPage page = document.getPage(0);

                PDPageContentStream contentStream = new PDPageContentStream(document, page, true, true, true);

                for (Line2D l : lines) {
                    contentStream.moveTo((float) l.getX1(), (float) l.getY1());
                    contentStream.lineTo((float) l.getX2(), (float) l.getY2());
                    contentStream.stroke();
                }

                contentStream.close();

                document.save(
                        new File("path"));
                document.close();
            } catch (IOException ex) {
                Logger.getLogger(Example.class.getName()).log(Level.SEVERE, null, ex);
            }

        }

        @Override
        public Dimension getPreferredSize() {
            int width = (int) (scale * image.getWidth());
            int height = (int) (scale * image.getHeight());
            return new Dimension(width, height);
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("PDF");
        frame.setSize(1500, 1200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);

        MyImagePanel imagePanel = null;
        try {
            imagePanel = new MyImagePanel();
        } catch (IOException ex) {
            Logger.getLogger(Example.class
                    .getName()).log(Level.SEVERE, null, ex);
        }

        JButton btn = new JButton("Save");

        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                MyImagePanel.save();
            }
        });

        btn.setBounds(10, 0, 70, 30);

        frame.add(btn);
        JPanel pnl = new JPanel();
        pnl.add(imagePanel);
        pnl.setBounds(0, 100, 1500, 1200);
        frame.add(pnl);
        frame.revalidate();
        frame.repaint();
        frame.setVisible(true);
    }

}

解决方案

PDF坐标从底部开始.因此,您必须从页面高度中扣除它. (如果有一个裁剪框,则要复杂一些,您必须将原点添加到计算的坐标中,因为裁剪框就是您所看到的).而且您需要从calcCoordinates =>变换逆变换.

因此代码应如下所示:

for (Line2D l : lines)
{
    Point2D p1 = new Point2D.Double(l.getX1(), l.getY1());
    Point2D p2 = new Point2D.Double(l.getX2(), l.getY2());
    p1 = atg.transform(p1, null);
    p2 = atg.transform(p2, null);
    contentStream.moveTo((float) p1.getX(), page.getMediaBox().getHeight() - (float) p1.getY());
    contentStream.lineTo((float) p2.getX(), page.getMediaBox().getHeight() - (float) p2.getY());
    contentStream.stroke();
}

要使其正常工作,必须能够访问atg,因为我从保存"中删除了静态",并在异常处理程序中添加了返回",并将MyImagePanel.save()更改为imagePanel.save();.

但是,等等,还有更多...以某种方式无法完全满足需求.略有不同...原因:比例尺不是0.38,约为0.36(72/200),其中200是您的dpi.您的错误是拥有两个相互依赖的固定值,但是这种依赖关系不在代码中.您的代码应具有以下内容:

final int DPI = 200;
final float scale = 72f / DPI;

完整代码:

public class SO57387803DrawShapesInPDF
{

    private static class MyImagePanel extends JPanel
    {

        final BufferedImage image;
        //final float scale = .38f;
        final int DPI = 200;
        final float scale = 72f / DPI;

        AffineTransform atg;
        Point start = new Point();
        Point end = new Point();
        boolean isNewLine = true;
        static ArrayList<Line2D> lines = new ArrayList<>();
        static PDDocument document;

        public MyImagePanel() throws IOException
        {
            document = PDDocument.load(new File("XXXX.pdf"));
            PDFRenderer renderer = new PDFRenderer(document);
            image = renderer.renderImageWithDPI(0, DPI, ImageType.RGB);

            addMouseListener(new MouseAdapter()
            {
                @Override
                public void mouseReleased(MouseEvent e)
                {
                    if (end != start)
                    {
                        Line2D line = new Line2D.Float(start.x, start.y, end.x, end.y);
                        lines.add(line);
                        Point2D p = calcCoordinates(e);
                        start = new Point();
                        start.x = (int) p.getX();
                        start.y = (int) p.getY();

                        repaint();
                    }

                }
            });
            addMouseMotionListener(new MouseMotionAdapter()
            {
                @Override
                public void mouseMoved(MouseEvent e)
                {
                    Point2D p = calcCoordinates(e);
                    end = new Point();

                    end.x = (int) p.getX();
                    end.y = (int) p.getY();
                    repaint();
                }
            });
        }

        private Point2D calcCoordinates(MouseEvent e)
        {
            Point p = new Point(e.getX(), e.getY());
            try
            {
                return atg.inverseTransform(p, null);
            }
            catch (NoninvertibleTransformException ex)
            {
                return p;
            }
        }

        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);

            Graphics2D g2D = (Graphics2D) g.create();

            double affineX = (getWidth() - scale * image.getWidth()) / 2;
            double affineY = (getHeight() - scale * image.getHeight()) / 2;

            AffineTransform at = new AffineTransform();
            at.translate(affineX, affineY);
            at.scale(scale, scale);

            AffineTransform atf = g2D.getTransform();
            atf.concatenate(at);
            atg = (AffineTransform) at.clone();

            g2D.setTransform(atf);

            g2D.drawImage(image, 0, 0, this);
            try
            {
                g2D.drawLine(start.x, start.y, end.x, end.y);
            }
            catch (NullPointerException e)
            {

            }

            for (Line2D l : lines)
            {
                g2D.draw(l);
            }

            g2D.dispose();
        }

        public void save()
        {

            try
            {
                PDPage page = document.getPage(0);

                PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, true);

                for (Line2D l : lines)
                {
                    Point2D p1 = new Point2D.Double(l.getX1(), l.getY1());
                    Point2D p2 = new Point2D.Double(l.getX2(), l.getY2());
                    p1 = atg.transform(p1, null);
                    p2 = atg.transform(p2, null);
                    //contentStream.moveTo((float) l.getX1(), (float) l.getY1());
                    //contentStream.lineTo((float) l.getX2(), (float) l.getY2());
                    contentStream.moveTo((float) p1.getX(), page.getMediaBox().getHeight() - (float) p1.getY());
                    contentStream.lineTo((float) p2.getX(), page.getMediaBox().getHeight() - (float) p2.getY());
                    contentStream.stroke();
                }

                contentStream.close();

                document.save(new File("saved.pdf"));
                document.close();
            }
            catch (IOException ex)
            {
                Logger.getLogger(SO57387803DrawShapesInPDF.class.getName()).log(Level.SEVERE, null, ex);
            }

        }

        @Override
        public Dimension getPreferredSize()
        {
            int width = (int) (scale * image.getWidth());
            int height = (int) (scale * image.getHeight());
            return new Dimension(width, height);
        }
    }

    public static void main(String[] args)
    {
        JFrame frame = new JFrame("PDF");
        frame.setSize(1500, 1200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);

        // MyImagePanel imagePanel = null;
        MyImagePanel imagePanel;
        try
        {
            imagePanel = new MyImagePanel();
        }
        catch (IOException ex)
        {
            Logger.getLogger(SO57387803DrawShapesInPDF.class
                    .getName()).log(Level.SEVERE, null, ex);
            return; // or there would be an uninitialized variable
        }

        JButton btn = new JButton("Save");

        btn.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                imagePanel.save();
                //MyImagePanel.save();
            }
        });

        btn.setBounds(10, 0, 70, 30);

        frame.add(btn);
        JPanel pnl = new JPanel();
        pnl.add(imagePanel);
        pnl.setBounds(0, 100, 1500, 1200);
        frame.add(pnl);
        frame.revalidate();
        frame.repaint();
        frame.setVisible(true);
    }

}

I have a PDF file that I converted into an image. Was able to write on top of the image but when I tried to save the shapes/lines into the pdf, the point are not their place and the shapes are inverted.

This is what I draw.

This is the saved PDF File.

I'm really sorry but that is the shortest code I can make in order replicate the problem.

I know this question is not good but I hope someone can help.

Thank you Tilman Hausherr for your patience..

   package pdfwriter;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;

public class Example {

    private static class MyImagePanel extends JPanel {

        final BufferedImage image;
        final float scale = .38f;
        AffineTransform atg;
        Point start = new Point();
        Point end = new Point();
        boolean isNewLine = true;
        static ArrayList<Line2D> lines = new ArrayList<>();
        static PDDocument document;

        public MyImagePanel() throws IOException {

            document = PDDocument.load(new File("path"));
            PDFRenderer renderer = new PDFRenderer(document);
            image = renderer.renderImageWithDPI(0, 200, ImageType.RGB);

            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseReleased(MouseEvent e) {
                    if (end != start) {
                        Line2D line = new Line2D.Float(start.x, start.y, end.x, end.y);
                        lines.add(line);
                        Point2D p = calcCoordinates(e);
                        start = new Point();
                        start.x = (int) p.getX();
                        start.y = (int) p.getY();
                        repaint();
                    }

                }
            });
            addMouseMotionListener(new MouseMotionAdapter() {
                @Override
                public void mouseMoved(MouseEvent e) {
                    Point2D p = calcCoordinates(e);
                    end = new Point();

                    end.x = (int) p.getX();
                    end.y = (int) p.getY();
                    repaint();
                }
            });
        }

        private Point2D calcCoordinates(MouseEvent e) {
            Point p = new Point(e.getX(), e.getY());
            try {
                return atg.inverseTransform(p, null);
            } catch (NoninvertibleTransformException ex) {
                return p;
            }
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            Graphics2D g2D = (Graphics2D) g.create();

            double affineX = (getWidth() - scale * image.getWidth()) / 2;
            double affineY = (getHeight() - scale * image.getHeight()) / 2;

            AffineTransform at = new AffineTransform();
            at.translate(affineX, affineY);
            at.scale(scale, scale);

            AffineTransform atf = g2D.getTransform();
            atf.concatenate(at);

            atg = (AffineTransform) atf.clone();

            g2D.setTransform(atf);

            g2D.drawImage(image, 0, 0, this);
            try {
                g2D.drawLine(start.x, start.y, end.x, end.y);
            } catch (NullPointerException e) {

            }

            for (Line2D l : lines) {
                g2D.draw(l);
            }

            g2D.dispose();
        }

        public static void save() {

            try {
                PDPage page = document.getPage(0);

                PDPageContentStream contentStream = new PDPageContentStream(document, page, true, true, true);

                for (Line2D l : lines) {
                    contentStream.moveTo((float) l.getX1(), (float) l.getY1());
                    contentStream.lineTo((float) l.getX2(), (float) l.getY2());
                    contentStream.stroke();
                }

                contentStream.close();

                document.save(
                        new File("path"));
                document.close();
            } catch (IOException ex) {
                Logger.getLogger(Example.class.getName()).log(Level.SEVERE, null, ex);
            }

        }

        @Override
        public Dimension getPreferredSize() {
            int width = (int) (scale * image.getWidth());
            int height = (int) (scale * image.getHeight());
            return new Dimension(width, height);
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("PDF");
        frame.setSize(1500, 1200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);

        MyImagePanel imagePanel = null;
        try {
            imagePanel = new MyImagePanel();
        } catch (IOException ex) {
            Logger.getLogger(Example.class
                    .getName()).log(Level.SEVERE, null, ex);
        }

        JButton btn = new JButton("Save");

        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                MyImagePanel.save();
            }
        });

        btn.setBounds(10, 0, 70, 30);

        frame.add(btn);
        JPanel pnl = new JPanel();
        pnl.add(imagePanel);
        pnl.setBounds(0, 100, 1500, 1200);
        frame.add(pnl);
        frame.revalidate();
        frame.repaint();
        frame.setVisible(true);
    }

}

解决方案

PDF coordinates start at the bottom. So you have to deduct it from the page height. (And if there is a cropbox, then it's a bit more complex, you'd have to add the origins to the calculated coordinates, because the cropbox is what you see). And you need to reverse the inverse-transform from calcCoordinates => transform.

So the code should look like this:

for (Line2D l : lines)
{
    Point2D p1 = new Point2D.Double(l.getX1(), l.getY1());
    Point2D p2 = new Point2D.Double(l.getX2(), l.getY2());
    p1 = atg.transform(p1, null);
    p2 = atg.transform(p2, null);
    contentStream.moveTo((float) p1.getX(), page.getMediaBox().getHeight() - (float) p1.getY());
    contentStream.lineTo((float) p2.getX(), page.getMediaBox().getHeight() - (float) p2.getY());
    contentStream.stroke();
}

To make that work, atg must be accessible, for that I removed "static" from "save", and added a "return" in the exception handler, and changed MyImagePanel.save() to imagePanel.save();.

But wait, there's more... somehow the lines don't fit fully. There is a slight difference... the reason: scale is not .38, it is about .36 (72 / 200), 200 being your dpi. Your mistake was to have two fixed values that depend on each other, but this dependence wasn't in the code. Your code should have something like this:

final int DPI = 200;
final float scale = 72f / DPI;

Full code:

public class SO57387803DrawShapesInPDF
{

    private static class MyImagePanel extends JPanel
    {

        final BufferedImage image;
        //final float scale = .38f;
        final int DPI = 200;
        final float scale = 72f / DPI;

        AffineTransform atg;
        Point start = new Point();
        Point end = new Point();
        boolean isNewLine = true;
        static ArrayList<Line2D> lines = new ArrayList<>();
        static PDDocument document;

        public MyImagePanel() throws IOException
        {
            document = PDDocument.load(new File("XXXX.pdf"));
            PDFRenderer renderer = new PDFRenderer(document);
            image = renderer.renderImageWithDPI(0, DPI, ImageType.RGB);

            addMouseListener(new MouseAdapter()
            {
                @Override
                public void mouseReleased(MouseEvent e)
                {
                    if (end != start)
                    {
                        Line2D line = new Line2D.Float(start.x, start.y, end.x, end.y);
                        lines.add(line);
                        Point2D p = calcCoordinates(e);
                        start = new Point();
                        start.x = (int) p.getX();
                        start.y = (int) p.getY();

                        repaint();
                    }

                }
            });
            addMouseMotionListener(new MouseMotionAdapter()
            {
                @Override
                public void mouseMoved(MouseEvent e)
                {
                    Point2D p = calcCoordinates(e);
                    end = new Point();

                    end.x = (int) p.getX();
                    end.y = (int) p.getY();
                    repaint();
                }
            });
        }

        private Point2D calcCoordinates(MouseEvent e)
        {
            Point p = new Point(e.getX(), e.getY());
            try
            {
                return atg.inverseTransform(p, null);
            }
            catch (NoninvertibleTransformException ex)
            {
                return p;
            }
        }

        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);

            Graphics2D g2D = (Graphics2D) g.create();

            double affineX = (getWidth() - scale * image.getWidth()) / 2;
            double affineY = (getHeight() - scale * image.getHeight()) / 2;

            AffineTransform at = new AffineTransform();
            at.translate(affineX, affineY);
            at.scale(scale, scale);

            AffineTransform atf = g2D.getTransform();
            atf.concatenate(at);
            atg = (AffineTransform) at.clone();

            g2D.setTransform(atf);

            g2D.drawImage(image, 0, 0, this);
            try
            {
                g2D.drawLine(start.x, start.y, end.x, end.y);
            }
            catch (NullPointerException e)
            {

            }

            for (Line2D l : lines)
            {
                g2D.draw(l);
            }

            g2D.dispose();
        }

        public void save()
        {

            try
            {
                PDPage page = document.getPage(0);

                PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, true);

                for (Line2D l : lines)
                {
                    Point2D p1 = new Point2D.Double(l.getX1(), l.getY1());
                    Point2D p2 = new Point2D.Double(l.getX2(), l.getY2());
                    p1 = atg.transform(p1, null);
                    p2 = atg.transform(p2, null);
                    //contentStream.moveTo((float) l.getX1(), (float) l.getY1());
                    //contentStream.lineTo((float) l.getX2(), (float) l.getY2());
                    contentStream.moveTo((float) p1.getX(), page.getMediaBox().getHeight() - (float) p1.getY());
                    contentStream.lineTo((float) p2.getX(), page.getMediaBox().getHeight() - (float) p2.getY());
                    contentStream.stroke();
                }

                contentStream.close();

                document.save(new File("saved.pdf"));
                document.close();
            }
            catch (IOException ex)
            {
                Logger.getLogger(SO57387803DrawShapesInPDF.class.getName()).log(Level.SEVERE, null, ex);
            }

        }

        @Override
        public Dimension getPreferredSize()
        {
            int width = (int) (scale * image.getWidth());
            int height = (int) (scale * image.getHeight());
            return new Dimension(width, height);
        }
    }

    public static void main(String[] args)
    {
        JFrame frame = new JFrame("PDF");
        frame.setSize(1500, 1200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);

        // MyImagePanel imagePanel = null;
        MyImagePanel imagePanel;
        try
        {
            imagePanel = new MyImagePanel();
        }
        catch (IOException ex)
        {
            Logger.getLogger(SO57387803DrawShapesInPDF.class
                    .getName()).log(Level.SEVERE, null, ex);
            return; // or there would be an uninitialized variable
        }

        JButton btn = new JButton("Save");

        btn.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                imagePanel.save();
                //MyImagePanel.save();
            }
        });

        btn.setBounds(10, 0, 70, 30);

        frame.add(btn);
        JPanel pnl = new JPanel();
        pnl.add(imagePanel);
        pnl.setBounds(0, 100, 1500, 1200);
        frame.add(pnl);
        frame.revalidate();
        frame.repaint();
        frame.setVisible(true);
    }

}

这篇关于写入PDF文件时,图像上绘制的形状会反转的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆