2014-12-03 30 views
6

ho bisogno di stampare un 1800 x 1200 pixel, 300 immagine dpi su 4" x 6" carta (noto anche come 4r)Stampa di un'immagine di 1800 x 1200 4 x 6 carta utilizzando Java

Quello che ho provato

ho creato un PrintRequestAttributeSet che si prende cura della mia PrintableArea (4 x 6), Printer print DPI, Orientation. Ho allegato un MCVE in basso.

Problema

Mentre il codice funziona, e ho un PageFormat con i seguenti attributi (per la mia stampante):

x= 12.0 
y= 12.32 
w= 276.0 
h= 419.67 

La larghezza e l'altezza sono poco meno, perché la mia stampante doesn non supportare Zero Margin. (Questo è quello che ho preso in considerazione. Se qualcuno è a conoscenza di un modo diverso da questo attraverso il quale posso forzare margine pari a zero, per favore fatemelo sapere)

sto fornendo il margin as 0, perché queste immagini verranno stampate tramite stampanti che supportano margine zero (stampanti Photobooth).

aset.add(new MediaPrintableArea(0, 0, 4, 6, MediaPrintableArea.INCH)); 

L'area di stampa incluso il margine è di circa 4 x 6 secondo necessità. Il problema si verifica quando scala l'immagine per stampare all'interno dell'area stampabile.

Poiché l'immagine è 1800 x 1200, supporta un rapporto aspetto di 3: 2, che significa che l'immagine viene creata per essere stampata su una carta 4 x 6 (dopo essere stata ruotata e ridimensionata). For Reference.

Ora, poiché la larghezza della pagina e il peso di pagina dello PageFormat non sono esattamente divisibili da ImageWidth e ImageHeight. Sto riscontrando problemi di ridimensionamento.

Nota: Ho ruotare l'immagine perché deve essere stampato su 4 x 6 e non 6 x 4.

L'immagine che dovrebbe prendere 4 x 6 spazio sta prendendo da qualche parte vicino a 4 x 5. Anche la dimensione dell'immagine viene ridotta drasticamente.

Come si supera questo problema?

Codice

Si prega di trovare il MCVE qui:

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

Per eseguire il programma, è sufficiente fornire un percorso di immagine 1800x1200 al programma principale e sarà stampare sulla stampante predefinita.

+0

carico JPG a BufferedImage, per scalare la risoluzione desiderata, ImageIO.write, poi per stampare direttamente una nuova immagine – mKorbel

+0

nota dato che l'utilizzo di scaledInstance è piuttosto asincrono, ho provato a ridimensionare l'immagine convertendola in BufferImage. – mKorbel

+0

Ho passato la nuova larghezza come '4 * 72 = 288' e altezza come' 6 * 72 = 432' (dato che tutto è 72dpi in java). Ma l'immagine viene distorta. Stampa un'immagine di 3,7 x 4 e utilizza un'area stampabile di 4 x 5,2. Anche la qualità di stampa è stata drasticamente ridotta. [Il collegamento al codice modificato] (http://pastie.org/9758244). Non sono sicuro, se sto utilizzando il processo corretto per convertire e tornare a BufferedImage in Immagine. – ItachiUchiha

risposta

1

Le cose che mi preoccupano ...

  1. Hanging scala/rotazione del Graphics contesto senza né prima facendo una copia o ripristino dopo il fatto. Ciò potrebbe effettivamente influire sui rendering successivi, poiché printable può essere chiamato più volte ...
  2. Utilizzo di Graphics2D#scale. Questo in realtà non è la migliore qualità né è generalmente così veloce. Vedi The Perils of Image.getScaledInstance(). Preferisco anche usare AffineTransform, ma questo è solo io ...
  3. Non bufferizzare il risultato. Ok, questo si riferisce al commento precedente, ma il tuo metodo print può essere chiamato più volte per stampare una singola pagina, ridimensionando l'immagine ogni volta è costoso, invece, dovresti ridimensionarla una volta e riutilizzare il risultato scalato.
  4. A meno che non si desideri ruotare fisicamente l'immagine, è probabile che si desideri ruotare attorno al centro della pagina, non sull'immagine stessa, ciò influirà sulla posizione in cui diventa 0x0.
  5. Ora, quando si ruota il contesto Graphics, il punto di origine cambia, quindi, invece di essere nell'angolo in alto a sinistra, in questo caso diventerà l'angolo in alto a destra. E ora sapete perché avrei ruotato l'immagine in isolamento e non provato nei guai con la Graphics contesto: P

Quello che "penso" che sta accadendo è che tra il ridimensionamento, rotazione e manipolazioni delle coordinate (scambiando l'altezza e la larghezza), le cose si stanno fottendo ... ma francamente, non avrei intenzione di scherzare con esso quando ho soluzioni migliori ...

L'esempio seguente fa uso di un gruppo di librerie personali codice, quindi alcuni potrebbero essere un po 'contorti, ma io uso la funzionalità separata per altre cose, quindi si lega bene insieme ...

Così, a partire da un'immagine di 7680x4800, questo genera un'immagine in scala di 423x264

Printable

(il bordo rosso sono solo guide visive, utilizzati quando il dumping il risultato in PDF per risparmiare carta;))

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

sai cosa sarebbe molto più semplice, la stampa della pagina in modalità orizzontale per iniziare con: P

+0

Ciao, MadProgrammer. Grazie per la risposta e scuse per la risposta tardiva. Ho provato i tuoi programmi e funziona alla grande, l'unico problema affrontato è la qualità di stampa. La qualità sembra essere molto degradata, puoi indicare il motivo e una possibile soluzione allo stesso. – ItachiUchiha

+0

Il motivo principale che posso pensare è il ridimensionamento. Puoi dare un'occhiata a [imgscalr] (http://www.thebuzzmedia.com/software/imgscalr-java-image-scaling-library/) per un'alternativa – MadProgrammer

+0

Grazie per l'input, darò un'occhiata a questo. Grazie anche per la meravigliosa risposta :) – ItachiUchiha

1

Direi che è necessario il ridimensionamento proporzionale. Ti piace questa

double scaleX = pageWidth/imageWidth; 
double scaleY = pageHeight/imageHeight; 
double scale = Math.min(scaleX, scaleY); 
g2d.scale(scale, scale); 

UPDATE: Un altro suggerimenti quanto mKorbel menzionati sarebbe scala separata.

Prova Usa public Image getScaledInstance(int width, int height, int hints) metodo BufferedImage passando Image.SCALE_SMOOTH come il suggerimento.

+0

Beh, l'ho già provato. Non crea molta differenza. – ItachiUchiha

+0

@ItachiUchiha è possibile dipingere un BufferedImage a componenti AWT/Swing con dimensione desiderata in pixel, esiste una relazione reciproca tra pixel e DPI, il problema è che si dipinge off_screen, per provare, iniziare con la stampa già visibile Oggetto sullo schermo (I Sono sicuro che le domande similari con/sulla stampa dell'immagine visibile siano alcune volte qui) – mKorbel