可打印的打印BufferedImage大小不正确 [英] Printable prints BufferedImage with incorrect size

查看:166
本文介绍了可打印的打印BufferedImage大小不正确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,我在这里尝试的是打印BufferedImage,一切正常,直到你看到结果。结果很大,印刷量很大,并且在出于某种原因打印时不会扩大尺寸。
我使用((MM * DPI)/ 25,4)根据毫米的纸张尺寸计算正确的像素长度,但是当我将它打印到大的时候。

So yeah what I am trying here is printing a BufferedImage, all works just fine until you see the outcome. The outcome is to big, the print is to large and doesn't it scales up everything when printing for some reason. I used ((MM * DPI)/25,4) to calculate the correct pixel length according to paper size from Millimeters but when I print it its to big.

这是我为它写的代码:

package frik.main;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.UIManager;

import java.awt.event.*;

import javax.swing.*;
import frik.data.Config;
import frik.utils.ImgUtil;

public class Previewer implements Config, Printable, ActionListener{

    private JFrame Frame;
    private JPanel ImagePanel;
    private JLabel PicLabel;
    private JButton PrintButton;
    private static BufferedImage before;
    private static boolean Scaled;

    public Previewer(BufferedImage Image, boolean scaled){
        this.before = Image;
        this.Scaled = scaled;
        loop();

    }

    public int print(Graphics g, PageFormat pf, int page) throws PrinterException{
        if (page > 0) { 
            return Printable.NO_SUCH_PAGE;
        }
        Graphics2D g2d = (Graphics2D)g;
        g2d.translate(pf.getImageableX(), pf.getImageableY());

        g.drawImage(0, 0, null);

        return Printable.PAGE_EXISTS;
    }

    public void actionPerformed(ActionEvent e){
        PrinterJob job = PrinterJob.getPrinterJob();
        job.setPrintable(this);
        boolean ok = job.printDialog();
        if (ok) {
            try {
                job.print();
            } catch (PrinterException ex) {
                JOptionPane.showMessageDialog(null, "The Printjob did not successfully complete.", "Print Failure.", JOptionPane.WARNING_MESSAGE);
            }
        }
    }

    public void loop(){
        UIManager.put("swing.boldMetal", Boolean.FALSE);
        Frame = new JFrame("Mold Preview");
        ImagePanel = new JPanel();
        PrintButton = new JButton("Print Mold");

        Frame.addWindowListener(new WindowAdapter() {
               public void windowClosing(WindowEvent e) {System.exit(0);}
            });

        if(Scaled){
            PicLabel = new JLabel(new ImageIcon(ImgUtil.scaleImage(PAPER_WIDTH / 3, PAPER_HEIGHT / 3, before)));
        }else if (!Scaled){
            PicLabel = new JLabel(new ImageIcon(before));
        }

        ImagePanel.setBackground(Color.orange);
        ImagePanel.add(PicLabel);
        Frame.add("Center", ImagePanel);

        PrintButton.addActionListener(this);
        Frame.add("North", PrintButton);

        Frame.pack();
        Frame.setVisible(true);
        Frame.setResizable(false);

    }

    public static void main(String args[]){
        new Previewer(before, Scaled);
        //////////////////////////////
    }
}

因此,如果有人可以根据打印机比例因子帮我缩放图像,因为我假设打印机DPI是导致这种情况,因此当打印精确到以像素为单位输入的尺寸时,图像是以毫米为单位的精确尺寸。

那会很棒。

So if someone could help me scale the image before printing it according to the printers scale factor, because I am assuming the printers DPI is causing this, so that the image is the exact size in Millimeters when printed exact to the size input in pixels.
That would be great.

推荐答案

我不确定这是否是答案本身,但它解决了我遇到的愚蠢问题之一。

I'm not sure if this is an answer per se, but it solves one of the "niggly" issues I'm having.

认为我遇到的问题你没有源DPI,所以不可能从一个上下文转换到另一个上下文。假设您有200x200的图像,这实际上意味着什么?

I think the problem I have is you don't have a source DPI, so it's not possible to convert from one context to another. Let's say you have a image of 200x200, what does that actually mean?

没有DPI,它毫无意义。如果图像是300dpi,那么我们可以使用 pixels / dpi = inches = 200/72 = 0.667英寸。然后我们可以使用英寸将其转换为像素@ 72dpi * dpi = 0.667 * 72 = 48

Without the DPI it's meaningless. If the image is 300dpi, then we could use pixels / dpi = inches = 200 / 72 = 0.667 inches. Then we can convert that to pixels @ 72dpi using inches * dpi = 0.667 * 72 = 48

现在,质疑变成了,我如何获得图像的DPI。这听起来并不像听起来那么容易......

Now, the question the becomes, how do I get the DPI of an image. That's not nearly as easy as it sounds...

import core.ui.UIUtilities;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageInputStream;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class TestDPI {

    public static final float INCH_PER_MM = 25.4f;

    public static void main(String[] args) {
        File imageFile = new File("/path/to/your/image");
        ImageInputStream iis = null;
        try {
            iis = ImageIO.createImageInputStream(imageFile);
            Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
            if (!readers.hasNext()) {
                throw new IOException("Bad format, no readers");
            }
            ImageReader reader = readers.next();
            reader.setInput(iis);
            IIOMetadata meta = reader.getImageMetadata(0);

            Node root = meta.getAsTree("javax_imageio_1.0");
            NodeList nl = root.getChildNodes();
            float horizontalPixelSize = 0;
            float verticalPixelSize = 0;
            for (int index = 0; index < nl.getLength(); index++) {
                Node child = nl.item(index);
                if ("Dimension".equals(child.getNodeName())) {
                    NodeList dnl = child.getChildNodes();
                    for (int inner = 0; inner < dnl.getLength(); inner++) {
                        child = dnl.item(inner);
                        if ("HorizontalPixelSize".equals(child.getNodeName())) {
                            horizontalPixelSize = Float.parseFloat(child.getAttributes().getNamedItem("value").getNodeValue());
                        } else if ("VerticalPixelSize".equals(child.getNodeName())) {
                            verticalPixelSize = Float.parseFloat(child.getAttributes().getNamedItem("value").getNodeValue());
                        }
                    }
                }
            }
            // As "I" understand it.  The horizontalPixelSize and verticalPixelSize
            // are the number of millimeters per pixel that should be occupied...
            System.out.println((INCH_PER_MM / horizontalPixelSize) + "x" + (INCH_PER_MM / verticalPixelSize));

        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                iis.close();
            } catch (Exception e) {
            }
        }
    }
}

使用预览示例更新

此示例基本上使用图像自身的DPI和目标DPI来生成a打印预览

This example basically uses the images own DPI and a target DPI to produce a "print preview"

我的测试图像是1667x1609 @ 300dpi

My test image is 1667x1609 @ 300dpi

300dpi测试......

300dpi test...


  • 原始尺寸= 1667x1609

  • cmSize = 14.11396110802889x13.622893474996092

  • 目标(像素)大小= 1667x1609

72dpi测试...

72dpi test...


  • 原始尺寸= 1667x1609

  • cmSize = 14.11396110802889x13.622893474996092

  • 目标(像素)尺寸= 400x386

import static core.ui.ImageUtilities.getScaleFactor;
import static core.ui.ImageUtilities.getScaleFactorToFit;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.stream.ImageInputStream;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class TestPrintPreview {

    public static void main(String[] args) {
        new TestPrintPreview();
    }

    public TestPrintPreview() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                File imageFile = new File("C:\\hold\\thumbnails\\RentAZilla-300dpi.png");

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new JScrollPane(new PreviewPane(imageFile, 300)));
                frame.setSize(400, 400);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    // The size of an A4 sheet in CMs
    public static final double[] A4_PAPER_SIZE = new double[]{21.0, 29.7};
    // The number of CMs per Inch
    public static final double CM_PER_INCH = 0.393700787d;
    // The number of Inches per CMs
    public static final double INCH_PER_CM = 2.545d;
    // The numer of Inches per mm's
    public static final double INCH_PER_MM = 25.45d;

    public class PreviewPane extends JPanel {

        private BufferedImage img;
        private float targetDPI;

        private BufferedImage gridBackground;

        public PreviewPane(File imageFile, float outputDPI) {
            // This determines the output DPI we want...
            targetDPI = outputDPI;
            try {
                // Get the DPI from the image...
                double[] imgDPI = getDPI(imageFile);
                // Read the image
                img = ImageIO.read(imageFile);

                // Output the original size...
                System.out.println("Original size = " + img.getWidth() + "x" + img.getHeight());

                // Calculate the size of the image in cm's
                double cmWidth = pixelsToCms(img.getWidth(), imgDPI[0]);
                double cmHeight = pixelsToCms(img.getHeight(), imgDPI[1]);

                System.out.println("cmSize = " + cmWidth + "x" + cmHeight);

                // Calculate the new image size based on the target DPI and
                // the cm size of the image...
                int imgWidth = (int) Math.round(cmsToPixel(cmWidth, targetDPI));
                int imgHeight = (int) Math.round(cmsToPixel(cmHeight, targetDPI));
                System.out.println("Target size = " + imgWidth + "x" + imgHeight);

                // Create a scaled instance of the image to fit within the 
                // target boundries
                img = getScaledInstanceToFit(img, new Dimension(imgWidth, imgHeight));

            } catch (IOException ex) {
                Logger.getLogger(TestPrintPreview.class.getName()).log(Level.SEVERE, null, ex);
            }
            setBackground(Color.WHITE);
        }

        @Override
        public Dimension getPreferredSize() {
            // Return the size of the component based on the size of 
            // an A4 sheet of paper and the target DPI
            return new Dimension(
                    (int) Math.round(cmsToPixel(A4_PAPER_SIZE[0], targetDPI)),
                    (int) Math.round(cmsToPixel(A4_PAPER_SIZE[1], targetDPI)));
        }

        /**
         * Generates a grid of 1x1 cm cells.  This is used to allow you
         * to compare the differences of different DPI and ensure that the
         * output is what you are expecting...
         * @return 
         */
        protected BufferedImage getGridBackground() {
            if (gridBackground == null) {
                // Calculate the width and height we need...
                int width = (int) Math.round(cmsToPixel(A4_PAPER_SIZE[0], targetDPI));
                int height = (int) Math.round(cmsToPixel(A4_PAPER_SIZE[1], targetDPI));

                // Create the grid...
                gridBackground = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
                Graphics2D g2d = gridBackground.createGraphics();
                // Calculate the size of each cell (1cm square)
                double cmAsPixel = cmsToPixel(1, targetDPI);
                float xPos = 0;
                float yPos = 0;
                g2d.setColor(new Color(225, 0, 0, 128));
                int count = 0;
                Font font = g2d.getFont();
                g2d.setFont(font.deriveFont(8f));
                FontMetrics fm = g2d.getFontMetrics();
                // Draw the horizontal lines
                while (xPos < gridBackground.getWidth()) {
                    g2d.draw(new Line2D.Float(xPos, 0, xPos, gridBackground.getHeight()));
                    // Add the text markers...
                    String text = (count++) + "cm";
                    float x = xPos - fm.stringWidth(text);
                    g2d.drawString(text, x, fm.getAscent());
                    xPos += cmAsPixel;
                }
                // Draw the vertical lines
                count = 0;
                while (yPos < gridBackground.getHeight()) {
                    g2d.draw(new Line2D.Float(0, yPos, gridBackground.getWidth(), yPos));
                    // Add the text markers
                    String text = (count++) + "cm";
                    float y = (yPos - fm.getHeight()) + fm.getAscent();
                    g2d.drawString(text, 0, y);
                    yPos += cmAsPixel;
                }
                g2d.dispose();
            }
            return gridBackground;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            // Paint the image...
            g2d.drawImage(img, 0, 0, this);
            // Paint the grid...
            g2d.drawImage(getGridBackground(), 0, 0, this);
            g2d.dispose();
        }
    }

    /**
     * Converts the given pixels to cm's based on the supplied DPI
     * @param pixels
     * @param dpi
     * @return 
     */
    public static double pixelsToCms(double pixels, double dpi) {
        return inchesToCms(pixels / dpi);
    }

    /**
     * Converts the given cm's to pixels based on the supplied DPI
     * @param cms
     * @param dpi
     * @return 
     */
    public static double cmsToPixel(double cms, double dpi) {
        return cmToInches(cms) * dpi;
    }

    /**
     * Converts the given cm's to inches
     * @param cms
     * @return 
     */
    public static double cmToInches(double cms) {
        return cms * CM_PER_INCH;
    }

    /**
     * Converts the given inches to cm's 
     * @param inch
     * @return 
     */
    public static double inchesToCms(double inch) {
        return inch * INCH_PER_CM;
    }

    /**
     * Gets the DPI for the specified image.  This does return the horizontal
     * and vertical DPI, but you could conceivably use just use one of the values
     * @param imageFile
     * @return
     * @throws IOException 
     */
    public double[] getDPI(File imageFile) throws IOException {

        double[] dpi = new double[]{72, 72};

        ImageInputStream iis = null;
        try {
            iis = ImageIO.createImageInputStream(imageFile);
            Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
            if (!readers.hasNext()) {
                throw new IOException("Bad format, no readers");
            }
            ImageReader reader = readers.next();
            reader.setInput(iis);
            IIOMetadata meta = reader.getImageMetadata(0);

            Node root = meta.getAsTree("javax_imageio_1.0");
            NodeList nl = root.getChildNodes();
            float horizontalPixelSize = 0;
            float verticalPixelSize = 0;
            for (int index = 0; index < nl.getLength(); index++) {
                Node child = nl.item(index);
                if ("Dimension".equals(child.getNodeName())) {
                    NodeList dnl = child.getChildNodes();
                    for (int inner = 0; inner < dnl.getLength(); inner++) {
                        child = dnl.item(inner);
                        if ("HorizontalPixelSize".equals(child.getNodeName())) {
                            horizontalPixelSize = Float.parseFloat(child.getAttributes().getNamedItem("value").getNodeValue());
                        } else if ("VerticalPixelSize".equals(child.getNodeName())) {
                            verticalPixelSize = Float.parseFloat(child.getAttributes().getNamedItem("value").getNodeValue());
                        }
                    }
                }
            }

            dpi = new double[]{(INCH_PER_MM / horizontalPixelSize), (INCH_PER_MM / verticalPixelSize)};
        } finally {
            try {
                iis.close();
            } catch (Exception e) {
            }
        }

        return dpi;
    }

    /**
     * Returns a scaled instance of the image to fit within the specified 
     * area.  This means that the image is guaranteed to be <= size.width and
     * <= size.height
     * @param img
     * @param size
     * @return 
     */
    public static BufferedImage getScaledInstanceToFit(BufferedImage img, Dimension size) {
        double scaleFactor = getScaleFactorToFit(img, size);
        return getScaledInstance(img, scaleFactor);
    }

    public static double getScaleFactorToFit(BufferedImage img, Dimension size) {

        double dScale = 1;
        if (img != null) {
            int imageWidth = img.getWidth();
            int imageHeight = img.getHeight();

            dScale = getScaleFactorToFit(new Dimension(imageWidth, imageHeight), size);
        }

        return dScale;

    }

    /**
     * Returns the required scale factor to fit the original size into the toFit
     * size.
     * @param original
     * @param toFit
     * @return 
     */
    public static double getScaleFactorToFit(Dimension original, Dimension toFit) {

        double dScale = 1d;
        if (original != null && toFit != null) {
            double dScaleWidth = getScaleFactor(original.width, toFit.width);
            double dScaleHeight = getScaleFactor(original.height, toFit.height);

            dScale = Math.min(dScaleHeight, dScaleWidth);
        }

        return dScale;

    }

    /**
     * Returns the scale factor required to go from the master size to the 
     * target size
     * @param iMasterSize
     * @param iTargetSize
     * @return 
     */
    public static double getScaleFactor(int iMasterSize, int iTargetSize) {
        return (double) iTargetSize / (double) iMasterSize;
    }

    /**
     * Returns a scaled instance of the image based on the supplied scale factor.
     * 
     * The images width and height are multiplied by the supplied scale factor
     * @param img
     * @param dScaleFactor
     * @return 
     */
    protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {
        BufferedImage imgScale = img;

        int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor);
        int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor);

        if (dScaleFactor <= 1.0d) {
            imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight);
        } else {
            imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight);
        }
        return imgScale;
    }

    /**
     * Scales the specified image down to be less then equal to the target width
     * and height.
     * 
     * The image is scaled using a divide an conquer approach to provide
     * the best scaling possible
     * @param img
     * @param targetWidth
     * @param targetHeight
     * @return 
     */
    protected static BufferedImage getScaledDownInstance(BufferedImage img,
            int targetWidth,
            int targetHeight) {

        int type = (img.getTransparency() == Transparency.OPAQUE)
                ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;

        BufferedImage ret = (BufferedImage) img;

        if (targetHeight > 0 || targetWidth > 0) {
            int w, h;
            w = img.getWidth();
            h = img.getHeight();

            do {
                if (w > targetWidth) {
                    w /= 2;
                    if (w < targetWidth) {
                        w = targetWidth;
                    }
                }

                if (h > targetHeight) {
                    h /= 2;
                    if (h < targetHeight) {
                        h = targetHeight;
                    }
                }

                BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
                Graphics2D g2 = tmp.createGraphics();
                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                g2.drawImage(ret, 0, 0, w, h, null);
                g2.dispose();

                ret = tmp;
            } while (w != targetWidth || h != targetHeight);
        } else {
            ret = new BufferedImage(1, 1, type);
        }

        return ret;

    }

    /**
    /**
     * Scales the specified image up
     * 
     * The image is scaled using a divide an conquer approach to provide
     * the best scaling possible
     * @param img
     * @param targetWidth
     * @param targetHeight
     * @return 
     */
    protected static BufferedImage getScaledUpInstance(BufferedImage img,
            int targetWidth,
            int targetHeight) {

        int type = BufferedImage.TYPE_INT_ARGB;

        BufferedImage ret = (BufferedImage) img;
        int w, h;
        w = img.getWidth();
        h = img.getHeight();

        do {
            if (w < targetWidth) {
                w *= 2;
                if (w > targetWidth) {
                    w = targetWidth;
                }
            }

            if (h < targetHeight) {
                h *= 2;
                if (h > targetHeight) {
                    h = targetHeight;
                }
            }

            BufferedImage tmp = new BufferedImage(w, h, type);
            Graphics2D g2 = tmp.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2.drawImage(ret, 0, 0, w, h, null);
            g2.dispose();

            ret = tmp;
            tmp = null;
        } while (w != targetWidth || h != targetHeight);
        return ret;
    }
}

这篇关于可打印的打印BufferedImage大小不正确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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