Frage

Ich habe eine Anwendung, die Metadateien (EMFs) generiert.Zum Rendern dieser Metadateien wird das Referenzgerät (auch der Bildschirm genannt) verwendet. Daher ändert sich die DPI der Metadatei je nachdem, auf welchem ​​Computer der Code ausgeführt wird.

Nehmen wir an, mein Code beabsichtigt, eine Metadatei mit den Maßen 8,5 x 11 Zoll zu erstellen.Wenn ich meine Entwicklungs-Workstation als Referenz verwende, erhalte ich ein EMF, das das hat

  • ein rclFrame von { 0, 0, 21590, 27940 } (Abmessungen der Metadatei, in Tausendstel mm)
  • ein szlDevice von { 1440, 900 } (Abmessungen des Referenzgeräts, in Pixel)
  • a szlMillimeter von { 416, 260 } (Abmessungen des Referenzgeräts, in mm)

Okay, der rclFrame sagt mir also, dass die Größe des EMF sein sollte

  • 21590 / 2540 = 8,5 Zoll breit
  • 27940 / 2540 = 11 Zoll hoch

Direkt am.Anhand dieser Informationen können wir auch die physische DPI meines Monitors bestimmen, wenn meine Berechnung richtig ist:

  • (1440 * 25,4) / 416 = 87,9231 horizontale dpi
  • (900 * 25,4) / 260 = 87,9231 vertikale dpi

Das Problem

Alles, was diese Metadatei wiedergibt – eine EMF-zu-PDF-Konvertierung, die Seite „Zusammenfassung“, wenn Sie im Windows Explorer mit der rechten Maustaste auf das EMF klicken usw. – scheint den berechneten DPI-Wert abzuschneiden und 87 statt 87,9231 (gerade) anzuzeigen 88 wäre in Ordnung).

Dies führt bei der Wiedergabe der Metadatei zu einer Seite mit einer physischen Größe von 8,48 x 10,98 Zoll (bei 87 dpi) statt 8,5 x 11 Zoll (bei 88 dpi).

  • Ist es möglich, den DPI-Wert des Referenzgeräts so zu ändern, dass die in der zur Berechnung des DPI-Werts verwendeten Metadatei gespeicherten Informationen eine schöne Ganzzahl ergeben?
  • Kann ich meinen eigenen Gerätekontext erstellen und dessen DPI angeben?Oder muss ich dafür wirklich einen Drucker verwenden?

Vielen Dank für jeden Einblick.

War es hilfreich?

Lösung

Ich bin gespannt, wie Windows die physische Größe Ihres Monitors kennt. Sie müssen eine Konfiguration irgendwo geändert haben? Vielleicht können Sie es in bequemere Werte ändern, die sich gut teilen.

Wie im Namen impliziert, muss ein "Gerätekontext" an ein Systemgerät angeschlossen werden. Dies muss jedoch kein Hardware -Treiber sein, sondern ein Gerätemulator wie ein PDF -Writer -Drucktreiber. Ich habe mindestens einen gesehen, mit dem Sie einen willkürlichen DPI festlegen können.

Andere Tipps

Ich habe jetzt mehr über Metadateien erfahren, als mir lieb war.

1.Einige der Metafile Die Konstruktorüberladungen der Klasse funktionieren schlecht und arbeiten mit einem abgeschnittenen DPI-Wert.

Folgendes berücksichtigen:

protected Graphics GetNextPage(SizeF pageSize)
{
    IntPtr deviceContextHandle;
    Graphics offScreenBufferGraphics;
    Graphics metafileGraphics;
    MetafileHeader metafileHeader;

    this.currentStream = new MemoryStream();
    using (offScreenBufferGraphics = Graphics.FromHwnd(IntPtr.Zero))
    {
        deviceContextHandle = offScreenBufferGraphics.GetHdc();
        this.currentMetafile = new Metafile(
            this.currentStream,
            deviceContextHandle,
            new RectangleF(0, 0, pageSize.Width, pageSize.Height),
            MetafileFrameUnit.Inch,
            EmfType.EmfOnly);

        metafileGraphics = Graphics.FromImage(this.currentMetafile);

        offScreenBufferGraphics.ReleaseHdc();
    }

    return metafileGraphics;
}

Wenn Sie in a bestanden haben SizeF von { 8,5, 11 }, könnten Sie erwarten, eine zu erhalten Metafile das hat eine rclFrame von { 21590, 27940 }.Zoll in Millimeter umzurechnen ist schließlich nicht schwer.Aber das wirst du wahrscheinlich nicht.Abhängig von Ihrer Auflösung verwendet GDI+ bei der Konvertierung des Zoll-Parameters anscheinend einen abgeschnittenen DPI-Wert.Um es richtig zu machen, muss ich es selbst in Hundertstelmillimetern machen, was GDI+ einfach durchläuft, da es so nativ im Metadatei-Header gespeichert wird:

this.currentMetafile = new Metafile(
    this.currentStream,
    deviceContextHandle,
    new RectangleF(0, 0, pageSize.Width * 2540, pageSize.Height * 2540),
    MetafileFrameUnit.GdiCompatible,
    EmfType.EmfOnly);

Rundungsfehler Nr. 1 behoben – der rclFrame meiner Metadatei ist jetzt korrekt.

2.Die DPI auf einem Graphics Instanzaufzeichnung auf a Metafile ist immer falsch.

Siehst du das metafileGraphics Variable, die ich durch Aufruf setze Graphics.FromImage() auf der Metadatei?Nun, es scheint so Graphics Die Instanz hat immer eine DPI von 96 dpi.(Wenn ich raten müsste, ist es immer auf eingestellt logisch DPI, nicht das körperlich eins.)

Sie können sich die Heiterkeit vorstellen, die entsteht, wenn Sie auf einem zeichnen Graphics Instanz, die mit 96 dpi arbeitet und auf einem aufzeichnet Metafile Instanz, deren Header 87,9231 dpi „aufgezeichnet“ hat.(Ich sage „aufgezeichnet“, weil es aus den anderen Werten berechnet wird.) Die „Pixel“ der Metadatei (denken Sie daran, dass die in der Metadatei gespeicherten GDI-Befehle in angegeben sind Pixel) sind größer, und so fluchen und murmeln Sie, warum Ihr Aufruf, etwas von einem Zoll Länge zu zeichnen, am Ende eins und etwas mehr als Zoll lang ist.

Die Lösung besteht darin, das zu verkleinern Graphics Beispiel:


metafileGraphics = Graphics.FromImage(this.currentMetafile);
metafileHeader = this.currentMetafile.GetMetafileHeader();
metafileGraphics.ScaleTransform(
    metafileHeader.DpiX / metafileGraphics.DpiX,
    metafileHeader.DpiY / metafileGraphics.DpiY);

Ist das nicht ein Scherz?Aber es scheint zu funktionieren.

„Rundungsfehler“ Nr. 2 behoben – wenn ich sage, dass ich etwas mit „1 Zoll“ und 88 dpi zeichne, sollte dieses Pixel besser $%$^ sein!aufgezeichnet als Pixel #88.

3. szlMillimeters kann stark variieren;Remote Desktop macht viel Spaß.

Daher haben wir (laut Marks Antwort) herausgefunden, dass Windows manchmal die EDID Ihres Monitors abfragt und tatsächlich weiß, wie groß dieser physisch ist.GDI+ nutzt dies hilfreich (HORZSIZE usw.) beim Ausfüllen der szlMillimeters Eigentum.

Stellen Sie sich nun vor, Sie gehen nach Hause, um diesen Code des Remotedesktops zu debuggen.Nehmen wir an, Ihr Heimcomputer verfügt zufällig über einen 16:9-Breitbildmonitor.

Offensichtlich kann Windows die EDID einer Remote-Anzeige nicht abfragen.Es verwendet also die uralte Standardeinstellung von 320 x 240 mm, was in Ordnung wäre, außer dass es zufällig ein Seitenverhältnis von 4:3 ist, und jetzt generiert genau derselbe Code eine Metadatei auf einem Display, das angeblich kein Seitenverhältnis hat. quadratische physische Pixel:Die horizontale und die vertikale DPI sind unterschiedlich, und ich kann mich nicht erinnern, wann ich das letzte Mal gesehen habe.

Meine Problemumgehung dafür ist vorerst:„Nun, führen Sie es nicht unter Remotedesktop aus.“

4.Das von mir verwendete EMF-zu-PDF-Tool hatte beim Betrachten einen Rundungsfehler rclFrame Header.

Dies war die Hauptursache meines Problems, das diese Frage ausgelöst hat.Meine Metadatei war die ganze Zeit über „richtig“ (naja, richtig, nachdem ich die ersten beiden Probleme behoben hatte), und die ganze Suche nach der Erstellung einer „hochauflösenden“ Metadatei war ein Ablenkungsmanöver.Es stimmt, dass bei der Aufzeichnung der Metadatei auf einem Anzeigegerät mit niedriger Auflösung ein Teil der Wiedergabetreue verloren geht.Das liegt daran, dass die in der Metadatei angegebenen GDI-Befehle in Pixeln angegeben sind.Es spielt keine Rolle, dass es sich um ein Vektorformat handelt und sich vergrößern oder verkleinern lässt, einige Informationen gehen verloren während der eigentlichen Aufnahme wenn GDI+ entscheidet, an welchem ​​„Pixel“ eine Operation ausgerichtet werden soll.

Ich habe den Verkäufer kontaktiert und er hat mir eine korrigierte Version gegeben.

Rundungsfehler Nr. 3 behoben.

5.Der Bereich „Zusammenfassung“ im Windows Explorer schneidet zufällig Werte ab, wenn der berechnete DPI-Wert angezeigt wird.

Zufällig stellte dieser abgeschnittene Wert denselben fehlerhaften Wert dar, den das EMF-zu-PDF-Tool intern verwendete.Abgesehen davon trägt diese Eigenart nichts Sinnvolles zur Diskussion bei.

Schlussfolgerungen

Da es bei meiner Frage darum ging, mit DPI in Gerätekontexten herumzuspielen, ist die von Mark eine gute Antwort.

Beachten Sie, dass ich die ganze Zeit mit 120 dpi auf WXP (große Schriftarten) laufe, was bedeutet, dass metafilegraphics.dpix 120 zurückgibt.

Die EMF -Datei scheint nicht aufzuzeichnen, was der DPI aus dem Referenzkontext war (120 in diesem Fall 96 für die meisten anderen Personen).

Um die Dinge interessanter zu machen, ist es möglich, eine EMF zu erstellen, indem Sie sich auf eine in Speicherbitmap gezogene Bitmap () auf 300DPI eingestellt haben. In diesem Fall glaube ich, dass der Skalierungsfaktor 300 betragen muss und nicht das, was der Monitor (86.x) oder Windows (120) verwenden könnte.

Es scheint, als ob Werte auf der zusammenfassenden Seite falsch sind. Sie werden berechnet als:

Size = round(precize_size)+1
Resolution = trunc(precize_resolution)

Wo genaue Werte ohne Rundung oder Kürzung berechnet werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top