gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 07:14:29 25 4
gpt4 key购买 nike

是的,我在这里尝试打印一个 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,因此无法从一个上下文转换为另一个上下文。假设您有一张 200x200 的图片,这究竟意味着什么?

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

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

300dpi 测试...

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

enter image description here

72dpi 测试...

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

enter image description here

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

关于java - 可打印的 BufferedImage 大小不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18460008/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com