2012-10-04 3 views
11

Ich habe ein langwieriges Projekt: ein grundlegendes Vektorgrafikwerkzeug, das im Browser läuft und SVG und Javascript benutzt (vielleicht hast du das irgendwo anders gesehen). Das Tool hat nur sehr begrenzte Funktionen, da die Zielgruppe eingeschränkt ist und der Zweck sehr spezifisch ist und es tatsächlich nicht erlaubt ist, andere Funktionen zu verwenden als das, was explizit erlaubt ist (Sie wissen schon). Eine verpasste Eigenschaft ist das Erodieren (auch bekannt als einfügend oder dünn) und das Erweitern (Anfang, Verdicken, bolden) Polygone und andere grafische Elemente.Wie kann ich Offset Path Effect in SVG implementieren, ohne Javascript zu verwenden oder Filter zu erweitern/erodieren?

Ich habe den Offset Path Effect von Adobe Illustrator viele Male benutzt und damit kann ich leicht Kopien von verdünnten oder verdickten Grafikobjekten machen, ohne das ursprüngliche Objekt zu beeinflussen, was also fast alles ist, was das Programm unterstützt.

Ich habe versucht, die gleiche Funktionalität zu bekommen, um in SVG zu funktionieren, aber ohne Erfolg.

Ich habe versucht, die folgenden:
- aufzuweiten und Filter erodieren, aber mit nicht befriedigenden Ergebnissen (please see the image here)
- Serverseitige Pythons Shapely Bibliothek, aber diese Abhilfe ist zu langsam und ermöglicht Einsatz oder Anfang nur die Grund Polygone (description here)
- JavaScript-Bibliothek/Code/Funktion zu finden, die die Pfaddaten von grafischen Elementen verändern könnten, aber nichts gefunden für Javascript

So ist es eine sinnvolle Möglichkeit, diese wie Offset-Pfad-Effekt zu implementieren und Wie?

+1

Siehe auch [dieses Papier] (https://hal.inria.fr/inria-00518005/document) –

Antwort

19

Dies ist eine "Beantworten Sie Ihre eigene Frage - share your knowledge, Q&A-style" -Style Antwort, aber wenn Sie eine bessere Antwort haben, bitte benutzen Sie frei Ihre Tastatur.

Ich habe SO nur ein paar Tage verwendet, also bitte nicht mich zu der Lücke runtersetzen. Ich habe eine interessante workaround idea zu diesem Problem, das auf Strichen und Masken mit variabler Breite basiert.

Aber fangen wir mit Ihrer (oder meiner) ersten Idee an. Wenn wir (dünne) grafische Objekte in SVG erodieren, ist der offensichtliche erste Gedanke, erodieren Filter:

Aber weil erodieren Filter (und erweitern auch) uses pixel data (the rasterized path) das Ergebnis ist nicht gut in allen Fällen. Tatsächlich habe ich nie ein gut aussehendes Erodieren gesehen, wenn es verwendet wurde, um Vektorobjekte zu filtern. Sehen Sie den Hut und den Mund:

Eroded image

Der dilate Filter ähnliche Probleme hat (die Nase ist nicht schön und die Baseball-Kappe ist lückenhaft und einige andere Ungereimtheiten):

Dilated image

Alle Benutzer von Adobe Illustrator kennen die schönen Pfadeffekte, mit denen verschiedene Pfadoperationen auf Formen (Objekte) angewendet werden können. Diese Effekte ändern die ursprünglichen Pfaddaten nicht, sie erstellen nur eine geänderte Kopie des Objekts. Eine der nützlichsten Funktionen ist Offset Path Effect, die verwendet werden kann, um vom ausgewählten Objekt um eine bestimmte Entfernung (oder etwas Ähnliches) abzuheben. SVG: s erodieren und dilatieren Filter haben Ähnlichkeiten mit Illustrator Offset Path Effect, aber die Qualität ist als Vektor-Operation (im Gegensatz zu Bitmap) hoch.

SVG-Format im aktuellen Zustand, keine Unterstützung für Illustrator-ähnliche Offset-Pfad, aber es ist möglich, die gleiche Funktionalität mit variabler Breite Striche und Masken wie notiert here.

Lassen Sie uns in die Welt der SVG-Masken eintauchen. Die Dilatation (oder Anfangsweg oder Verdickung) ist möglich, indem man einfach eine Strichbreite vergrößert, aber erodiert (oder eingesetzter Pfad oder Ausdünnung) braucht etwas mehr, zum Beispiel Masken. In SVG kann jedes Grafikobjekt oder Element 'g' als Alpha-Maske zum Zusammensetzen des aktuellen Objekts in den Hintergrund (W3C SVG 1.1 Recommendation) verwendet werden.

Obiges bedeutet, dass nicht nur die Füllung eines Objekts als Maske, sondern auch ein Strich verwendet werden kann. Und die Breite des Striches des Pfades, der als Maske verwendet wird, kann eingestellt werden, wie viel des aktuellen Objekts (in das die Maske unter Verwendung des Maskenattributs angewendet wird) maskiert wird.

Lassen Sie uns ein Beispiel für die Verwendung von Maske erhalten. Zuerst definieren wir einen Weg in SVG: s defs Element:

<defs> 
<path id="head_path" d="M133.833,139.777c1 ...clip... 139.777z"/> 
</defs> 

Wenn wir einen Weg in defs Elemente definieren, beseitigt die Notwendigkeit für die gleichen Daten in anderen Teilen des Dokuments zu wiederholen. Das ID-Attribut des Pfads wird verwendet, um auf den Pfad von einem oder mehreren Punkten des Dokuments zu verweisen.

Jetzt können wir diesen Weg Daten in der Maske verwenden:

<defs> 
... 
<mask id="myMask" maskUnits="userSpaceOnUse"> 
<use xlink:href="#head_path" fill="#FFFFFF" stroke="#000000" 
stroke-width="18" stroke-linecap="round" stroke-linejoin="round"/> 
</mask> 
... 
</defs> 

die ‚Verwendung‘ Element Verweise auf das ‚Pfad‘ Element, deren ID ist ‚head_path‘ und zeigt an, dass die grafischen Inhalte (in diesem Fall nur die Pfaddaten) des Elements 'head_path' sind in dieser Maske enthalten. Die Strichbreite, die auf dem obigen Element 'usage' definiert ist, ist der Betrag des Offset (erode) -Effekts. Dieser Betrag wird für den Fall, dass wir als nächstes zeichnen, aus dem Element ausgeblendet.

Okay, lassen Sie uns zeichnen zuerst den 'Kopf', ohne zu sehen, Maskierung, wie schön es ist:

... 
</defs> 
<use x="5" y="5" xlink:href="#head_path" fill="#4477FF" stroke="black" 
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> 

Das folgende Form erzeugt:

Original shape

Jetzt testen, was wir können, erreichen mit der Maske:

... 
</defs> 
<use x="5" y="5" xlink:href="#head_path" fill="#22EE22" stroke="black" 
stroke-width="21" stroke-linecap="round" stroke-linejoin="round" 
mask="url(#myMask)"/> 

Das oben genannte 'verwenden' Element i s wurde angewiesen, 'myMask' als Maske und 'head_path' als grafischen Inhalt zu verwenden. Die Maske Effekt wird auf die ‚Verwendung‘ Element angelegt und die folgende Form gezogen:

Masked shape

Wenn wir beide oben auf jedem Stapel, wir den ursprünglichen Kopf in den maskierten Kopf vergleichen:

Original and masked shape

Nicht schlecht? Vergleichen sie der erste Versuch mit SVG gefilterte Version auf die maskierte Version erodieren:

Eroded vs masked

Die linke ist erodieren-filtriert und die richtigen maskierter Illustrator artigen Offset-Pfad-Effekt zu imitieren. Keine seltsamen Artefakte in Hut und Mund!

Wie wäre es dann erweitern?Gibt es eine Möglichkeit, die Wegtreue auf der Nase und der Abschürfung der Baseballkappe zu entfernen? Sicher. Und die Methode ist wirklich einfach, aber irgendwie Hack. Glücklicherweise müssen keine Masken verwendet werden. Stattdessen können wir die Strichstärke anpassen, um den gewünschten Effekt zu erzielen. Und da der Strich bereits für die Betonung verwendet wird, müssen wir eine zusätzliche Kopie des Elements mit einem etwas breiteren Strich hinzufügen, um einen schwarzen Strich um die gebogene Form zu erhalten (0).

<!-- To get the black stroke --> 
<use x="220" y="5" xlink:href="#head_path" fill="red" stroke="black" 
stroke-width="24" stroke-linecap="round" stroke-linejoin="round"/> 
<!-- To get the boldened shape --> 
<use x="220" y="5" xlink:href="#head_path" fill="red" stroke="red" 
stroke-width="21" stroke-linecap="round" stroke-linejoin="round"/> 

Daraus ergibt sich die folgende Form:

Offset Path Effect applied

Hier sind sowohl die ursprüngliche Form und das mit unseren kundenspezifischen Offset-Pfad-Effekt angewendet:

Original and Offset Path Effect applied

Wie unsere eigene boldening Filter aufzuweiten vergleicht:

Dilated vs Boldened

Der linke (oben) erweitert wird unter Verwendung von SVG: s Filter aufzuweiten, die richtige ist boldened unsere eigene Offset-Pfad-Effekt. Ziemlich nett, mag ich. Pfad folgt getreu dem ursprünglichen Weg in der gegebenen Entfernung und keine Anzeichen von Abschürfungen auf Baseballkappe.

Und schließlich wollen wir alle Drähte an einem Strang ziehen: Dilate/Origina/Erode vs Offset Path Combined

Der linke (oben) verwendet aufzuweiten/erodieren Filter von SVG und der rechten Seite verwendet man Illustrator-nachgeahmt Offset-Pfad-Effekt, der SVG-Maske wird unter Verwendung und dickere Striche. Welchen würdest du wählen?

Fazit: Wir sind nicht gezwungen, Javascript oder andere Skripte zu verwenden, um grafische Elemente in SVG zu verdichten oder zu verdünnen. Erodier- und Dilatationsfilter von SVG können einige Verwendungszwecke haben, aber sie sind nicht gut geeignet für qualitativ hochwertige Pfad- "Modifikationen". Masken sind ein wenig kompliziert zu bedienen, aber nach ein paar Experimenten werden Sie mit ihnen vertraut. Ich hoffe wirklich, dass SVG in Zukunft den Offset Path Effect nativ unterstützt, ohne dies wie Hacks zu benutzen.

ich jsfiddled die in diesen Beispielen verwendeten Formen für Sie mit Filtern und Masken zu spielen: http://jsfiddle.net/7Y4am/
(!-Test mindestens Strichbreiten zu ändern)

(Leider mein schlechtes Englisch, die Muttersprachler erhalten lachen bis sterben, aber bitte denken Sie daran, ich gehöre zu den 94% der Menschheit, die Englisch nicht nativ spricht. Aber zum Glück haben wir Google Translate.)

+0

Ich habe ein Beispiel für Text mit Offset Path Effect hinzugefügt: http://jsfiddle.net/BbYV6/. Wir müssen maskUnits = "objectBoundingBox" anstelle von maskUnits = "userSpaceOnUse" verwenden, um die Maske an die richtige Stelle zu bringen. Und wir bevorzugen Schlaganfall-Liniejoin = "Gehrung" statt Schlagliniejoin = "Runde". Und leider, wegen des Fehlens von Kerning-on-the-Fly, ist Kerning, was der Browser will. Wenn Sie Ideen haben, teilen Sie sie bitte: http://stackoverflow.com/questions/12654826/kerning-on-the-fly. –

+0

Die blöde Sache ist, dass SVG ein rechteckiges strukturierendes Element für morphologische Operationen verwendet. Die Leute wollen wahrscheinlich runde. – nraynaud

+1

http://sourceforge.net/p/jsclipper/wiki/Home/ Ich habe gerade gefunden, dass – nraynaud

Verwandte Themen