Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Canvas.TextOut mit Text Shadow-Erweiterung (https://www.delphipraxis.net/161879-canvas-textout-mit-text-shadow-erweiterung.html)

s.h.a.r.k 25. Jul 2011 19:49

Canvas.TextOut mit Text Shadow-Erweiterung
 
Einen wunderschönen guten Abend zusammen,

hatte mir vor ein paar Tagen gedacht, dass ich "schnell" mal eine TextOut-Methode schreibe, die mir einen Text auf ein Canvas druckt -- was das normale TextOut() bisher ja kann -- und eben dazu noch einen passenden Schatten, analog zum CSS text-shadow.

So, meine Idee war die folgende: ich drucke in ein Buffer-Bitmap (PixelFormat: pf32bit, AlphaFormat: afDefined) den Text (übliches TextOut), lasse einen Weichzeichner drüber laufen (Gaussian Blur), pinsel die Bitmap auf das Canvas und drucke dann via dem üblichen TextOut den Text drauf. Soweit, so gut, aber ich habe nicht bedacht, dass mit hier die fehlende Transparenz einen Strich durch die Rechnung macht.

Ich hatte mir überlegt, das Bitmap komplett auf transparent, also bei jedem Pixel den Alpha-Kanal auf 0, zu setzen. Drucke ich den Text dann drauf, bleibt jedes Pixel transparent -> schlecht. Den Text direkt auf das Canvas drucken und darauf blurren ist blöde, da ja schon vorher etwas auf dem Canvas sein kann.

Irgendwie fällt mir im Moment nichts ein, wie ich dem Problem beikommen könnte. Ich will doch einfach nur einen Text auf einen transparenten Layer drucken, diesen blurren und unter Beachtung des Alpha-Kanals diesen Layer auf ein Canvas bringen :wall:

jfheins 25. Jul 2011 20:11

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
text auf ein Canvas malen, invertieren und als alphawerte für ein neues (komplett schwarzes) Bild hernehmen ;-)

Also quasi wie deine erste Lösung, nur statt einem schwarz/weiß übergang eben ein schwarz/transparent Übergang. (= statt einem Pixel mit wert 200 einen mit 0 und alpha = 55)

Namenloser 26. Jul 2011 06:18

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
[edit]irrelevant[/edit]

s.h.a.r.k 26. Jul 2011 10:31

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Zitat:

Zitat von jfheins (Beitrag 1113501)
text auf ein Canvas malen, invertieren und als alphawerte für ein neues (komplett schwarzes) Bild hernehmen ;-)

Also quasi wie deine erste Lösung, nur statt einem schwarz/weiß übergang eben ein schwarz/transparent Übergang. (= statt einem Pixel mit wert 200 einen mit 0 und alpha = 55)

Okay, der Trick ist mir nicht wirklich eingefallen, danke dir! Aber wie genau pinsel ich das dann auf ein Canvas?! Ich habe keinerlei Methode gefunden, die mir das mit einer solchen Bitmaske zeichnet.

-- Edit: Bin evtl. doch fündig geworden -> AlphaBlend. MaskBlt ist ja scheinbar nur für "1-Bit-Transparenz".

Sailor 26. Jul 2011 10:45

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Setze vor dem Textout den Hintergrund auf Transparent:

SetBkMode(Canvas.Handle,Windows.Transparent)

Dann bleibt der Hintergrund unter dem Text erhalten.

s.h.a.r.k 26. Jul 2011 10:53

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Wenn ich dann aber das den Gaussian Blur anwende, wird quasi alles geblurrt und das will ich ja nicht. Daher ja die Idee mit dem transparenten Puffer-Layer, der dann später auf das Canvas gepinselt werden soll.

Sailor 26. Jul 2011 11:20

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Verstehe ich nicht, das Weichzeichnen ist doch schon auf dem Bitmap erfolgt.
Der wird jetzt auf den Canvas gezeichnet und dann anschließend an die gleiche
Position nochmals den Text auf den Canvas mit transparentem Hintergrund ausgeben.
Oder habe ich da was nicht mitgekriegt?

Sailor 26. Jul 2011 11:37

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Liste der Anhänge anzeigen (Anzahl: 1)
Anbei noch eine kleine Demo

s.h.a.r.k 26. Jul 2011 11:48

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Achso, du meintest den zweiten TextOut-Befehl auf dem eigentlichen Canvas. Dabei setze ich den Brush-Style auf bsClear, was ja den selben Effekt hat.

Mein Problem ist eigentlich nur, dass dieser geblurrte Puffer-Bitmap eine Hintergrundfarbe hat und diese beim Pinsel auf dem Canvas übernommen wird. Was ich damit meine ist klar?

Bin gerade dabei das hier umzusetzen, nur klappts noch nicht so recht...

Medium 26. Jul 2011 12:18

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Wenn du beim Blur den Alphakanal mit verarbeitest, hast du doch schon die richtigen Transparenzwerte. Du musst nur darauf achten, dass das Alpha vom weichzuzeichnenden Bitmap 255 bei der Schrift ist, und 0 sonst.

s.h.a.r.k 26. Jul 2011 12:27

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Zitat:

Zitat von Medium (Beitrag 1113587)
Wenn du beim Blur den Alphakanal mit verarbeitest, hast du doch schon die richtigen Transparenzwerte. Du musst nur darauf achten, dass das Alpha vom weichzuzeichnenden Bitmap 255 bei der Schrift ist, und 0 sonst.

Wenn du mir nun noch sagst, wie ich das anstellen soll, dann wäre ich glücklich :mrgreen: Den Gaussian Blur, den ich implementiert habe, der beachtet den Alpha-Kanal, in so fern das Pixel-Format pf32bit ist.

Canvas.TextOut() setzt jedenfalls keinerlei Alpha-Kanal, denn ich hatte schon testweise den Alpha-Kanal alles Pixel auf 0 gesetzt und darauf dann ein TextOut() gemacht.

Blup 26. Jul 2011 12:55

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Liste der Anhänge anzeigen (Anzahl: 1)
Die Unit TransparentText im Anhang ist eine kleine Spielerei von mir:
Delphi-Quellcode:
uses
  TransparentText;

var
  iBlur: Integer;
  lBlur: IBitmapFilter;
  X, Y: Integer;
  s: string;
  dTransp: Double;
begin
{...}

  if iBlur > 0 then
    lBlur := TBlurFilter.Create(iBlur);
//  Image.Canvas.Font.Name :=
  Image.Canvas.Font.Style := [fsBold{, fsItalic}];
  Image.Canvas.Font.Size := 48;
  Image.Canvas.Font.Color := clRed;
  TransparentTextOut(Image.Canvas, X, Y, s, dTransp, lBlur);
end;

s.h.a.r.k 26. Jul 2011 13:23

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Liste der Anhänge anzeigen (Anzahl: 2)
Danke dir schon mal. Das mit dem vorherigen Kopieren wollte ich bisher umgehen, aber wie mir so scheint, da ich dann ja evtl. Probleme wegen dem Blur bekomme.

Meine Idee, um den geblurrten Text, der evtl. semitransparent ist, auf ein Canvas zu bekommen, war nun die folgende, die auch theoretisch funktionieren müsste:
  • Erzeuge ein Bitmap A und fülle es mit der gewünschten Textfarbe, also der Farbe, in der später der Text-Shadow erscheinen soll. Dieses Bitmap muss 32bit haben, da Alpha-Kanal vorhanden sein muss.
  • Erzeuge ein weiteres Bitmap B, welches keinen Alpha-Kanal benötigt, fülle es mit schwarzer Farbe und drucke darauf in weißer Schrift den gewünschten Text. Die Farben schwarz und weiß sind hier wichtig, siehe folgender Schritt.
  • Gehe Pixel für Pixel von Bitmap A durch und setze den Alpha-Kanal der folgenden Formel nach:
    Delphi-Quellcode:
    BitmapAPixel.rgbReserved := EnsureRange((BitmapBPixel.rgbtRed + BitmapBPixel.rgbtGreen + BitmapBPixel.rgbtBlue) div 3, 0, 255);
    Im Anhang findet ihr einen Screenshot der entstehenden Alpha-Werte.
  • Via Windows.AlphaBlend() kann man dann das geänderte Bitmap A auf ein gewünschtes Canvas kopieren.
Aber wer glaubt, dass der Spass auf Anhieb funktionieren würde, der ist leider im Irrtum :wall: Also entweder hab ich einen dummen Fehler in meinem Code, oder AlphaBlend() macht etwas, was ich so nicht weiß oder was es so nicht machen soll. Links im Screenshot seht ihr ganz oben das Bitmap A, darunter Bitmap B mit Text (hier eine nicht geblurrte Variante) und darunter die "Grafik" die AlphaBlend() auf die Form zeichnet. Wenn ihr genau hinseht, dann entdeckt ihr in der untersten Grafik, dass der Text einen Hintergrund hat, was ja so nicht sein sollte, da die Alpha-Werte an der Stelle ja gleich 0 sind. Der Farbwert an dieser Stelle ist: $fff0f0, also ein ganz leichtes rot.

Anbei findet ihr mal das aktuelle Projekt, falls da mal jemand reinschauen will.

Blup 26. Jul 2011 15:12

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx

Lies mal den Komentar:
Zitat:

I hope developer who designed this method is fired already?
:)

s.h.a.r.k 26. Jul 2011 15:26

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Liste der Anhänge anzeigen (Anzahl: 2)
Okay :mrgreen:

Habs nun schon anders gelöst. Allein mein Gaussian Blur ist leider noch etwas langsam, weswegen es bei größeren Font-Größen etwas dauert (~500ms) bist das Bild da ist. Anbei mal eine Demo und der Source. Für meine Zwecke reicht das aber schon vollkommen :stupid:

Blup 26. Jul 2011 15:55

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Zitat:

Zitat von s.h.a.r.k (Beitrag 1113656)
Allein mein Gaussian Blur ist leider noch etwas langsam, weswegen es bei größeren Font-Größen etwas dauert (~500ms) bist das Bild da ist.

Teste mal TBlurFilter aus meiner Unit, der ist eigentlich recht flott.

Namenloser 26. Jul 2011 17:03

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
[OT]
Zitat:

Zitat von Blup (Beitrag 1113653)
http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx

Lies mal den Komentar:
Zitat:

I hope developer who designed this method is fired already?
:)

Lies auch die Antwort darüber ;)
PS: Premultiplied Alpha rules
[/OT]

stOrM 26. Jul 2011 18:59

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Zitat:

Zitat von s.h.a.r.k (Beitrag 1113656)
Okay :mrgreen:

Habs nun schon anders gelöst. Allein mein Gaussian Blur ist leider noch etwas langsam, weswegen es bei größeren Font-Größen etwas dauert (~500ms) bist das Bild da ist. Anbei mal eine Demo und der Source. Für meine Zwecke reicht das aber schon vollkommen :stupid:

Könntest Du den Democode ggf. mal mit anhängen das ganze sieht seht interessant aus leider fehlen ein paar Dinge wie: ApLib.Collections

Viele Grüße

s.h.a.r.k 26. Jul 2011 19:34

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Oh Schande... Hab ich die da mit eincompiliert?! Das war nicht erwünscht, sorry. Ist alles Bestandteil meiner eigenen Library, die ich gerade aufbaue und bald mal freigeben werde. Ich schau mal, dass ich das so reduziere, dass es nur noch das Pinseln umfasst. Einene Moment...

-- Edit: Anbei einfach mal die aktuelle Version meinen Sammlung.

-- Edit: Anhang entfernt und im 7z-Format hier neu angehängt.

Namenloser 26. Jul 2011 19:39

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Die Exe-Demo funktioniert leider auch nicht:
Zitat:

---------------------------
Project1.exe - Komponente nicht gefunden
---------------------------
Die Anwendung konnte nicht gestartet werden, weil FastMM_FullDebugMode.dll nicht gefunden wurde. Neuinstallation der Anwendung könnte das Problem beheben.
---------------------------
OK
---------------------------
PS: Wäre schön, wenn du für Archive ein offenes Format wie 7zip oder ZIP statt RAR verwenden würdest.

s.h.a.r.k 26. Jul 2011 19:42

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von NamenLozer (Beitrag 1113691)
Die Exe-Demo funktioniert leider auch nicht:
Zitat:

---------------------------
Project1.exe - Komponente nicht gefunden
---------------------------
Die Anwendung konnte nicht gestartet werden, weil FastMM_FullDebugMode.dll nicht gefunden wurde. Neuinstallation der Anwendung könnte das Problem beheben.
---------------------------
OK
---------------------------
PS: Wäre schön, wenn du für Archive ein offenes Format wie 7zip oder ZIP statt RAR verwenden würdest.

Okay, okay, okay... Wird auch noch gefixt :stupid: Mein Lib kommt dann auch noch 7z-verpackt...

So, anbei das Paket im 7z-Format und im Examples-Ordner befindet sich eine gefixte Version, ohne Einbindung von FastMM.

stOrM 26. Jul 2011 20:25

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Btw. Ich teste grad mal ein wenig rum, ganz nette Sachen bei:thumb:
Btw. sowas funzt ned?

Code:
Label1.Canvas.ShadowedTextOut(8, 8, 'Test!', 2, 2, 4, 0, 255);

s.h.a.r.k 26. Jul 2011 20:33

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Hm, da stimmt wohl eine Berechnung eines Rechtecks nicht so recht :gruebel:

-- Edit: Doch, ist alles korrekt imho. Schau mal in die Zeile 200 der ApLib.ClassHelpers. Dort pinsel ich via TextOut die Schrit auf das Canvas und das genau an die Stelle, die du via X und Y Koordinaten übergibst.

Und nachdem das hier eine Frage war.
Zitat:

Zitat von stOrM (Beitrag 1113698)
Btw. sowas funzt ned?
Code:
Label1.Canvas.ShadowedTextOut(8, 8, 'Test!', 2, 2, 4, 0, 255);

Doch, das geht :)

stOrM 26. Jul 2011 20:38

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Naja so tief bin ich nicht eingestiegen in die Sourcen fiehl mir nur grad auf weil genau für nen Label könnt ich den Shadowtext gut brauchen. Gibts ein SVN zu deinen Sourcen falls es Opensource bleibt bzw. Du Sachen fixt?

s.h.a.r.k 26. Jul 2011 20:44

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Zitat:

Zitat von stOrM (Beitrag 1113702)
Naja so tief bin ich nicht eingestiegen in die Sourcen fiehl mir nur grad auf weil genau für nen Label könnt ich den Shadowtext gut brauchen. Gibts ein SVN zu deinen Sourcen falls es Opensource bleibt bzw. Du Sachen fixt?

Bisher ist leider alles noch in einem Closed-Source-Repository. Ich wollte schon seit Monaten meine Lib veröffentlichen, bin aber leider noch nicht so recht dazu gekommen, alles auf ein von mir gewünschtes Niveau zu heben. Es gibt hier und da immer noch Ecken und Kanten, die noch nicht so toll sind. Ebenso sind die Demos nicht unbedingt auf dem Stand des Source-Codes und es fehlen noch viele Demos, die ich in einem anderen Repo pflege, da diese noch nicht final sind.

Jedenfalls hoffe ich, dass ich das binnen ein bis zwei Monate endlich mal eine Beta veröffentlichen kann. Dann erfährst du definitiv hier davon ;) Hin und wieder poste ich ein Version der Lib in einem Beitrag, da ich sonst die Lib auseinandere nehmen müsste, wenn ich eine Demo oder dergleichen poste -- so wie es eben hier der Fall ist.

Somit, in alter Blizzard-Manier: It's done, when it's done! :stupid:

PS: Es bleibt auf jedenfall Opensource, da mir die DP schon so viel gegeben hat, dass man so einer Community auch was zurückgeben muss. Werde wohl auch die MIT Lizenz nutzen, da diese recht kurz und frei gehalten ist.

stOrM 26. Jul 2011 20:52

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Ja würd mich freuen wenn Du mir eine Info zukommen läßt wenns mal soweit ist mit der Beta...
Was ich vorschlagen würde wäre ggf. Wenn Du halt Demos machst nutz wenn Du kannst Hauptsächlich standart VCL für Einstellungen und der gleichen. (Beispiel ShadowText man will ja nicht immer ne Komplette Sammlung installieren um eine Sache anzusehen.)

Was die Sache mit dem gerade besprochenen TLabel anbelangt also bisher funzt es nicht bei mir, muß ich mir noch mal genauer ansehen an den Coords sollte es eigentlich nicht liegen, da die nun auf 0, 0 stehen anstelle von 8,8 also sollte die im Rect liegen)

s.h.a.r.k 26. Jul 2011 21:05

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Pass aber auf die AutoSize-Eigenschaft deines Labels auf. Ich habe vorher einfach die Caption entfernt, dann die Größe via Designer gesetzt und AutoSize gleich False gesetzt. Hat dann eben wunderbar geklappt gehabt.

Bzgl. den Demos: Jup, da hast du wohl Recht :thumb: Dieses BMSpinEdit nutze ich nur sehr gerne, da es von der Usability her klasse ist, ebenso die (Sp-)TBX-Komponenten.

stOrM 26. Jul 2011 21:13

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Zitat:

Zitat von s.h.a.r.k (Beitrag 1113705)
Pass aber auf die AutoSize-Eigenschaft deines Labels auf. Ich habe vorher einfach die Caption entfernt, dann die Größe via Designer gesetzt und AutoSize gleich False gesetzt. Hat dann eben wunderbar geklappt gehabt.

Bzgl. den Demos: Jup, da hast du wohl Recht :thumb: Dieses BMSpinEdit nutze ich nur sehr gerne, da es von der Usability her klasse ist, ebenso die (Sp-)TBX-Komponenten.

Sorry wie Dumm muß man sein :wall: ne andere Komponente hatte das Label verdeckt deshalb sah ich nix :oops: Funzt nu super :thumb:

Blup 29. Jul 2011 14:43

AW: Canvas.TextOut mit Text Shadow-Erweiterung
 
Für alle die sich mit AlphaBlend rumärgern müssen, hier noch die Änderung am urspünglichen Code:
Delphi-Quellcode:
var
  Alpha: word;
{...}
      for Col in [0 .. Buffer.Width - 1] do
      begin
        BufferPixel := @BufferScanline[Col];
        MaskPixel  := @MaskScanline[Col];
        Alpha := (MaskPixel.rgbtRed + MaskPixel.rgbtGreen + MaskPixel.rgbtBlue) div 3;
        // premultiplied alpha, red, green and blue channel
        BufferPixel.rgbRed     := (BufferPixel.rgbRed  * Alpha) shr 8;
        BufferPixel.rgbGreen   := (BufferPixel.rgbGreen * Alpha) shr 8;
        BufferPixel.rgbBlue    := (BufferPixel.rgbBlue * Alpha) shr 8;
        BufferPixel.rgbReserved := Alpha;
      end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:36 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