Java设置图像的分辨率和打印尺寸

4
我写了一个程序,生成了一张BufferedImage用于显示和打印。图像的一部分包括1像素宽的网格线,即每条线之间有大约10个像素。由于屏幕分辨率的原因,该图像显示得比实际更大,每条线都有几个像素。我想把它画得更小一些,但是当我缩放图像(使用Image.getScaledInstance或Graphics2D.scale)时,会失去很多细节。
我也想打印这张图片,并且面临着同样的问题。在这种情况下,我使用以下代码设置分辨率:
HashPrintRequestAttributeSet set = new HashPrintRequestAttributeSet();
PrinterResolution pr = new PrinterResolution(250, 250, ResolutionSyntax.DPI);
set.add(pr);
job.print(set);

这段代码使用了技术来缩小图像而不会丢失细节。但问题是,图像被裁剪在与设定分辨率相同的边界处。同时让我感到困惑的是,我原本期待更高的DPI数值能够生成更小的图像,但实际情况则恰恰相反。

我正在使用 Windows 7 上的 Java 1.6 和 Eclipse。

5个回答

3

关于图像在页面边界被裁剪的问题,你是否检查了图形的剪辑区域?我的意思是尝试:

System.out.println(graphics.getClipBounds());

确保其已正确设置。


1
我有同样的问题。这是我的解决方案。
首先更改打印作业的分辨率...
    PrinterJob job = PrinterJob.getPrinterJob();
    // Create the paper size of our preference
    double cmPx300 = 300.0 / 2.54;
    Paper paper = new Paper();
    paper.setSize(21.3 * cmPx300, 29.7 * cmPx300);
    paper.setImageableArea(0, 0, 21.3 * cmPx300, 29.7 * cmPx300);
    PageFormat format = new PageFormat();
    format.setPaper(paper);
    // Assign a new print renderer and the paper size of our choice !
    job.setPrintable(new PrintReport(), format);

    if (job.printDialog()) {
        try {
            HashPrintRequestAttributeSet set = new HashPrintRequestAttributeSet();
            PrinterResolution pr = new PrinterResolution((int) (dpi), (int) (dpi), ResolutionSyntax.DPI);
            set.add(pr);
            job.setJobName("Jobname");
            job.print(set);
        } catch (PrinterException e) {
        }
    }

现在,您可以像这样将您喜欢的任何东西绘制到新的高分辨率纸张上!
    public class PrintReport implements Printable {

    @Override
    public int print(Graphics g, PageFormat pf, int page) throws PrinterException {
        // Convert pixels to cm to lay yor page easy on the paper...
        double cmPx = dpi / 2.54;
        Graphics2D g2 = (Graphics2D) g;
        int totalPages = 2; // calculate the total pages you have...
        if (page < totalPages) {

            // Draw Page Header
            try {
                BufferedImage image = ImageIO.read(ClassLoader.getSystemResource(imgFolder + "largeImage.png"));
                g2.drawImage(image.getScaledInstance((int) (4.8 * cmPx), -1, BufferedImage.SCALE_SMOOTH), (int) (cmPx),
                        (int) (cmPx), null);
            } catch (IOException e) {
            }
            // Draw your page as you like...
            // End of Page
            return PAGE_EXISTS;
        } else {
            return NO_SUCH_PAGE;
        }
    }

0

使用Java编写代码,将带有尺寸的图像转换并打印出来。

类:ConvertImageWithDimensionsAndPrint.java

package com.test.convert;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;

public class ConvertImageWithDimensionsAndPrint {
    private static final int IMAGE_WIDTH = 800;
    private static final int IMAGE_HEIGHT = 1000;

public static void main(String[] args) {
    try {
        String sourceDir = "C:/Images/04-Request-Headers_1.png";
        File sourceFile = new File(sourceDir);
        String destinationDir = "C:/Images/ConvertedImages/";//Converted images save here
        File destinationFile = new File(destinationDir);
        if (!destinationFile.exists()) {
            destinationFile.mkdir();
        }
        if (sourceFile.exists()) {
            String fileName = sourceFile.getName().replace(".png", "");
            BufferedImage bufferedImage = ImageIO.read(sourceFile);
            int type = bufferedImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : bufferedImage.getType();

            BufferedImage resizedImage = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, type);
            Graphics2D graphics2d = resizedImage.createGraphics();
            graphics2d.drawImage(bufferedImage, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);//resize goes here
            graphics2d.dispose();

            ImageIO.write(resizedImage, "png", new File( destinationDir + fileName +".png" ));

            int oldImageWidth = bufferedImage.getWidth();
            int oldImageHeight = bufferedImage.getHeight();
            System.out.println(sourceFile.getName() +" OldFile with Dimensions: "+ oldImageWidth +"x"+ oldImageHeight);
            System.out.println(sourceFile.getName() +" ConvertedFile converted with Dimensions: "+ IMAGE_WIDTH +"x"+ IMAGE_HEIGHT);

            //Print the image file
            PrintActionListener printActionListener = new PrintActionListener(resizedImage);
            printActionListener.run();
        } else {
            System.err.println(destinationFile.getName() +" File not exists");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
}

PrintActionListener.java的参考资料

package com.test.convert;

import java.awt.Graphics;
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;

public class PrintActionListener implements Runnable {

private BufferedImage image;

public PrintActionListener(BufferedImage image) {
    this.image = image;
}

@Override
public void run() {
    PrinterJob printJob = PrinterJob.getPrinterJob();
    printJob.setPrintable(new ImagePrintable(printJob, image));

    if (printJob.printDialog()) {
        try {
            printJob.print();
        } catch (PrinterException prt) {
            prt.printStackTrace();
        }
    }
}

public class ImagePrintable implements Printable {

    private double x, y, width;

    private int orientation;

    private BufferedImage image;

    public ImagePrintable(PrinterJob printJob, BufferedImage image) {
        PageFormat pageFormat = printJob.defaultPage();
        this.x = pageFormat.getImageableX();
        this.y = pageFormat.getImageableY();
        this.width = pageFormat.getImageableWidth();
        this.orientation = pageFormat.getOrientation();
        this.image = image;
    }

    @Override
    public int print(Graphics g, PageFormat pageFormat, int pageIndex) throws PrinterException {
        if (pageIndex == 0) {
            int pWidth = 0;
            int pHeight = 0;
            if (orientation == PageFormat.PORTRAIT) {
                pWidth = (int) Math.min(width, (double) image.getWidth());
                pHeight = pWidth * image.getHeight() / image.getWidth();
            } else {
                pHeight = (int) Math.min(width, (double) image.getHeight());
                pWidth = pHeight * image.getWidth() / image.getHeight();
            }
            g.drawImage(image, (int) x, (int) y, pWidth, pHeight, null);
            return PAGE_EXISTS;
        } else {
            return NO_SUCH_PAGE;
        }
    }

}

}

输出:

04-Request-Headers_1.png OldFile with Dimensions: 1224x1584
04-Request-Headers_1.png ConvertedFile converted with Dimensions: 800x1000

在图像转换后,将打开一个打印窗口以打印转换后的图像。该窗口显示如下,从名称下拉菜单中选择打印机,然后单击确定按钮。

Print Window


0

看起来你的问题是你将网格线作为 BufferedImage 的一部分,当缩放时看起来不太好。为什么不在绘制完图像后使用 drawLine() 来生成网格呢?


我不确定你具体在暗示什么。也许我应该缩放图像,然后再画线?我不想缩放图像或线条,我的屏幕和打印机都有足够的DPI来显示所有细节。我提到了线条,但还有很多小的(10像素正方形)图标,如果我缩小一半,它们就变得模糊不清。我感到困惑的是这不是件容易的事情(假定这很容易,只是我不知道如何做)。 - Ingrid
Printable提供了一个Graphics2D对象:public int print(Graphics g, PageFormat pf, int page)。不要将您的页面呈现为巨大的像素化图像,而是将其呈现为矢量图形调用:例如多个g.drawLine()g.drawImage()调用。 - Justin
我会试一下看看效果如何。如果我理解正确的话,这只是让较少详细信息的显示看起来更好而已。难道没有办法显示和打印出所有的细节吗? - Ingrid
你只能打印图像中本来就有的细节。这将为线条元素添加无限的细节。如果单个图标比您的巨型BufferedImage的分辨率具有更多的细节,这也将解决该问题。 - Justin
感谢您的耐心等待!我对屏幕显示有误解。您是正确的,它只是显示我要求的内容,没有办法使它更小而不失去细节。但是我仍然无法打印我想要的细节。我将我想要的所有细节都放到了原始图像中。在打印时,每个像素使用多个点进行打印,导致打印出来的图像非常大。我可以使用PrinterResolution来使其缩小而不会丢失细节,但如果我没有设置分辨率,图像将被切断在页面边界处。 - Ingrid
搞定了!我需要使用Pageable而不是Printable。这样,我可以设置纸张大小,并将setImageableArea设置为比纸张大。这样,当我使用PrinterResolution时,它就不会切掉我的图像。 - Ingrid

-1

您可以使用以下任一方法来提高缩放的质量。我相信双三次插值法可以获得更好的结果,但速度比双线性插值法慢。

g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

我也不会使用Image.getScaledInstance(),因为它非常慢。至于打印方面,我也在处理类似的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接