使用Java在4 x 6纸张上打印1800 x 1200图像

Ita*_*iha 6 java printing awt

我需要在4"x 6"纸(也称为4r)上打印1800 x 1200像素,300 dpi图像

我试过了什么

我创建了一个PrintRequestAttributeSet这需要照顾我的PrintableArea(4×6) ,.Printer print DPI Orientation我在底部贴了一个MCVE.

问题

虽然代码有效,但我得到了PageFormat以下属性(对于我的打印机):

x= 12.0
y= 12.32
w= 276.0
h= 419.67
Run Code Online (Sandbox Code Playgroud)

宽度和高度都少,因为我的打印机不支持Zero Margin.(这是我考虑过的.如果有人知道除此之外我可以强迫零利润的方式,请告诉我)

我正在提供margin as 0,因为这些图像将通过支持零保证金的打印机打印(Photobooth打印机).

aset.add(new MediaPrintableArea(0, 0, 4, 6, MediaPrintableArea.INCH));
Run Code Online (Sandbox Code Playgroud)

包括边距的可打印区域大约为4 x 6.当我缩放图像以在可打印区域内打印时,会出现问题.

由于图像为1800 x 1200,因此它支持3:2的宽高比,这意味着创建的图像可以在4 x 6纸张上打印(旋转和缩放后).以供参考.

现在,由于PageFormatImageWidth和ImageHeight 的pageWidth和pageHeight 不能完全整除.我正在解决扩展问题.

注意:我旋转图像是因为它必须以4 x 6而不是6 x 4打印.

应该占据4 x 6空间的图像占用接近4 x 5的图像.图像尺寸也大大减小.

我该如何克服这个问题?

请在这里找到MCVE:

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.print.attribute.standard.OrientationRequested;
import javax.print.attribute.standard.PrintQuality;
import javax.print.attribute.standard.PrinterResolution;

public class ImgPrinter implements Printable {

    Image img;

    @Override
    public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
            throws PrinterException {

        Graphics2D g2d = (Graphics2D) graphics;
        g2d.translate((int) (pageFormat.getImageableX()),
                (int) (pageFormat.getImageableY()));
        if (pageIndex == 0) {
            double pageWidth = pageFormat.getImageableWidth();
            double pageHeight = pageFormat.getImageableHeight();
            /**
             * Swapping width and height, coz the image is later rotated
             */
            double imageWidth = img.getHeight(null);
            double imageHeight = img.getWidth(null);
            double scaleX = pageWidth / imageWidth;
            double scaleY = pageHeight / imageHeight;
            g2d.scale(scaleX, scaleY);
            g2d.rotate(Math.toRadians(90), img.getWidth(null) / 2,
                    img.getHeight(null) / 2);
            g2d.drawImage(img, 0, 0, null);
            return Printable.PAGE_EXISTS;
        }
        return Printable.NO_SUCH_PAGE;

    }

    public void printPage(String file, String size) {
        try {
            Image img = ImageIO.read(new File(file));
            this.img = img;
            PrintRequestAttributeSet aset = createAsetForMedia(size);
            PrinterJob pj = PrinterJob.getPrinterJob();
            PageFormat pageFormat = pj.getPageFormat(aset);
            pj.setPrintable(this, pageFormat);
            pj.print();
        } catch (PrinterException ex) {
            ex.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private PrintRequestAttributeSet createAsetForMedia(String size) {
        PrintRequestAttributeSet aset = null;
        try {
            aset = new HashPrintRequestAttributeSet();
            aset.add(PrintQuality.NORMAL);
            aset.add(OrientationRequested.PORTRAIT);
            /**
             * Suggesting the print DPI as 300
             */
            aset.add(new PrinterResolution(300, 300, PrinterResolution.DPI));
            /**
             * Setting the printable area and the margin as 0
             */
            if (size.equals("3r")) {
                aset.add(new MediaPrintableArea(0, 0, 3, 5,
                        MediaPrintableArea.INCH));
            } else if (size.equals("4r")) {
                aset.add(new MediaPrintableArea(0, 0, 4, 6,
                        MediaPrintableArea.INCH));
            } else if (size.equals("5r")) {
                aset.add(new MediaPrintableArea(0, 0, 5, 7,
                        MediaPrintableArea.INCH));
            } else if (size.equals("6r")) {
                aset.add(new MediaPrintableArea(0, 0, 6, 8,
                        MediaPrintableArea.INCH));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return aset;

    }

    public static void main(String[] args) {
        new ImgPrinter().printPage("/Some_URL/sam.jpg",
                "4r");
    }
}
Run Code Online (Sandbox Code Playgroud)

要运行该程序,只需为主程序提供1800x1200图像路径,它将打印到默认打印机.

Mad*_*mer 1

让我担心的事情...

  1. 更改上下文的缩放/旋转,Graphics而无需先复制它或在事后重置它。这实际上可能会影响后续的渲染,因为printable可能会被多次调用......
  2. 使用Graphics2D#scale。这确实不是最好的质量,通常也不是那么快。请参阅Image.getScaledInstance() 的危险。我也更喜欢使用AffineTransform,但这只是我......
  3. 不缓冲结果。好的,这与之前的评论有关,但是您的print方法可能会被多次调用来打印单个页面,每次缩放图像的成本很高,相反,您应该缩放一次并重新使用缩放后的结果。
  4. 除非您要物理旋转图像,否则您可能想要围绕页面中心旋转,而不是图像本身,这将影响变为的位置0x0
  5. 现在请记住,当您旋转上下文时Graphics,原点会发生变化,因此在这种情况下,它将变为顶/右上角,而不是位于顶/左上角。现在你知道为什么我会单独旋转图像而不是尝试弄乱上下文Graphics:P

我“认为”正在发生的是,在坐标的缩放、旋转和操作(交换高度和宽度)之间,事情变得很糟糕……但坦率地说,当我有更好的解决方案...

下面的示例使用了一堆个人库代码,因此其中一些代码可能有点复杂,但我将单独的功能用于其他事情,因此它可以很好地结合在一起......

因此,从 7680x4800 的图像开始,这会生成 423x264 的缩放图像

可打印

(红色边框仅供视觉参考,在将结果转储为 PDF 以节省纸张时使用;))

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.geom.AffineTransform;
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 java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.print.attribute.standard.OrientationRequested;
import javax.print.attribute.standard.PrintQuality;
import javax.print.attribute.standard.PrinterResolution;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ImgPrinter implements Printable {

    BufferedImage img;
    BufferedImage scaled;

    @Override
    public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
            throws PrinterException {

        int result = NO_SUCH_PAGE;
        Graphics2D g2d = (Graphics2D) graphics.create();
        g2d.translate((int) (pageFormat.getImageableX()), (int) (pageFormat.getImageableY()));
        if (pageIndex == 0) {
            double pageWidth = pageFormat.getImageableWidth();
            double pageHeight = pageFormat.getImageableHeight();
            if (scaled == null) {
                // Swap the width and height to allow for the rotation...
                System.out.println(pageWidth + "x" + pageHeight);
                scaled = getScaledInstanceToFit(
                        img, 
                        new Dimension((int)pageHeight, (int)pageWidth));
                System.out.println("In " + img.getWidth() + "x" + img.getHeight());
                System.out.println("Out " + scaled.getWidth() + "x" + scaled.getHeight());
            }
            double imageWidth = scaled.getWidth();
            double imageHeight = scaled.getHeight();

            AffineTransform at = AffineTransform.getRotateInstance(
                    Math.toRadians(90), 
                    pageWidth / 2d, 
                    pageHeight / 2d
            );

            AffineTransform old = g2d.getTransform();
            g2d.setTransform(at);
            double x = (pageHeight - imageWidth) / 2d;
            double y = (pageWidth - imageHeight) / 2d;
            g2d.drawImage(
                    scaled, 
                    (int)x, 
                    (int)y, 
                    null);

            g2d.setTransform(old);

            // This is not affected by the previous changes, as those were made
            // to a different copy...
            g2d.setColor(Color.RED);
            g2d.drawRect(0, 0, (int)pageWidth - 1, (int)pageHeight - 1);
            result = PAGE_EXISTS;
        }
        g2d.dispose();

        return result;
    }

    public void printPage(String file, String size) {
        try {
            img = ImageIO.read(new File(file));
            PrintRequestAttributeSet aset = createAsetForMedia(size);
            PrinterJob pj = PrinterJob.getPrinterJob();
            PageFormat pageFormat = pj.getPageFormat(aset);
            pj.setPrintable(this, pageFormat);
            if (pj.printDialog()) {
                pj.print();
            }
        } catch (PrinterException ex) {
            ex.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private PrintRequestAttributeSet createAsetForMedia(String size) {
        PrintRequestAttributeSet aset = null;
        try {
            aset = new HashPrintRequestAttributeSet();
            aset.add(PrintQuality.NORMAL);
            aset.add(OrientationRequested.PORTRAIT);
            /**
             * Suggesting the print DPI as 300
             */
            aset.add(new PrinterResolution(300, 300, PrinterResolution.DPI));
            /**
             * Setting the printable area and the margin as 0
             */
            if (size.equals("3r")) {
                aset.add(new MediaPrintableArea(1, 1, 3, 5,
                        MediaPrintableArea.INCH));
            } else if (size.equals("4r")) {
                aset.add(new MediaPrintableArea(1, 1, 4, 6,
                        MediaPrintableArea.INCH));
            } else if (size.equals("5r")) {
                aset.add(new MediaPrintableArea(1, 1, 5, 7,
                        MediaPrintableArea.INCH));
            } else if (size.equals("6r")) {
                aset.add(new MediaPrintableArea(1, 1, 6, 8,
                        MediaPrintableArea.INCH));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return aset;

    }

    public static BufferedImage getScaledInstanceToFit(BufferedImage img, Dimension size) {

        double scaleFactor = getScaleFactorToFit(img, size);

        return getScaledInstance(img, scaleFactor);

    }

    public static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {

        return getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

    }

    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;

    }

    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;

    }

    public static double getScaleFactor(int iMasterSize, int iTargetSize) {

        return (double) iTargetSize / (double) iMasterSize;

    }

    protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint) {

        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, hint);

        } else {

            imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight, hint);

        }

        return imgScale;

    }

    protected static BufferedImage getScaledDownInstance(BufferedImage img,
            int targetWidth,
            int targetHeight,
            Object hint) {

//      System.out.println("Scale down...");
        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 = img.getWidth();
            int 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, hint);
                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;

    }

    protected static BufferedImage getScaledUpInstance(BufferedImage img,
            int targetWidth,
            int targetHeight,
            Object hint) {

        int type = BufferedImage.TYPE_INT_ARGB;

        BufferedImage ret = (BufferedImage) img;
        int w = img.getWidth();
        int 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, hint);
            g2.drawImage(ret, 0, 0, w, h, null);
            g2.dispose();

            ret = tmp;
            tmp = null;

        } while (w != targetWidth || h != targetHeight);

        return ret;

    }


    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                new ImgPrinter().printPage("/Volumes/Disk02/Dropbox/Wallpapers/animepaper.net_wallpaper_art_anime_aria_duanwu_festival_205050_wonderngo_7680x4800-a8aecc9c.jpg",
                        "4r");
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

你知道什么会更容易,以横向模式打印页面并以 :P 开头