Shapes drawn on an image is inverted when written into PDF file

梦想与她 提交于 2020-01-03 06:45:55

问题


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);
    }

}

回答1:


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);
    }

}


来源:https://stackoverflow.com/questions/57387803/shapes-drawn-on-an-image-is-inverted-when-written-into-pdf-file

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!