All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.prism.j2d.print.J2DPrinter Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

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.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.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;
    }

    @Override
    public void setPrinter(Printer printer) {
        fxPrinter = printer;
    }

    public PrintService getService() {
        return service;
    }

    @Override
    public String getName() {
        return service.getName();
    }

    /*
     * Since JobSettings are mutable, this always returns
     * a new instance.
     */
    @Override
    public JobSettings getDefaultJobSettings() {
        return PrintHelper.createJobSettings(fxPrinter);
    }

    //-------------- BEGIN COPIES --------------------

    private int defaultCopies = 0;
    @Override
    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;
    @Override
    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 --------------------

    @Override
    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;
        }
    }

    @Override
    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;
    @Override
    public Collation defaultCollation() {
        if (defaultCollation != null) {
            return defaultCollation;
        }
        SheetCollate collate = getDefaultSheetCollate();
        defaultCollation = (collate == SheetCollate.COLLATED) ?
            Collation.COLLATED : Collation.UNCOLLATED;
        return defaultCollation;
    }


    private Set collateSet;
    @Override
    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;
    @Override
    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;
    @Override
    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;
    @Override
    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.
         */
        @Override
        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;
    @Override
    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;
    @Override
    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.
         */
        @Override
        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.
         */
        @Override
        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;
    @Override
    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;
    @Override
    public Set supportedPapers() {
        if (paperSet == null) {
            populateMedia();
        }
        return paperSet;
    }

    private static Map predefinedPaperMap;
    private static Map predefinedTrayMap;

    private static void initPredefinedMediaMaps() {
        if (predefinedPaperMap == null) {
            // North American papers
            predefinedPaperMap = Map.ofEntries(
                Map.entry(MediaSizeName.NA_LETTER,             Paper.NA_LETTER),
                Map.entry(MediaSizeName.TABLOID,               Paper.TABLOID),
                Map.entry(MediaSizeName.NA_LEGAL,              Paper.LEGAL),
                Map.entry(MediaSizeName.EXECUTIVE,             Paper.EXECUTIVE),
                Map.entry(MediaSizeName.NA_8X10,               Paper.NA_8X10),
                // Envelopes
                Map.entry(MediaSizeName.MONARCH_ENVELOPE,      Paper.MONARCH_ENVELOPE),
                Map.entry(MediaSizeName.NA_NUMBER_10_ENVELOPE, Paper.NA_NUMBER_10_ENVELOPE),
                // ISO sizes.
                Map.entry(MediaSizeName.ISO_A0,                Paper.A0),
                Map.entry(MediaSizeName.ISO_A1,                Paper.A1),
                Map.entry(MediaSizeName.ISO_A2,                Paper.A2),
                Map.entry(MediaSizeName.ISO_A3,                Paper.A3),
                Map.entry(MediaSizeName.ISO_A4,                Paper.A4),
                Map.entry(MediaSizeName.ISO_A5,                Paper.A5),
                Map.entry(MediaSizeName.ISO_A6,                Paper.A6),
                Map.entry(MediaSizeName.C,                     Paper.C), // Eng. size
                // I've seen this as "Envelope DL" on HP inkjet drivers for OS X and WIndows.
                Map.entry(MediaSizeName.ISO_DESIGNATED_LONG,   Paper.DESIGNATED_LONG),
                // Common Japanese sizes.
                Map.entry(MediaSizeName.JIS_B4,                Paper.JIS_B4),
                Map.entry(MediaSizeName.JIS_B5,                Paper.JIS_B5),
                Map.entry(MediaSizeName.JIS_B6,                Paper.JIS_B6),
                Map.entry(MediaSizeName.JAPANESE_POSTCARD,     Paper.JAPANESE_POSTCARD));
        }

        if (predefinedTrayMap == null) {
            predefinedTrayMap = Map.of(
                MediaTray.MAIN,           PaperSource.MAIN,
                MediaTray.MANUAL,         PaperSource.MANUAL,
                MediaTray.BOTTOM,         PaperSource.BOTTOM,
                MediaTray.MIDDLE,         PaperSource.MIDDLE,
                MediaTray.TOP,            PaperSource.TOP,
                MediaTray.SIDE,           PaperSource.SIDE,
                MediaTray.ENVELOPE,       PaperSource.ENVELOPE,
                MediaTray.LARGE_CAPACITY, PaperSource.LARGE_CAPACITY);
        }
    }

    private void populateMedia() {
        initPredefinedMediaMaps();

        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;
    @Override
    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 final Map mediaToPaperMap
         = new HashMap<>();
    private final Map paperToMediaMap
         = new HashMap<>();

    private Paper createPaper(MediaSizeName media) {
        Paper 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);
        }
        return paper;
   }

    private synchronized final Paper addPaper(MediaSizeName media) {
        Paper paper = predefinedPaperMap.get(media);
        if (paper == null) {
           paper = createPaper(media);
        }
        /* If that failed create a Paper from the default MediaSizeName */
        if (paper == null) {
            Media m = (Media)service.getDefaultAttributeValue(Media.class);
            if (m instanceof MediaSizeName) {
                paper = createPaper((MediaSizeName)m);
            }
        }
        if (paper != null) {
            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.
     */
    @Override
    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 --------------------


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy