AGB  ·  Datenschutz  ·  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 30. Okt 2018
Antwort Antwort
Seite 1 von 5  1 23     Letzte » 
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 12 Athens
 
#2
  Alt 24. Aug 2017, 18:44
Hallo Redeemer,

schön das sich mal jemand dieses Themas annimmt.
Ich finde SVG ist ein total unterschätztes Format, und die bisherigen Lösungen die ich gesehen habe sind viel zu fett.
Deine kleine Library, mit den Basic-Funktionen und wenn möglich Support für Layer, wäre genau das was ich suche.
Ist das jetzt bei dir der Plan als Freeware, OpenSource, o.ä. anzubieten ?

Ich hätte mal folgende Frage, weil ich sehe das du Referenzen zu Windows/GDI drinhast.
Wärest du daran interessiert die Library für VCL und FMX fit zu machen, oder ist das schon dein Plan ?
Ich verstehe aber das du mit D2009 unterwegs bist, das könnte schwierig werden

Ansonsten muss ich leider berichten das ich die Beispielbilder mit deiner Demo nicht
laden kann.
Vermutlich waren das die Fehlerbilder für uns zum Testen, richtig ?
In den Code habe ich noch nicht tiefer geschaut, ich denke das DemoProgramm dafür fehlt, deshalb kann ich auch nicht debuggen.
Einfachere SVG kann ich aber mit dem Demo anzeigen lassen, das ist schonmal super.

Rollo
  Mit Zitat antworten Zitat
bepe
 
#3
  Alt 24. Aug 2017, 19:23
Das ist interessant. Wegen der hochauflösenden Monitore spiele ich mit dem Gedanken, die Png's für Toolbar und co. durch SVG's zu ersetzen. Werde ich mir ansehen...

Aber spontan ist mir das ins Auge gefallen:

[*]Andere Codepages als UTF-8. UTF-8 ist der Standard, ärgerlich ist das nur, weil TStringList.LoadFromStream() mit TEncoding.UTF8 im Fall von ungültigen UTF-8-Codes überhaupt nichts tut.
Versuch das:
Delphi-Quellcode:
type
  TCustomUTF8Encoding = class(TUTF8Encoding)
  public
    constructor Create; override;

  end;
...
{ TCustomUTF8Encoding }

constructor TCustomUTF8Encoding.Create;
begin
  inherited Create(CP_UTF8, 0, 0); // Embas UTF8 setzt MB_ERR_INVALID_CHARS und führt zu dem Problem
  FIsSingleByte := False;
end;
Hier die Erklärung für die Flags. Mehr kann ich nicht schreiben, sonst ärgere ich mich schon wieder maßlos über die RTL- und VCL-Klassenstrukturen...
  Mit Zitat antworten Zitat
Redeemer

 
Delphi 2009 Professional
 
#4
  Alt 24. Aug 2017, 23:23
Hallo Redeemer,

schön das sich mal jemand dieses Themas annimmt.
Ich finde SVG ist ein total unterschätztes Format, und die bisherigen Lösungen die ich gesehen habe sind viel zu fett.
Deine kleine Library, mit den Basic-Funktionen und wenn möglich Support für Layer, wäre genau das was ich suche.
Was ist mit Layer gemeint?

Ist das jetzt bei dir der Plan als Freeware, OpenSource, o.ä. anzubieten ?
Keine Ahnung. Dieser Post war nur die Frage, ob überhaupt Interesse an einer ausdrücklich kleinen SVG-Bibliothek besteht.

Ich hätte mal folgende Frage, weil ich sehe das du Referenzen zu Windows/GDI drinhast.
Wärest du daran interessiert die Library für VCL und FMX fit zu machen, oder ist das schon dein Plan ?
Ich verstehe aber das du mit D2009 unterwegs bist, das könnte schwierig werden
Ich ahbe auch XE2 hier rumliegen, nutze ich nur recht selten. Was meinst du mit VCL? Das Teil registriert sich als VCL-Bildklasse.
Da FMX ja plattformunabhängig ist, frage ich mich auch, inwieweit das mit GDI machbar sein soll.

Ansonsten muss ich leider berichten das ich die Beispielbilder mit deiner Demo nicht
laden kann.
Vermutlich waren das die Fehlerbilder für uns zum Testen, richtig ?
In den Code habe ich noch nicht tiefer geschaut, ich denke das DemoProgramm dafür fehlt, deshalb kann ich auch nicht debuggen.
Einfachere SVG kann ich aber mit dem Demo anzeigen lassen, das ist schonmal super.

Rollo
Die Niedersachsenkarte geht, es dauert nur etwas (20 Sekunden auf meinem Laptop). Bei 1 MB Quelltext, der verarbeitet werden muss...
Das Bild der Landshut funktioniert wie erwähnt nur, wenn man die Höhenangabe (height) aus dem SVG-Tag löscht. Ich habe kurz vor Release Support für die wissenschaftliche e-Schreibweise von Zahlen eingebaut und übersehen, dass ich den Exponenten nur auf Kommazahlen, nicht jedoch auf Ganzzahlen (wie hier 1e3) anwende (letzte Zeile von RedeemerFloat, ergänze "* Exponent").

Das ist interessant. Wegen der hochauflösenden Monitore spiele ich mit dem Gedanken, die Png's für Toolbar und co. durch SVG's zu ersetzen. Werde ich mir ansehen...
Man müsste echt mal evaluieren, wie schlimm das Fehlen des ArcTo-Befehls von path ist. Ich glaube, ich habe das unterschätzt. Gut dokumentiert wird es, nur widerspricht diese Demo meiner Meinung nach der Formel.

Aber spontan ist mir das ins Auge gefallen:

[*]Andere Codepages als UTF-8. UTF-8 ist der Standard, ärgerlich ist das nur, weil TStringList.LoadFromStream() mit TEncoding.UTF8 im Fall von ungültigen UTF-8-Codes überhaupt nichts tut.
Versuch das:
Delphi-Quellcode:
type
  TCustomUTF8Encoding = class(TUTF8Encoding)
  public
    constructor Create; override;

  end;
...
{ TCustomUTF8Encoding }

constructor TCustomUTF8Encoding.Create;
begin
  inherited Create(CP_UTF8, 0, 0); // Embas UTF8 setzt MB_ERR_INVALID_CHARS und führt zu dem Problem
  FIsSingleByte := False;
end;
Hier die Erklärung für die Flags. Mehr kann ich nicht schreiben, sonst ärgere ich mich schon wieder maßlos über die RTL- und VCL-Klassenstrukturen...
Danke, werde ich mir mal ansehen.

/Edit: Die Grenze zwischen Äthiopien und Eritrea fehlt in Firefox und im Wikimedia-Rasterisierer, worauf auch immer der basiert. Umso lustiger, dass sie in einer früheren Version meiner Engine da war, wonach ich kaum noch was geändert habe...
Miniaturansicht angehängter Grafiken
entfuehrung-der-landshut-alt.png  
Janni

Geändert von Redeemer (24. Aug 2017 um 23:44 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von DerAndereMicha
DerAndereMicha

 
Delphi 2007 Enterprise
 
#5
  Alt 25. Aug 2017, 09:21
Hallo Redeemer,

ein wirklich tolles Projekt, aber leider mit derartigen Ladezeiten (noch) nicht wirklich nutzbar.

Diese Karte:

https://commons.wikimedia.org/wiki/F...cation_map.svg

wird zwar geladen, Dein Demo braucht dazu aber, statt wie der Browser < 1 Sekunde, bei mir auf dem PC über 7 Sekunden. Da gibt es doch bestimmt noch einiges zu optimieren, oder?

Andere Dateien scheinen allerdings überhaupt nicht zu funktionieren:

https://upload.wikimedia.org/wikiped...cation_map.svg

zumindest habe ich hier nach 5 Minuten Eieruhr das Programm abgebrochen.

Ich finde Dein Projekt durchaus interessant, vor allem weil es bisher keine freie Komponente zu geben scheint, die auch wirklich produktiv nutzbar ist. Das es mit Delphi durchaus kompakt und schnell funktioniert, zeigt diese kommerzielle Komponente, welche ich momentan für eines meiner Projekte nutze.

Gruß
Micha
  Mit Zitat antworten Zitat
Rollo62

 
Delphi 12 Athens
 
#6
  Alt 25. Aug 2017, 11:13
Wieso lädt das bei euch ?

Wenn ich die Datei mit deinem Demo öffne, mit Lade SVG, z.B. das letzte mit Germany_location_map.svg, dann kommt das siehe Anhang.
Genauso bei den beiden orginalen Beispielen.

Nur sehr einfache Icons hatte ich noch getestet, die funktionierten.

Rechner: Win10-Pro aktuell

Rollo
Miniaturansicht angehängter Grafiken
clipboard03.jpg  
  Mit Zitat antworten Zitat
Redeemer

 
Delphi 2009 Professional
 
#7
  Alt 26. Aug 2017, 01:21
Keine Ahnung, warum es bei dir nicht läuft. Habe das mit der Geschwindigkeit korrigiert (bei größeren Dateien locker Faktor 100 und mehr), da ich wegen Bahnchaos seit langer Zeit in einer Stadt festsitze, die es noch nicht mal gibt.
Grund für die Performanceprobleme war praktisch nur eine einzige Funktion: StrUtils.MidStr. Meine eigenen Funktionen waren nicht Schuld. Habe MidStr durch Copy ersetzt und einige andere Optimierungen mit Generics.Collections.TDictionary durchgeführt. Changelog liegt bei.
Link hat sich nicht geändert.

Danke für das Feedback schonmal. Warum es bei dir nicht geht, Rollo, weiß ich nicht. Kannst ja mal probieren, das selbst zu kompilieren.
Janni
  Mit Zitat antworten Zitat
Benutzerbild von DerAndereMicha
DerAndereMicha

 
Delphi 2007 Enterprise
 
#8
  Alt 26. Aug 2017, 09:36
Zitat:
Habe das mit der Geschwindigkeit korrigiert (bei größeren Dateien locker Faktor 100 und mehr),
Super! Zwar ist es immer noch nicht ganz so schnell wie die kommerzielle Konkurrenz, aber jetzt scheint es mir auf jeden Fall produktiv nutzbar zu sein. Ich werde es bei Gelegenheit mal versuchen in meinem Projekt testweise einzusetzen.

Ab welcher Delphi-Version ist es kompilierbar?

Gruß
Micha
  Mit Zitat antworten Zitat
Redeemer

 
Delphi 2009 Professional
 
#9
  Alt 26. Aug 2017, 12:08
Ist mit Delphi 2009 geschrieben. Sollte aber mit allen nachfolgenden laufen, da es nur sehr wenige grundlegende Delphifunktionen verwendet und stattdessen viele GDI-API-Calls.
Janni
  Mit Zitat antworten Zitat
Benutzerbild von DerAndereMicha
DerAndereMicha

 
Delphi 2007 Enterprise
 
#10
  Alt 26. Aug 2017, 13:17
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
  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:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:37 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz