Codelab Hilfe Teil 5 - Kleinkram

Sonderbare Dinge

Wenn Sie bisher mitgemacht haben, haben Sie eine Menge darüber gelernt, wie Plugins funktionieren und zusammengesetzt sind. Vielleicht haben Sie aber auch einige Ideen für Plugins, die nicht in die übliche Form passen. Sie wissen zum Beispiel, dass ein Plugin in jedes Pixel der Zielleinwand schreiben muss... aber was, wenn Sie nicht in jedes Pixel schreiben wollen? Zum Beispiel, um Text auf der Leinwand zu rendern oder Linien/Formen zu zeichnen? Nun, auch so etwas können wir mit CodeLab machen.

Ich habe hier auch einige andere Tipps und Tricks aufgeführt, die ich im Laufe der Zeit gelernt habe. Die meisten der Skripte hier habe ich selbst geschrieben, einige aber auch nicht. Ich habe diese Ideen hier an einem Ort gesammelt, damit Sie und ich sie leicht finden können, wenn wir ein Plugin schreiben wollen.

Schauen Sie sich die Abschnitte unten an. Ich hoffe, Sie finden hier etwas, das Ihnen nützlich ist.

Text

Das Rendern von Text auf das Bild ist interessant, weil beim Rendern von Text nicht jedes Pixel geschrieben wird.

Damit dies richtig funktioniert, müssen wir sicherstellen, dass jedes Pixel auf die Zielleinwand geschrieben wird. Das geht am einfachsten, indem man alle Pixel von Src nach Dst kopiert und dann den Text auf die Dst-Leinwand rendert.

Beginnen wir mit dem Standardskript:

Hier Beispielcode

Nun, für dieses einfache Beispiel brauchen wir keine UI-Steuerelemente, also löschen Sie diese. Wir brauchen auch keine der Variablen (außer der ersten, der Auswahl), also werden Sie sie los. Und da wir nicht über jedes einzelne Pixel im Ziel-Canvas eine Schleife ziehen werden, können Sie auch diese inneren Schleifen loswerden!

OK, so weit, das ist, was wir haben:

Hier Beispielcode

Als Erstes müssen wir sicherstellen, dass alle Pixel von der Ausgangsleinwand auf die Zielleinwand kopiert werden. Das können wir mit einer einzigen Codezeile erreichen. Verwenden Sie einfach CopySurface, etwa so:

Hier Beispielcode

Nun, da alle Pixel auf der Zielleinwand geschrieben (von der Quellleinwand kopiert) wurden, können wir einen Text darauf schreiben.

Da wir GDI+ verwenden werden, um die Textzeichenfolge auf die Leinwand zu zeichnen, müssen wir einige Dinge erstellen, damit es funktioniert. Wir brauchen eine Grafikoberfläche, einen Pinsel und eine Schriftart.

Zunächst erstellen wir mit dem folgenden Code eine Grafikoberfläche aus unserer Zielleinwand:

Hier Beispielcode

Denken Sie daran, dass Paint.NET Ihren Effekt in ROI-Arbeitseinheiten aufteilt. Wir müssen also sicherstellen, dass wir beim Zeichnen unseres Textes nicht versehentlich außerhalb unserer aktuellen Arbeitseinheit schreiben. Um dies zu tun, müssen wir auf das aktuelle ROI beschneiden:

Hier Beispielcode

Als Nächstes müssen wir einen Pinsel erstellen, um damit zu schreiben. Wir erstellen einen einfarbigen Pinsel mit einer bestimmten Farbe, z. B. Rot:

Hier Beispielcode

Dann müssen wir die Schriftart erstellen, die wir verwenden werden:

Hier Beispielcode

Wenn Sie all diese Zeilen in unser Skript einfügen, sollte es jetzt so aussehen:

Hier Beispielcode

Nun, da alles erstellt ist, müssen wir nur noch die Funktion DrawString aufrufen, um den Text auf die Zielleinwand zu schreiben:

Hier Beispielcode

Fertig!

Natürlich ist dies ein sehr einfaches Beispiel und es gibt viel Raum für Verbesserungen. Ausgehend von diesem einfachen Skript wollen wir uns nun ansehen, was es bedeuten würde, weitere Optionen hinzuzufügen und den Text zu entzerren.

Anti-Alias-Text

Wenn Sie nicht angeben, dass Ihr Text mit einem Anti-Alias-Effekt gerendert werden soll, wirkt er in der Regel sehr blockig. Um den Text zu entzerren, geben Sie einfach die Grafik TextRenderingHint an.

Es stehen mehrere Methoden zur Verfügung, um Text zu entzerren. Wählen Sie Ihre Methode und fügen Sie die entsprechende Zeile in Ihr Skript ein:

Hier Beispielcode

Unser erweitertes und verbessertes Skript sollte nun folgendermaßen aussehen:

Hier Beispielcode

Experimentieren Sie mit jeder Methode, um zu sehen, was sie bewirkt.

Da wir nun wissen, wie man Text richtig zeichnet, wollen wir dieses einfache Skript zu einem Plugin mit mehr Funktionen, einer Benutzeroberfläche und einstellbaren Parametern ausbauen:

Hier Beispielcode

Anti-Alias-Linien/Formen

Genau wie beim Zeichnen von Text müssen wir auch beim Zeichnen von Linien und Formen auf der Leinwand sicherstellen, dass wir die Ausgangsleinwand auf die Zielleinwand kopieren, bevor wir unser Material zeichnen.

Dann müssen wir den SmoothingMode der Leinwand wie folgt einstellen:

Hier Beispielcode

Hier ist ein Beispielskript, das 2 Linien auf die Leinwand zeichnet, eine mit und eine ohne Aliasing:

Hier Beispielcode

Vergrößern Sie die Ansicht und sehen Sie sich die beiden Linien an, die gezeichnet wurden. Die Linie auf der rechten Seite ist glatter als die auf der linken Seite.

Clipboard / Zwischenablage

Der Zugriff auf die Zwischenablage von einem Paint.NET-Plugin aus ist etwas knifflig. Man kann nur von einem STA-Thread aus auf die Zwischenablage zugreifen. Hier ist ein Plugin, um etwas aus der Zwischenablage in die aktuelle Auswahl einzufügen. Wenn die Grafik in der Zwischenablage kleiner ist als die Auswahl, wird sie wiederholt.

Hier Beispielcode

Am unteren Ende des Codes sehen Sie die Standard-Render-Schleifen. Beim ersten Versuch, das Bild aus der Zwischenablage zu lesen, wird es für Sie geladen.

Das Lesen von Text aus der Zwischenablage ist eine Übung, die dem Leser überlassen bleibt.

HSV-Farben

Normalerweise wird auf Farben im RGB-Modell zugegriffen, indem einfach die Methoden CurrentPixel.R, CurrentPixel.G und CurrentPixel.B verwendet werden. Manchmal ist es jedoch erwünscht, auf die Farben im HSV-Modell zuzugreifen.

Um CurrentPixel in HSV zu konvertieren, gehen wir folgendermaßen vor:

Hier Beispielcode

Sobald Sie die H-, S- und V-Werte geändert haben, können Sie sie mit dem folgenden Code wieder zu einem ColorBgra-Pixel (dem Standardpixeltyp von Paint.NET) zusammensetzen:

Hier Beispielcode

Von hier aus würden Sie NewPixel auf der Zielleinwand speichern, damit Sie das Ergebnis sehen können.

Hier sehen Sie ein Beispielskript, das die HSV-Bearbeitung verwendet:

Hier Beispielcode

Marschierende Ameisen ("Marching Ants") / Auswahl

"Marching Ants" nenne ich die Auswahlgrenze, weil sie in früheren Versionen von Paint.NET durch etwas angezeigt wurde, das wie eine Linie marschierender Ameisen aussah. In der aktuellen Version von Paint.NET wird die Auswahl durch eine durchgehende XOR-Linie gekennzeichnet. Die Marschierende Ameisen wurden in aktuellen Paint.Net-Versionen aus Performancegründen entfernt, aber vielleicht tauchen auch mal wieder auf, in Zukunft.

Was ist, wenn Sie einen Effekt (oder eine Änderung) nur auf die Pixel direkt neben dem Rand der Auswahl anwenden möchten? Schauen wir uns zum Beispiel meinen Effekt Auswahl > Umriss an.

Beginnen wir mit dem Standardskript und löschen wir alles, was wir nicht brauchen. Entfernen Sie zunächst alle UI-Steuerelemente außer dem ersten. Als Nächstes entfernen wir alle Variablen, die wir nicht benötigen, und die Kommentare innerhalb der inneren Schleife:

Hier Beispielcode

Als nächstes müssen wir eine Variable erstellen, die die Form der Auswahl enthält:

Hier Beispielcode

Mit diesem Code können wir prüfen, ob ein Pixel ausgewählt ist:

Hier Beispielcode

Jedes Pixel in der inneren Schleife befindet sich innerhalb einer Auswahl, da Paint.NET keine Pixel zur Bearbeitung sendet, die nicht ausgewählt sind. Wir müssen eine Schleife innerhalb der inneren Schleife erstellen, um die Pixel um das aktuelle Pixel, an dem wir arbeiten, daraufhin zu überprüfen, ob diese Pixel ausgewählt sind oder nicht. Wenn wir ein Pixel finden, das nicht ausgewählt ist, wissen wir, dass wir uns nahe am Rand unserer Auswahl befinden und müssen daher das aktuelle Pixel durch ein anderes ersetzen.

Fügen wir den obigen Code zu unserem Skript hinzu:

Hier Beispielcode

Als Nächstes erstellen wir die inneren Schleifen auf der Grundlage der gewünschten Konturbreite:

Hier Beispielcode

Und schließlich, wenn wir feststellen, dass wir uns in der Nähe des Randes der Auswahl befinden, ersetzen wir das Pixel durch ein rotes Pixel.

Hier Beispielcode

Fertig!

Sie sollten wissen, dass dieser Code zwar funktioniert, aber sehr langsam ist. Immerhin ist es die Überprüfung LOTS of Pixel für jedes Pixel, das ausgewählt wird - viele Male mehr als einmal!

Was Sie oben sehen, war im Grunde die erste Version meines Plugins Auswahl > Umriss (mit der zusätzlichen Möglichkeit, die Ersatzfarbe auszuwählen). Das ist nicht der Code des Plugins, das Teil meines Pakets ist. Es war einfach zu langsam und bietet keine Möglichkeit, die gezeichneten Umrisse zu verfremden. Nun, da Sie neugierig sind, hier ist der Code des Plugins in meinem Paket:

Hier Beispielcode

In dieser Version gibt es zwei grundlegende Verbesserungen. Erstens wird die Funktion GetMatrix verwendet, um einen runden Stift zum Zeichnen der Kontur zu erstellen. Dies verleiht dem gezeichneten Umriss eine natürlichere Form und bietet die Möglichkeit, einen Umriss mit Anti-Aliasing zu zeichnen. Zweitens wird versucht, die Überprüfung vieler Pixel zu überspringen, um das Zeichnen zu beschleunigen.

Der Aufruf von selectionRegion.IsVisible ist sehr langsam, so dass ich versuche, ihn nur bei Bedarf aufzurufen. Woher soll ich wissen, ob es notwendig ist? Gut, dass Sie fragen. Ich habe mir die gleiche Frage gestellt, und Ed Harvey hat mir Folgendes beigebracht: Im Grunde genommen überprüfen wir Pixel, eines nach dem anderen, in einer Reihe. Daher befindet sich das zu prüfende Pixel direkt rechts neben dem zuvor geprüften Pixel. Wenn das zuvor geprüfte Pixel nicht in der Nähe einer Kante lag und viele der umliegenden Pixel unseres aktuellen Pixels sich mit dem vorherigen Pixel überschneiden, brauchen wir diese umliegenden Pixel nicht noch einmal zu prüfen. Hier ist eine Illustration dessen, wovon ich spreche:

Hier Beispielbild

Beachten Sie im Bild, dass die umliegenden Pixel, die für das vorherige Pixel (P) geprüft wurden, in Rot dargestellt sind. Die umliegenden Pixel des aktuellen Pixels (C) sind blau dargestellt. Die Pixel, die sich überschneiden, sind lila dargestellt. Wenn das vorherige Pixel nicht in der Nähe einer Kante lag, muss nur die Vorderkante (die rechte Kante) der umliegenden Pixel geprüft werden (blau dargestellt). Dies ist eine enorme Einsparung! Die meisten Änderungen in den inneren Schleifen beziehen sich auf die Verfolgung dieser Optimierung.

Weitere Beispiele

Hier Link zu einer Folgeseite, die noch nicht erstellt ist

Alle Seiten mit Tag Codelab