可打印的打印BufferedImage大小不正确

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

这是我为它写的代码:

 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导致这种情况,因此当打印精确到以像素为单位输入的大小时,图像的精确尺寸以毫米为单位。
那太好了。

我不确定这本身是否是一个答案,但它解决了我遇到的一个“琐碎”的问题。

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

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

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

 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 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来产生“打印预览”

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

300dpi测试......

  • 原始尺寸= 1667x1609
  • cmSize = 14.11396110802889x13.622893474996092
  • 目标(像素)大小= 1667x1609

在此处输入图像描述

72dpi测试......

  • 原始尺寸= 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 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; } }