2013-08-27 4 views
1

Так что я пытаюсь здесь напечатать BufferedImage, все работает отлично, пока вы не увидите результат. Результат - большой, печать крупная и не масштабирует все при печати по какой-то причине. Я использовал ((MM * DPI)/25,4), чтобы рассчитать правильную длину пикселя в соответствии с размером бумаги от миллиметров, но когда я распечатаю его на большой.Версия для печати BufferedImage с неправильным размером

Это код, который я написал для него:

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 является причиной этого, так что изображение будет точным размером в миллиметрах при печати с точностью до размера ввода в пикселях.
Это было бы здорово.

+0

Я не уверен, что вы расчет имеет смысл '((ММ * DPI) /25.4)' DPI должно быть «Dots Per Inch "... – MadProgrammer

+1

Проверьте [этот пример] (http: // stackoverflow.com/questions/13993692/how-to-produ-physical-dimension-of-the-image-draw-using-java/14000933 # 14000933) для вычисления Cm в пикселях, [этот пример] (http: // stackoverflow .com/questions/12173515/fit-image-in-the-printing-area/12174371 # 12174371) для установки изображения в область для печати и [этот пример] (http://stackoverflow.com/questions/17904518/fit -scale-jcomponent-to-page-being-printing/17961911 # 17961911) для установки компонента в область для печати ... – MadProgrammer

+0

Ну, например, Photoshop использует это, чтобы масштабировать ваш холст. Допустим, вы хотите, чтобы вы сделали холст 11,5 см, вы получите 325,98px (11,5 * 72 (стандартный dpi))/2,54 = 325,98. Миллиметры предназначены только для клиентов. Но результат для фотошопа, конечно же, будет зависеть от используемых вами dpi. –

ответ

3

Я не уверен, если это ответ на скажу, но он решает один из «niggly» вопросы, которые я имею ...

я «думает» проблема у меня есть, вы не» t есть источник DPI, поэтому невозможно преобразовать из одного контекста в другой ... Предположим, у вас есть образ 200x200, что это значит?

Без ДОИ это бессмысленно. Если изображение составляет 300 точек на дюйм, мы можем использовать pixels/dpi = inches = 200/72 = 0.667 inches. Затем мы можем преобразовать это в пикселы с помощью 72dpi, используя inches * dpi = 0.667 * 72 = 48

Теперь вопрос становится, как мне получить 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
  • Target (пиксел) Размер = 1667x1609

enter image description here

72dpi тест ...

  • Оригинальный размер = 1667x1609
  • cmSize = 14.11396110802889x13.622893474996092
  • Target (пиксел) размер = 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; 
    } 
} 
Смежные вопросы