AGB  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Projekte RedeemerSVG.TSVGImage - Kleine SVG-Unit für Delphi mit GDI

RedeemerSVG.TSVGImage - Kleine SVG-Unit für Delphi mit GDI

Ein Thema von Redeemer · begonnen am 23. Aug 2017 · letzter Beitrag vom 1. Nov 2017
Antwort Antwort
Seite 2 von 4     12 34   
Redeemer
Registriert seit: 19. Jan 2009
Da ich für ein eigenes Projekt SVG-Unterstützung (für Tiny 2.0, statisch) brauchte, aber mit den bestehenden Lösungen nicht zufrieden war (viel zu viele benötigte fremde Pakete), habe ich mir kurzerhand selbst eine geschrieben, die nur mit den Delphi-Canvas-Funktionen und GDI (nicht GDI+) arbeitet. Der Quelltext ist relativ klein. Es werden mein eigener XML-Reader (wegen der vielen nicht zwingend zu schließenden Tags) und diverse Parser, z.B. für Style-Angaben, verwendet. Die eigentliche SVG-Klasse ist etwa 1000 Zeilen lang. Der mit Abstand größte Teil des Projekts, das mit Vanilla-Delphi ab 2009 (wegen Generics) kompiliert, ist die Tabelle mit den XML-Entities (was nicht mal Inkscape unterstützt)... Alles in allem kompiliert derzeit zu gerade mal 150 KiB und LZMA-gepackt irgendwo bei unter 30 KiB plus PNG-Image wenn ihr das nicht schon nutzt.

Funktionsweise:
  • Es werden zwei TPNGImages (ich arbeite gerne damit, später eventuell Umstellung auf TBitmap) erstellt, eine in RGB für Farbe und eine in Graustufen für Deckkraft. Diese sind derzeit 3× breiter und höher als das Zielbild. Außerdem wird ein SVG-Kontext erstellt. Dieser enthält alle Style-Informationen und wird weitergereicht.
  • Anschließend werden die SVG-Elemente verarbeitet:
    • Der Stil wird aus den Attributen und dem style-Attribut geladen. style überschreibt andere Attribute. SVGTiny kann standardgemäß keine richtigen Stylesheets lesen, nur style-Attribute.
    • Zunächst einmal wird ohne Transformationen, aber mit einer erhöhten Genauigkeit (32× breiter und höher, um auszugleichen, dass GDI nur Ganzzahlen kann) mit den GDI-Pfadfunktionen auf eins der PNG-Bilder gezeichnet (bzw. so getan, als ob).
    • Der SVG-Kontext wird in den Brush, Pen, Font und weitere Optionen (Umgang mit Überlappungen, später Gehrung) der beiden PNG-Canvases geschrieben. Wannimmer Farben gesetzt werden, wird beim DeckkraftPNG stattdessen clWhite geschrieben. (Es gibt zwar genau für das Zeichen immer in Weiß eine Funktion beim einfachen Pen (den auch TPen kapsel), aber nicht beim erweiterten ExtCreatePen-Pen.)
    • Der Pfad wird mit GetPath in ein tagPOINT-Array geladen und anschließend aus dem PNG gelöscht. Auch Formen und die für Text verwendete ExtTextOut-Funktion ergeben einen solchen Pfad.
    • Die Punkte des Pfades werden mit allen weiteren Transformationen (affine Abbildungen) versehen und anschließend auf beide PNGs wieder gezeichnet (PolyDraw ist die Umkehrfunktion von GetPath). Die Transformationen finden mit Extended-Gleitkommazahlen statt und haben wie erwähnt eine 32-fache Grund-Genauigkeit. Erst direkt vorm finalen Zeichnen wird gerundet, sodass eine sehr hohe Qualität entsteht, obwohl GDI nur mit Ganzzahlen arbeitet. PS: Der Name dieser Funktion und ihrer Unit stehen nicht zur Diskussion.
  • Die Scanline des Deckkraft-PNG wird in die AlphaScanline des Farb-PNGs geschrieben.
  • Das sich ergebende PNG wird mittels meines ungewichteten Downscale-Algorithmus um den Faktor 3 je Achse verkleinert, um ein Antialias zu erzeugen. Das Ergebnis ist ein PNG-Bild mit ausreichend hübschem Antialias (TSVGImage leitet sich derzeit von TPNGImage ab, irgendwann könnte man das vielleicht zu TBitmap ändern).

Nennenswerte Einschränkungen:
  • Keine Halbtransparenz (Transparenz gibt es aber), da GDI keine Halbtransparenz zeichnen kann. Ich hatte überlegt, eine 10-stufige Halbtransparenz mittels 3×3-Muster (hierbei wird völlige Transparenz unterstützt) zu implementieren, das sähe allerdings an Kanten etwas ungleichmäßig aus und das Überlagern mehrerer solcher Objekte ergäbe kein sinnvolles Ergebnis. Prinzipiell könnte man ein drittes PNG nehmen, darauf zeichnen und anschließend an den bemalten Stellen die Berechnungen mit der Scanline durchführen. Aber will man das? (Bevor jemand fragt: Der TPenMode pmMerge sorgt dafür, dass bei jedem RGB-Kanal der jeweils hellere Wert genommen wird.)
  • Keine Farbverläufe und Filter.
  • Diverse exotische Attribute und Eigenschaften, jeweils fast ausschließlich beim text-Element, werden nicht unterstützt.
  • Die path-Befehle Catmull-Rom (wird als Gerade dargestellt) und Bearing (wird ignoriert) aus SVG2 werden nicht unterstützt.
  • Das image-Element.
  • Metrische Einheiten.
Details siehe die beiliegende Excel-Tabelle.

Tipps:
  • Nach Lesen aller nötigen Informationen des Wurzel-svg-Elements kann die Ausgabegröße mittels Event beeinflusst werden, das SizeCallback heißt und global auf ein folgendes Event gesetzt wird:
    Code:
    type TSizeCallbackEvent = procedure (const Viewport: TRealRect; var Dimensions: TRealPoint) of object;
    So kann das Bild skaliert werden.
  • Die Datei RedeemerHypertextColorsX11.pas wird nicht benötigt. Sie liegt bloß für den Fall bei, falls ihr wie ich RedeemerHypertextColors.HTMLToColor anderswo mit X11-Unterstützung brauchen solltet.
  • EXE-Demo liegt bei.

Lizenz:
Die Nutzung ist kostenlos. Wer es in einem eigenen Produkt verwendet, das nicht für den Eigenbedarf ist, muss mir eine Nachricht schreiben. Weiterentwicklungen und Ableitungen der Klasse TSVGImage müssen mir auf Wunsch zur Verfügung gestellt werden.

Feedback ist gerne gesehen!

Download (ca. 300 KiB)

Beispielbild der Karte von Niedersachsen von TUBS (Wikipedia). Das Forum kann es leider nicht in der Originalgröße, ich habe es zugeschnitten.
Beispielbild der Flugzeugentführung der Landshut von Devilm25 (Wikipedia). Sie ist nicht ganz perfekt, man sieht ganz gut, was die Engine kann und was nicht. Ich frage mich gerade, warum zwischen der letzten und der aktuellen Version meiner Unit die Grenze zwischen Eritrea und Äthiopien verschwunden ist (sie fehlt allerdings auch bei anderen SVG-Viewern).
Miniaturansicht angehängter Grafiken
niedersachsen.png   strichelungen.png   entfuehrung-der-landshut.png  
2005 PE, 2009 PA, XE2 PA

Geändert von Redeemer (20. Okt 2017 um 21:58 Uhr)
 
Rollo62

 
Delphi 10.2 Tokyo Professional
 
#11
  Alt 26. Aug 2017, 13:39
Hätte ich schon gemacht und gecheckt wo der Fehler herkommt. Aber das Demo fehlt in dem File.
Ich habe jetzt keine Zeit das alles selber nachzubauen

Rollo
  Mit Zitat antworten Zitat
Redeemer

 
Delphi 2009 Professional
 
#12
  Alt 26. Aug 2017, 15:21
Schade. Ich habe noch ein anderes Projekt hier, welches mit Delphi 2007 geschrieben wurde und dort hätte ich gerne eine WMF-Lösung durch SVG ersetzt. Leider funktioniert nämlich auch die schon von mir erwähnte kommerzielle SVG-Komponente nicht mehr unter Delphi 2007.

Gruß
Micha
Die alte Version dürfte auch in Delphi 2007 kompiliert haben (TEncoding aus TStringList.LoadFromStream rausschmeißen), inzwischen nutzt es mehrere Generics, dementsprechend wird es nicht laufen. Sie dürfte bereits deutlich schneller laufen, wenn man konsequent einfach das Wort "MidStr" durch "Copy" ersetzt. Eventuell brauchst du PNGDelphi.

Den Quelltext der Demo-App werde ich demnächst mal beilegen. Stürzt die neueste Version immer noch bei dir ab?

Geändert von Redeemer (26. Aug 2017 um 15:24 Uhr)
  Mit Zitat antworten Zitat
samso
 
#13
  Alt 26. Aug 2017, 17:53
Es werden mein eigener XML-Reader (wegen der vielen nicht zwingend zu schließenden Tags)...verwendet
Das "wegen der vielen nicht zwingend zu schließenden Tags" verstehe ich nicht. Ist SVG also keine gültiges XML-Format? Hast Du ein Beispiel für die Abweichungen im Format?
  Mit Zitat antworten Zitat
Redeemer

 
Delphi 2009 Professional
 
#14
  Alt 26. Aug 2017, 21:21
SVG2 ist, ebenso wie HTML4 und HTML5, im Allgemeinen kein gültiges XML. XHTML und ich glaube auch SVG1 waren XML. Für SVG2 steht das nirgendwo ganz konkret, aber im Draft steht:
Zitat:
SVG is defined in terms of a document object model (DOM), rather than a particular file format or document type. For SVG content, therefore, conformance with this specification is defined by whether the content is or can generate a conforming DOM. Additional conformance classes depend on whether the content is also valid and well-formed XML.
Anschließend steht da mehr oder weniger, dass SVG nur XML ist, wenn es gültiges XML ist.
Der erste Satz der Spezifikation wurde von SVG1 zu SVG2 von "described in XML" in "based on XML" geändert.

HTML4 und HTML5 sind ganz eindeutig kein XML. <td>, <li> und viele weitere müssen ja nicht geschlossen werden.
  Mit Zitat antworten Zitat
samso
 
#15
  Alt 27. Aug 2017, 08:06
Danke für die Erklärung. Das klingt ja nicht so toll.
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

 
Delphi 10.2 Tokyo Enterprise
 
#16
  Alt 27. Aug 2017, 08:51
Ich verstehe die Spezifikation so, dass SVG alleine XML kompatibel ist, aber auch mit HTML Syntax in HTML-Dokumente eingebettet werden kann.

Gibt es bei SVG tatsächlich Elemente die gar nicht geschlossen werden müssen, oder nur die Möglichkeit von self closing tags?
Sebastian Jänicke
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi XE3 Professional
 
#17
  Alt 27. Aug 2017, 10:41
Wenn/da es mit XML kompatibel ist, müssen alle Elemente geschlossen sein.
Allgemein ist XML mit HTML kompatibel und mit XHTML sowieso, bzw. XHTML ist eigentlich eine Erweiterung von HTML, die mit XML kompatibel ist.
  Mit Zitat antworten Zitat
Redeemer

 
Delphi 2009 Professional
 
#18
  Alt 27. Aug 2017, 13:51
Ich verstehe die Spezifikation so, dass SVG alleine XML kompatibel ist, aber auch mit HTML Syntax in HTML-Dokumente eingebettet werden kann.
Welche hast du gelesen? SVG1 und SVG2 sind da komplett unterschiedlich. Der von mir zitierte Teil ist durch „can generate a conforming DOM“ ja schon sehr deutlich, dass eine SVG2-Datei weder XML noch DOM ist. Statt mir kompliziert das dazugehörige XML oder DOM zu generieren, habe ich mir lieber einen Parser geschrieben, der da toleranter ist.
Ich weiß gerade keine Tags, die nur optional geschlossen werden müssen, das liegt aber auch daran, dass ich keine Website finden konnte, wo das steht. selfHTML behandelt in der Hinsicht nur SVG1. Meine Klasse lädt übrigens auch das erste SVG-Bild in HTML-Dateien, was nicht unbedingt beabsichtigt ist, aber ein nettes Feature.
  Mit Zitat antworten Zitat
Redeemer

 
Delphi 2009 Professional
 
#19
  Alt 1. Sep 2017, 15:00
Habe die neue Version 0.2b-alpha um die Lösung mit dem alternativen UTF-8-Encoding ergänzt. Der Download enthält jetzt das Projekt für die Demoanwendung.

In dem Projekt, in dem ich das nutze, habe ich leider ein Problem:
Delphi-Quellcode:
type TSVGImage = class(TPNGImage)
  ...
end;

...

procedure DoSomething();
var
  GraphicClass: TGraphicClass;
  Graphic: TGraphic;
begin
  GraphicClass := TSVGImage;
  Graphic := GraphicClass.Create(); // Ruft TPNGImage.Create() auf. (schlecht)
  // ...aber...
  Graphic := TSVGImage.Create(); // Ruft TSVGImage.Create() auf. (gut)
end
Das liegt wohl daran, dass ich bei Create reintroduce verwende statt override, denn die CreateBlank-Methode des zugrundeliegenden PNG-Bilds benötigt die Create-Methode des PNG-Bilds, weshalb ich Create nicht überschreiben kann. Habt ihr da Ideen?
  Mit Zitat antworten Zitat
TiGü

 
Delphi 10.1 Berlin Enterprise
 
#20
  Alt 1. Sep 2017, 15:21
]Das liegt wohl daran, dass ich bei Create reintroduce verwende statt override, denn die CreateBlank-Methode des zugrundeliegenden PNG-Bilds benötigt die Create-Methode des PNG-Bilds, weshalb ich Create nicht überschreiben kann. Habt ihr da Ideen?
Hä, wieso nicht override?
Du rufst doch den TPNGImage.CreateBlank innerhalb deines TSVGImage.Create auf. Muss doch gehen ohne reintroduce.

Delphi-Quellcode:
...
  public
    constructor Create(); override;
    procedure LoadFromStream(Stream: TStream); override;
end;

constructor TSVGImage.Create;
begin
  inherited CreateBlank(COLOR_RGBALPHA, 8, 1, 1); // 0 führt beim Setzen einer neuen Größe zum Fehler
end;
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:18 Uhr.
Powered by vBulletin® Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2017 by Daniel R. Wolf