/* * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package com.sun.prism.j2d.print; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.TreeSet; import javax.print.PrintService; import javax.print.attribute.HashPrintRequestAttributeSet; import javax.print.attribute.PrintRequestAttributeSet; import javax.print.attribute.ResolutionSyntax; import javax.print.attribute.standard.Chromaticity; import javax.print.attribute.standard.Copies; import javax.print.attribute.standard.CopiesSupported; import javax.print.attribute.standard.Destination; import javax.print.attribute.standard.Media; import javax.print.attribute.standard.MediaPrintableArea; import javax.print.attribute.standard.MediaSize; import javax.print.attribute.standard.MediaSizeName; import javax.print.attribute.standard.MediaTray; import javax.print.attribute.standard.OrientationRequested; import javax.print.attribute.standard.PageRanges; import javax.print.attribute.standard.PrinterResolution; import javax.print.attribute.standard.SheetCollate; import javax.print.attribute.standard.Sides; import javafx.geometry.Rectangle2D; import java.awt.print.PageFormat; import javafx.print.JobSettings; import javafx.print.PageLayout; import javafx.print.Printer; import javafx.print.Printer.MarginType; import javafx.print.Collation; import javafx.print.Paper; import javafx.print.PaperSource; import javafx.print.PageRange; import javafx.print.PrintColor; import javafx.print.PageOrientation; import javafx.print.PrintQuality; import javafx.print.PrintResolution; import javafx.print.Paper; import javafx.print.PaperSource; import javafx.print.PrintSides; import com.sun.javafx.print.PrintHelper; import com.sun.javafx.print.PrinterImpl; import com.sun.javafx.print.Units; public class J2DPrinter implements PrinterImpl { private PrintService service; private Printer fxPrinter; public J2DPrinter(PrintService s) { service = s; } public Printer getPrinter() { return fxPrinter; } public void setPrinter(Printer printer) { fxPrinter = printer; } public PrintService getService() { return service; } public String getName() { return service.getName(); } /* * Since JobSettings are mutable, this always returns * a new instance. */ public JobSettings getDefaultJobSettings() { return PrintHelper.createJobSettings(fxPrinter); } //////////////// BEGIN COPIES //////////////////// private int defaultCopies = 0; public int defaultCopies() { if (defaultCopies > 0) { return defaultCopies; } try { Copies copies = (Copies)service.getDefaultAttributeValue(Copies.class); defaultCopies = copies.getValue(); } catch (Exception e) { defaultCopies = 1; } return defaultCopies; } private int maxCopies = 0; public int maxCopies() { if (maxCopies > 0) { return maxCopies; } CopiesSupported copies = null; try { copies = (CopiesSupported)service.getSupportedAttributeValues (CopiesSupported.class, null, null); } catch (Exception e) { } if (copies != null) { int[][] members = copies.getMembers(); if (members != null && members.length > 0 && members[0].length > 0) { maxCopies = members[0][1]; } } if (maxCopies == 0) { maxCopies = 999; } return maxCopies; } //////////////// END COPIES //////////////////// //////////////// BEGIN PAGERANGE //////////////////// public PageRange defaultPageRange() { try { PageRanges ranges = (PageRanges)service.getDefaultAttributeValue(PageRanges.class); if (ranges == null) { return null; } int s = ranges.getMembers()[0][0]; int e = ranges.getMembers()[0][1]; if (s == 1 && e == Integer.MAX_VALUE) { return null; } else { return new PageRange(s, e); } } catch (Exception e) { return null; } } public boolean supportsPageRanges() { return true; } //////////////// BEGIN COLLATION //////////////////// SheetCollate getDefaultSheetCollate() { SheetCollate collate = null; try { collate = (SheetCollate) service.getDefaultAttributeValue(SheetCollate.class); } catch (Exception e) { collate = SheetCollate.UNCOLLATED; } return collate; } private Collation defaultCollation; public Collation defaultCollation() { if (defaultCollation != null) { return defaultCollation; } SheetCollate collate = getDefaultSheetCollate(); defaultCollation = (collate == SheetCollate.COLLATED) ? Collation.COLLATED : Collation.UNCOLLATED; return defaultCollation; } private Set collateSet; public Set supportedCollations() { if (collateSet == null) { Set cSet = new TreeSet(); SheetCollate[] sc = null; try { sc = (SheetCollate[]) service.getSupportedAttributeValues(SheetCollate.class, null, null); } catch (Exception e) { } if (sc != null) { for (int i=0;i colorSet; public Set supportedPrintColor() { if (colorSet == null) { Set cSet = new TreeSet(); Chromaticity[] sc = null; try { sc = (Chromaticity[]) service.getSupportedAttributeValues(Chromaticity.class, null, null); } catch (Exception e) { } if (sc != null) { for (int i=0;i sidesSet; public Set supportedSides() { if (sidesSet == null) { Set sSet = new TreeSet(); Sides[] ss = null; try { ss = (Sides[]) service.getSupportedAttributeValues(Sides.class, null, null); } catch (Exception e) { } if (ss != null) { for (int i=0;i orientSet; public Set supportedOrientation() { if (orientSet != null) { return orientSet; } Set oset = new TreeSet(); OrientationRequested[] or = null; try { or = (OrientationRequested[]) service.getSupportedAttributeValues (OrientationRequested.class, null, null); } catch (Exception e) { } if (or == null || or.length == 0) { oset.add(defaultOrientation()); } else { for (int i=0;i { final static PrintResolutionComparator theComparator = new PrintResolutionComparator(); /** * Is used to approximate a sort of resolutions from * lowest to highest overall resolution. * The feed and cross feed resolutions are combined so a * where M and N represent cross feed and feed dpi values, * a resolution MxN will equal NxM. * @param other resolution to compare. * @return whether this resolution is less, equal or * greater than the other. */ public int compare(PrintResolution r1, PrintResolution r2) { long r1Res = r1.getCrossFeedResolution() * r1.getFeedResolution(); long r2Res = r2.getCrossFeedResolution() * r2.getFeedResolution(); if (r1Res == r2Res) { return 0; } else if (r1Res < r2Res) { return -1; } else { return 1; } } } private Set resSet; public Set supportedPrintResolution() { if (resSet != null) { return resSet; } Set rSet = new TreeSet(PrintResolutionComparator.theComparator); PrinterResolution[] pr = null; try { pr = (PrinterResolution[]) service.getSupportedAttributeValues (PrinterResolution.class, null, null); } catch (Exception e) { } if (pr == null || pr.length == 0) { rSet.add(defaultPrintResolution()); } else { for (int i=0;i qualitySet; public Set supportedPrintQuality() { if (qualitySet == null) { Set set = new TreeSet(); javax.print.attribute.standard.PrintQuality[] arr = null; try { arr = (javax.print.attribute.standard.PrintQuality[]) service.getSupportedAttributeValues (javax.print.attribute.standard.PrintQuality.class, null, null); } catch (Exception e) { } if (arr == null || arr.length == 0) { set.add(PrintQuality.NORMAL); } else { for (int i=0;i { final static PaperComparator theComparator = new PaperComparator(); /** * This sorts papers lexically based on name, not size. */ public int compare(Paper p1, Paper p2) { return p1.getName().compareTo(p2.getName()); } } private static class PaperSourceComparator implements Comparator { final static PaperSourceComparator theComparator = new PaperSourceComparator(); /** * This sorts papers lexically based on name, not size. */ public int compare(PaperSource p1, PaperSource p2) { return p1.getName().compareTo(p2.getName()); } } Paper getPaperForMedia(Media media) { populateMedia(); if (media == null || !(media instanceof MediaSizeName)) { return defaultPaper(); } else { return getPaper((MediaSizeName)media); } } private Paper defPaper; public Paper defaultPaper() { if (defPaper != null) { return defPaper; } Media m = (Media)service.getDefaultAttributeValue(Media.class); if (m == null || !(m instanceof MediaSizeName)) { defPaper = Paper.NA_LETTER; } else { defPaper = getPaper((MediaSizeName)m); } return defPaper; } private Set paperSet; public Set supportedPapers() { if (paperSet == null) { populateMedia(); } return paperSet; } private static Map preDefinedTrayMap = null; private static Map predefinedPaperMap = null; private static void initPrefinedMediaMaps() { if (predefinedPaperMap == null) { // North American papers HashMap map = new HashMap(); map.put(MediaSizeName.NA_LETTER, Paper.NA_LETTER); map.put(MediaSizeName.TABLOID, Paper.TABLOID); map.put(MediaSizeName.NA_LEGAL, Paper.LEGAL); map.put(MediaSizeName.EXECUTIVE, Paper.EXECUTIVE); map.put(MediaSizeName.NA_8X10, Paper.NA_8X10); // Envelopes map.put(MediaSizeName.MONARCH_ENVELOPE, Paper.MONARCH_ENVELOPE); map.put(MediaSizeName.NA_NUMBER_10_ENVELOPE, Paper.NA_NUMBER_10_ENVELOPE); // ISO sizes. map.put(MediaSizeName.ISO_A0, Paper.A0); map.put(MediaSizeName.ISO_A1, Paper.A1); map.put(MediaSizeName.ISO_A2, Paper.A2); map.put(MediaSizeName.ISO_A3, Paper.A3); map.put(MediaSizeName.ISO_A4, Paper.A4); map.put(MediaSizeName.ISO_A5, Paper.A5); map.put(MediaSizeName.ISO_A6, Paper.A6); map.put(MediaSizeName.C, Paper.C); // Eng. size // I've seen this as "Envelope DL" on HP inkjet drivers // for OS X and WIndows. map.put(MediaSizeName.ISO_DESIGNATED_LONG, Paper.DESIGNATED_LONG); // Common Japanese sizes. map.put(MediaSizeName.JIS_B4, Paper.JIS_B4); map.put(MediaSizeName.JIS_B5, Paper.JIS_B5); map.put(MediaSizeName.JIS_B6, Paper.JIS_B6); map.put(MediaSizeName.JAPANESE_POSTCARD, Paper.JAPANESE_POSTCARD); predefinedPaperMap = map; } if (preDefinedTrayMap == null) { HashMap map = new HashMap(); map.put(MediaTray.MAIN, PaperSource.MAIN); map.put(MediaTray.MANUAL, PaperSource.MANUAL); map.put(MediaTray.BOTTOM, PaperSource.BOTTOM); map.put(MediaTray.MIDDLE, PaperSource.MIDDLE); map.put(MediaTray.TOP, PaperSource.TOP); map.put(MediaTray.SIDE, PaperSource.SIDE); map.put(MediaTray.ENVELOPE, PaperSource.ENVELOPE); map.put(MediaTray.LARGE_CAPACITY, PaperSource.LARGE_CAPACITY); preDefinedTrayMap = map; } } private void populateMedia() { initPrefinedMediaMaps(); if (paperSet != null) { return; // already inited } Media[] media = (Media[])service.getSupportedAttributeValues(Media.class, null, null); Set pSet = new TreeSet(PaperComparator.theComparator); Set tSet = new TreeSet(PaperSourceComparator.theComparator); /* We will get back a list of Media and want to look for * MediaSizeName and MediaTray instances and map to FX classes. * We will hard code here recognising the set we've chosen to * expose in FX API. * For the rest we'll need to create custom instances. */ if (media != null) { for (int i=0; i paperSourceSet; public Set supportedPaperSources() { if (paperSourceSet == null) { populateMedia(); } return paperSourceSet; } /* * We have a static map from pre-defined javax.print trays to * pre-defined javafx.print trays. For all other trays we create * a printer specific instance. */ private Map sourceToTrayMap; private Map trayToSourceMap; synchronized final PaperSource getPaperSource(MediaTray tray) { if (paperSourceSet == null) { populateMedia(); } PaperSource source = trayToSourceMap.get(tray); if (source != null) { return source; } else { return addPaperSource(tray); } } MediaTray getTrayForPaperSource(PaperSource source) { if (paperSourceSet == null) { populateMedia(); } return sourceToTrayMap.get(source); } private synchronized final PaperSource addPaperSource(MediaTray tray) { PaperSource source = preDefinedTrayMap.get(tray); if (source == null) { source = PrintHelper.createPaperSource(tray.toString()); } if (trayToSourceMap == null) { trayToSourceMap = new HashMap(); } trayToSourceMap.put(tray, source); if (sourceToTrayMap == null) { sourceToTrayMap = new HashMap(); } sourceToTrayMap.put(source, tray); return source; } /* * We have a static map from pre-defined javax.print MediaSizeName * to pre-defined javafx.print Papers. For all other reported media we * create a printer-specific instance and store it in a per-printer map. */ private Map mediaToPaperMap; private Map paperToMediaMap; private synchronized final Paper addPaper(MediaSizeName media) { if (mediaToPaperMap == null) { mediaToPaperMap = new HashMap(); paperToMediaMap = new HashMap(); } Paper paper = predefinedPaperMap.get(media); if (paper == null ) { MediaSize sz = MediaSize.getMediaSizeForName(media); if (sz != null) { double pw = sz.getX(1) / 1000.0; double ph = sz.getY(1) / 1000.0; paper = PrintHelper.createPaper(media.toString(), pw, ph, Units.MM); } } if (paper == null) { paper = Paper.NA_LETTER; } paperToMediaMap.put(paper, media); mediaToPaperMap.put(media, paper); return paper; } private Paper getPaper(MediaSizeName m) { populateMedia(); Paper paper = mediaToPaperMap.get(m); if (paper == null) { paper = Paper.NA_LETTER; } return paper; } private MediaSizeName getMediaSizeName(Paper paper) { populateMedia(); MediaSizeName m = paperToMediaMap.get(paper); if (m == null) { m = MediaSize.findMedia((float)paper.getWidth(), (float)paper.getHeight(), (int)(MediaSize.INCH/72.0)); } return m; } /** * For any given paper, this retrieves the hardware margins, * or a reasonable and safe guess if they aren't available. */ public Rectangle2D printableArea(Paper paper) { Rectangle2D area = null; MediaSizeName msn = getMediaSizeName(paper); if (msn != null) { PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet(); pras.add(msn); MediaPrintableArea[] mpa = (MediaPrintableArea[])service. getSupportedAttributeValues(MediaPrintableArea.class, null, pras); if (mpa != null && mpa.length > 0 && mpa[0] != null) { int MPA_INCH = MediaPrintableArea.INCH; area = new Rectangle2D(mpa[0].getX(MPA_INCH), mpa[0].getY(MPA_INCH), mpa[0].getWidth(MPA_INCH), mpa[0].getHeight(MPA_INCH)); } } // If we could not get the area for whatever reason, // then go with 0.75" margins unless they are too large // ie its a really small paper. if (area == null) { double pw = (paper.getWidth() / 72.0); ; double ph = (paper.getHeight() / 72.0); double iw, ih; if (pw < 3.0) { iw = 0.75 * pw; } else { iw = pw - 1.5; } if (ph < 3.0) { ih = 0.75 * ph; } else { ih = ph - 1.5; } double lm = (pw - iw) / 2.0; double tm = (ph - ih) / 2.0; area = new Rectangle2D(lm, tm, iw, ih); } return area; } private PageLayout defaultLayout; PageLayout defaultPageLayout() { if (defaultLayout == null) { Paper paper = defaultPaper(); PageOrientation orient = defaultOrientation(); defaultLayout = fxPrinter.createPageLayout(paper, orient, MarginType.DEFAULT); } return defaultLayout; } //////////////// END PAPERS //////////////////// }