DPI-Auflösungen von Druckern auslesen

inflamer

Bekanntes Mitglied
Hallo zusammen!

Der folgende Code liest "vorbildhaft" die "Auflösungen" von PDF- und XPS-Druckern aus, nicht jedoch von echten Druckern ;-)))
Java:
import java.util.*;
import javax.print.*;
import javax.print.attribute.standard.*;


public class A {

  public static void main(String[] args) {
    PrintService[] printServices = PrintServiceLookup.lookupPrintServices(null, null);

    for (PrintService printService : printServices) {
      System.out.println("\nPrinter: " + printService.getName());

      PrinterResolution[] resolutions = (PrinterResolution[])printService
          .getSupportedAttributeValues(PrinterResolution.class, null, null);

      if (resolutions != null) {
        Arrays.sort(resolutions, (r1, r2) -> {
          int res1 = r1.getCrossFeedResolution(PrinterResolution.DPI);
          int res2 = r2.getCrossFeedResolution(PrinterResolution.DPI);
          return Integer.compare(res1, res2);
        });
        for (PrinterResolution resolution : resolutions) {
          int dpiX = resolution.getCrossFeedResolution(PrinterResolution.DPI);
          int dpiY = resolution.getFeedResolution(PrinterResolution.DPI);
          System.out.println("Resolution: " + dpiX + "x" + dpiY + " DPI");
        }
      } else {
        System.out.println("No supported resolutions found.");
      }

    }

  }

}

Output:
Code:
Printer: Microsoft XPS Document Writer
Resolution: 600x600 DPI

Printer: PDFCreator
Resolution: 72x72 DPI
Resolution: 96x96 DPI
Resolution: 144x144 DPI
Resolution: 150x150 DPI
Resolution: 300x300 DPI
Resolution: 600x600 DPI
Resolution: 720x720 DPI
Resolution: 1200x1200 DPI
Resolution: 2400x2400 DPI
Resolution: 3600x3600 DPI
Resolution: 4000x4000 DPI

Printer: EPSON XP-6100 Series
No supported resolutions found.

Printer: Brother DCP-J572DW Printer
No supported resolutions found.

Printer: 7-PDF Printer
Resolution: 1x1 DPI
Resolution: 9x9 DPI
Resolution: 12x12 DPI
Resolution: 18x18 DPI
Resolution: 36x36 DPI
Resolution: 72x72 DPI
Resolution: 96x96 DPI
Resolution: 144x144 DPI
Resolution: 150x150 DPI
Resolution: 300x300 DPI
Resolution: 600x600 DPI
Resolution: 720x720 DPI
Resolution: 1200x1200 DPI
Resolution: 2400x2400 DPI
Resolution: 3600x3600 DPI
Resolution: 4000x4000 DPI

Falls einer von euch zufällig einen typischen Thermotransfer-Etikettendrucker mit 203, 300 oder 600 dpi in Reichweite stehen hat (denn um solche geht es mir im konkreten Fall eigentlich), wäre ich euch äußerst verbunden, wenn Ihr den Code damit ausprobieren und den "Output" hier posten könntet (natürlich nur falls tatsächlich Auflösungen geliefert werden).

Edit: Die beiden "physischen" Drucker in meinem Output sind beides 0815-Tintenstrahl-DIN A4-Drucker, daher meine Hoffnung, dass es mit reinen Etikettendruckern eventuell ja besser funktioniert.

Vielen Dank!
 
Zuletzt bearbeitet:
Bei mir funktioniert es. "PrinterResolution" und "MediaPrintableArea" sind wahrscheinlich die gesuchten Attribute:

Java:
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.Attribute;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class MyPrinter {
    public static void main(String[] args) {
        Map<PrintService, Map<Class<? extends Attribute>, Object>> supportedAttributes = new HashMap<>();
        PrintService[] printServices = PrintServiceLookup.lookupPrintServices(null, null);
        for (PrintService printService : printServices) {
            Class<? extends Attribute>[] supportedAttributeCategories = (Class<? extends Attribute>[]) printService.getSupportedAttributeCategories();
            for (Class<? extends Attribute> supportedAttributeCategory : supportedAttributeCategories) {
                Object supportedAttributeValues = printService.getSupportedAttributeValues(supportedAttributeCategory, null, null);
                supportedAttributes.computeIfAbsent(printService, k -> new HashMap<>()).put(supportedAttributeCategory, supportedAttributeValues);
            }
        }
        for (Map.Entry<PrintService, Map<Class<? extends Attribute>, Object>> ps : supportedAttributes.entrySet()) {
            System.out.println(ps.getKey().getName());
            for (Map.Entry<Class<? extends Attribute>, Object> entry : ps.getValue().entrySet()) {
                Class<? extends Attribute> attributeClass = entry.getKey();
                Object attributeValue = entry.getValue();
                if (attributeValue instanceof Object[]) {
                    attributeValue = Arrays.toString((Object[]) attributeValue);
                }
                System.out.println(attributeClass.getSimpleName() + ": " + attributeValue);
            }
        }
    }
}
 
Ja, eigentlich geht es ausschließlich um "PrinterResolution", zumindest wenn es um die Auflösung in DPI geht.

Bekommst Du diese denn für deine physischen Drucker zurückgeliefert, also nicht nur für PDF-Drucker etc.?

Bei mir funktioniert das eben nicht, auch nicht mit Deinem Code...
 
Bei mir funktioniert das eben nicht, auch nicht mit Deinem Code...

In wesentlichen liegt das daran, dass beide Quellcodes gleich sind. von @bullish einfach nur komplizierter gemacht.

Ich gehe davon aus, dass die DPI erst nach Auswahl im Druckdialog "fest" steht. Aktuell habe ich meinen Thermodrucker nicht angeschlossen, daher kann ich das auch nicht weiter ausprobieren. Eventuell wirst du den User fragen müssen, auf welche Ettiketten er gerade gedenkt zu drucken und darauf dein Druckauftrag richten.
 
Ja, richtig, im wesentlichen passiert dort und dort dasselbe...

Ich habe deine Idee ausprobiert, indem ich meinem obigen Code das hier vorgeschaltet habe:

Java:
printerJob.printDialog();

Leider hat dies am Ergebnis nichts geändert, obwohl ich ebenfalls eine gewisse Hoffnung hegte.
 
Hängt vom Drucker ab, dein Code liefert bei mir:
Printer: SEC30CDA7FB505B
Resolution: 600x600 DPI
Resolution: 1200x1200 DPI

Printer: Samsung M262x 282x Series (USB001)
Resolution: 600x600 DPI
Resolution: 1200x1200 DPI

Printer: OneNote for Windows 10
Resolution: 300x300 DPI

Printer: PDF24 Fax
Resolution: 72x72 DPI
Resolution: 96x96 DPI
Resolution: 144x144 DPI
Resolution: 150x150 DPI
Resolution: 200x200 DPI
Resolution: 300x300 DPI
Resolution: 600x600 DPI
Resolution: 720x720 DPI
Resolution: 1200x1200 DPI
Resolution: 2400x2400 DPI
Resolution: 3600x3600 DPI
Resolution: 4000x4000 DPI

Printer: PDF24
Resolution: 72x72 DPI
Resolution: 96x96 DPI
Resolution: 144x144 DPI
Resolution: 150x150 DPI
Resolution: 200x200 DPI
Resolution: 300x300 DPI
Resolution: 600x600 DPI
Resolution: 720x720 DPI
Resolution: 1200x1200 DPI
Resolution: 2400x2400 DPI
Resolution: 3600x3600 DPI
Resolution: 4000x4000 DPI

Printer: OneNote (Desktop)
Resolution: 600x600 DPI
Resolution: 1200x1200 DPI

Printer: Microsoft XPS Document Writer
Resolution: 600x600 DPI

Printer: Microsoft Print to PDF
Resolution: 600x600 DPI

Printer: HP55610F (HP DeskJet 3630 series)
Resolution: 300x300 DPI
Resolution: 600x600 DPI

Printer: Fax
Resolution: 200x200 DPI
Resolution: 200x100 DPI
 
Schau mal ob dieser Dialog von ServiceUI etwas bringt (Ich vermute nicht):

Java:
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.Attribute;
import javax.print.attribute.AttributeSet;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.PrinterResolution;
import javax.print.attribute.standard.PrinterState;
import javax.print.PrintService;
import javax.print.ServiceUI;

public class PrinterResolutionExample {
    public static void main(String[] args) {
        PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
        PrintService[] printServices = PrintServiceLookup.lookupPrintServices(null, null);

        PrintService printService = ServiceUI.printDialog(null, 200, 200, printServices, null, null, pras);

        if (printService != null) {
            System.out.println("Selected Printer: " + printService.getName());

            PrinterResolution[] resolutions = (PrinterResolution[]) printService.getSupportedAttributeValues(PrinterResolution.class, null, null);

            if (resolutions != null) {
                for (PrinterResolution resolution : resolutions) {
                    int dpiX = resolution.getCrossFeedResolution(PrinterResolution.DPI);
                    int dpiY = resolution.getFeedResolution(PrinterResolution.DPI);
                    System.out.println("Resolution: " + dpiX + "x" + dpiY + " DPI");
                }
            } else {
                System.out.println("No supported resolutions found.");
            }
        }
    }
}
 
@Konrad
Danke! Das Ergebnis ist mit dem meines Ursprungscodes leider identisch - positiv für PDF/XPS, kein Ergebnis für die A4-Drucker (eingeschaltet und betriebsbereit, was aber vermulich eh keine Rolle spielt).

@LimDul
Danke ebenfalls. Zumindest funktioniert es anscheinend manchmal. Werde der Frage mal nachgehen "wieso nicht in meinem Fall"...
 
@Limbul.
Das ist mir aufgefallen, vor allem weil für Deinen HP nur 300dpi und 600dpi zurückgegeben werden. Was ja leider so auch nicht stimmen kann bei einem modernen Tintenstrahler. Na ja...
 
Zuletzt bearbeitet:
Was gut sein kann ist dass das hier vom Betriebssystem und vom Treiber abhaengt, ob die Informationen geliefert werden oder nicht.

Waehrend Java ja Betriebssystemunabhaengig ist, muss es ja dennoch die Schichten darunter verwenden welche vom Betriebssystem zur Verfuegung gestellt werden. @LimDul wird vermutlich Linux verwenden, @Konrad hat Apple wenn ich mich richtig erinnere und bei mir unter Linux funktioniert es auch.

Ich bilde mir ein genau diese Frage haetten wir schonmal hier gehabt, und die Antwort war "nimm eine andere Bibliothek", aber ich finde das Thema gerade nicht wieder.
 
@Robert. Ja, das mit dem OS könnte so sein.

Speziell für Etikettendrucker (also gerade dort, wo die Auflösung am relevantesten ist, weil idR. relativ niedrig) kann man sich übrigens den Umstand zunutze machen, dass die DPI-Zahl, gefolgt von dem Zusatz "dpi", häufig direkt im Namen des Druckers erwähnt ist, über den der Drucker ansprechbar ist. Und das findet sich nicht nur bei Zebra, sondern bei mehreren Herstellern.

Unbenannt - 1.png

Der Angabe im Namen ist, so wie es fast aussieht, sogar eher zu trauen, als dem was da über die schwer zu durchschauenden Kanäle der API rüberkommt. Das und die Menge von Druckern mit "XYdpi" im Namen machen eine Vorab-Abfrage (also noch vor der API), denke ich, auf jeden Fall lohnenswert...
 
Zuletzt bearbeitet:
Was gut sein kann ist dass das hier vom Betriebssystem und vom Treiber abhaengt, ob die Informationen geliefert werden oder nicht.

Waehrend Java ja Betriebssystemunabhaengig ist, muss es ja dennoch die Schichten darunter verwenden welche vom Betriebssystem zur Verfuegung gestellt werden. @LimDul wird vermutlich Linux verwenden, @Konrad hat Apple wenn ich mich richtig erinnere und bei mir unter Linux funktioniert es auch.

Ich bilde mir ein genau diese Frage haetten wir schonmal hier gehabt, und die Antwort war "nimm eine andere Bibliothek", aber ich finde das Thema gerade nicht wieder.
Naja, wie du auf Linux bei mir kommst, bei den Druckern, würde mich mal interessieren 🙂

Printer: OneNote for Windows 10
Resolution: 300x300 DPI


Printer: OneNote (Desktop)
Resolution: 600x600 DPI
Resolution: 1200x1200 DPI

Printer: Microsoft XPS Document Writer
Resolution: 600x600 DPI

Printer: Microsoft Print to PDF
Resolution: 600x600 DPI

Ist ein Windows 10 mit Java 21 🙂
 
OK, kleines Update: Gerade habe ich's mit JNA (Windows) getestet, mit exakt demselben Ergebnis. (Zur Erinnerung: keine Auflösungen für die beiden A4-Drucker)

An der Java-Print-API scheint es jedenfalls schon mal nicht zu liegen.

JNA spricht ja auf ziemlich niedrigem Level direkt das OS an. Und wenn von dem nichts kommt, dann liegt die Ursache wohl irgendwo ziemlich nahe an der Quelle... Hier der Code:
Java:
import com.sun.jna.*;
import com.sun.jna.ptr.IntByReference;


public interface Winspool extends Library {

  Winspool INSTANCE = Native.load("Winspool.drv", Winspool.class);

  int EnumPrinters(int Flags, String Name, int Level, Pointer pPrinterEnum, int cbBuf,
      IntByReference pcbNeeded, IntByReference pcReturned);

  int DeviceCapabilities(String pDevice, String pPort, int fwCapability, Pointer pOutput,
      Pointer pDevMode);

}

Java:
import com.sun.jna.*;
import java.awt.print.*;
import javax.print.*;


public class A {

  public static void main(String[] args) {
    for (PrintService ps : PrinterJob.lookupPrintServices()) {
      String printerName = ps.getName();

      // Buffer for the printer resolution capabilities
      int[] resolutions = new int[100];
      Pointer pResolutions = new Memory(resolutions.length * Native.getNativeSize(Integer.TYPE));

      // Abrufen der Druckerauflösungen
      int resCount = Winspool.INSTANCE.DeviceCapabilities(printerName, null, 13, pResolutions, null);

      System.out.println("\n" + printerName + ":");
      if (resCount > 0) {
        for (int i = 0; i < resCount; i++) {
          int dpiX = pResolutions.getInt(i * 2 * Native.getNativeSize(Integer.TYPE));
          int dpiY = pResolutions.getInt((i * 2 + 1) * Native.getNativeSize(Integer.TYPE));
          System.out.println(dpiX + " x " + dpiY);
        }
      } else {
        System.out.println("No supported resolutions found.");
      }
    }
  }

}
 
Zuletzt bearbeitet:
Dafür liefern sowohl der ursprüngliche Code als der obige ein Ergebnis (203x203) für einen Zebra-Drucker, von dem ich für Testzwecke nur den Treiber installiert habe, der also physisch gar nicht existiert.

Wollt's hier nur nochmal posten, falls es jemand braucht.
 

Zurück
Oben