AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Algorithmus für Text zu Polygon/TPath (Vector)

Ein Thema von milos · begonnen am 24. Jul 2016 · letzter Beitrag vom 25. Jul 2016
Antwort Antwort
Benutzerbild von milos
milos

Registriert seit: 14. Jul 2008
Ort: Bern (CH)
509 Beiträge
 
Delphi 11 Alexandria
 
#1

Algorithmus für Text zu Polygon/TPath (Vector)

  Alt 24. Jul 2016, 08:18
Hi,

ich hätte gerne die Möglichkeit einen Text mit bestimmter Schriftart zu einem Polygon (oder vielleicht Delphi-Referenz durchsuchenTPath (Vector)?) zu konvertieren.
Ich dachte dabei, dass ich den Text (gross genug) auf ein TBitmap zeichnen lasse und das gezeichnete dann mit einem Algorithmus "scanne".

Gibt es da gute und schnelle Algorithmen die das auch schön hinbekommen? Wie macht man z.B. Buchstaben mit Leerräumen dazwischen? Da müsste ich doch mit mehreren Polygonen arbeiten oder?

Freundliche Grüsse
Milos
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.367 Beiträge
 
Delphi 12 Athens
 
#2

AW: Algorithmus für Text zu Polygon/TPath (Vector)

  Alt 24. Jul 2016, 08:50
Wenn es für TrueType Fonts reicht, könnte das hier ein Anfang sein. Der Code ist zwar ungefähr so alt wie du, aber mit ein bisschen Refactoring und Anpassungen könnte das eine gute Basis sein.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von milos
milos

Registriert seit: 14. Jul 2008
Ort: Bern (CH)
509 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: Algorithmus für Text zu Polygon/TPath (Vector)

  Alt 24. Jul 2016, 11:24
Hallo Uwe,

Danke für den Link. Sitze leider gerade im Zug und kann erst morgen das ganze genauer in der IDE ansehen. Auch scheint mir der Code zu sehr von der Windows API abzuhängen. (z.B. GetGlyphOutline/GetGlyphOutlineW und diverse andere Klassen/Strukturen die wichtig zu sein scheinen) Das müsste jedoch auch auf Android laufen, wenn das schon implementiert werden soll.

Ich weiss wie gesagt leider nicht was da im Hintergrund passiert aber ich dachte zunächst an etwas wie den A*-Algorithmus. Bei dem kann ich jedoch keine Leerräume finden und das Ergebnis war mehr "Windings" als "Arial".

PS: Die erste Version des Source Codes ist 2 Monate jünger als ich. Das ganze Pointergedöns hätte mir aber Angst eingejagt.

Freundliche Grüsse
Milos
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.367 Beiträge
 
Delphi 12 Athens
 
#4

AW: Algorithmus für Text zu Polygon/TPath (Vector)

  Alt 24. Jul 2016, 13:48
Im Wesentlichen interpretiert man hier die Vektordefinition des TrueType. Für andere Plattformen müsste man das aber noch selbst implementierten.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von milos
milos

Registriert seit: 14. Jul 2008
Ort: Bern (CH)
509 Beiträge
 
Delphi 11 Alexandria
 
#5

AW: Algorithmus für Text zu Polygon/TPath (Vector)

  Alt 25. Jul 2016, 01:11
Hi,

habe vorhin angefangen das Ding einfach irgendwie zu implementieren, was (sehr unerwartet) sehr gut funktioniert hat.
Beim optimieren bin ich jedoch auf Delphi-Referenz durchsuchenFMX.TextLayout gestossen welche die Klasse Delphi-Referenz durchsuchenTTextLayout beinhaltet, die es anscheinend ermöglicht auf jeder Platform einen Text mit gewünschtem Font in ein TPathData umzuwandeln.

Beispielcode mit leerem Formular (Nur das OnPaint Event reicht zum testen):
Delphi-Quellcode:
procedure TForm1.FormPaint(Sender: TObject; Canvas: TCanvas;
  const [Ref] ARect: TRectF);
var
  LTextLayout : TTextLayout;
  LPathData : TPathData;
begin
  Canvas.Font.Family := 'Comic Sans MS';
  Canvas.Font.Size := 128;

  LTextLayout := TTextLayoutManager.DefaultTextLayout.Create;
  try
    LPathData := TPathData.Create;
    try
      LTextLayout.Text := '@';
      LTextLayout.Font := Canvas.Font;
      LTextLAyout.ConvertToPath(LPathData); // Magic

      Canvas.Fill.Color := $FF0070FF;
      Canvas.FillPath(LPathData,1);

      Canvas.Stroke.Color := $FF000000;
      Canvas.DrawPath(LPathData,1);
    finally
      LPathData.Free;
    end;
  finally
    LTextLayout.Free;
  end;
end;
Mehr infos: http://riversoftavg.com/blogs/index....text-with-fmx/

Ich hoffe das auch andere hiervon Gebrauch machen können.
Ich mag es wie Firemonkey schon sehr vieles von Haus aus mitbringt auch wen einiges ab und zu mal buggy ist aber seit ich für Freizeitprojekte Firemonkey benutze, schreibe ich viel weniger Nebensächlichen Code den man zwar immer braucht, aber auch immer wieder neu schreibt weil das meist nur einige Zeilen sind. Da bleibt mehr Zeit für das eigentliche Vorhaben

Freundliche Grüsse
Milos

Geändert von milos (25. Jul 2016 um 01:16 Uhr)
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
4.016 Beiträge
 
Delphi 12 Athens
 
#6

AW: Algorithmus für Text zu Polygon/TPath (Vector)

  Alt 25. Jul 2016, 13:38
Hallo Milos,

hier ist noch ein "grober" Versuch Text in einen Pfad zu rendern unter FMX.
Jedenfalls hatte ich immer Probleme mit dem Scaling untern verschiedenen Plattformen,
und auch davon einen Screenshot zu machen hatte diverse Probleme.
Mit viel manuellen Korrekturen läuft es, aber ob es auf allen Geräten gleich aussieht kann ich nicht garantieren.

Ich will den Text erst im 0,0 Punkt mittig zentrieren,
dann drehen und verschieben, und
an die finale Position positioinieren.
Das alles mit den Matrizen.

Vielleicht hilft dir das ja auch it´rgendwie weiter.

Delphi-Quellcode:
procedure TS4Shape.PaintToLayout_Text(Canvas: TCanvas; const ARect: TRectF);
var
  ptS, ptE, ptC: TPointF;
// sAng: Single;
// mtrx: TMatrix;
// mtrxOfs: TMatrix;
// sAngL: Single;
  F_Arm : Single;
  len : Single;
// mtrxTrn: TMatrix;
// mtrxRot: TMatrix;
// rcText: TRectF;
// szBmp: TSizeF;
// MState: TMatrix;
// ptVP: TPointF;
// sSclC: Single;
// sSclCP: Single;
// sSclP: Single;
// sSclB: Single;
// sSclSC: Single;
  pd: TPathData;
  ang: Single;
  rcImg: TRectF;
  lenOfs: Single;
  sHeight: Single;
  rcTxt: TRectF;
  sScale: Single;
  mat: TMatrix;
  sSclScrn: Single;
  sSclCan: Single;
  sSclBmp: Single;
  bOrientH: Boolean;
  FScrn: IFMXScreenService;
  sGetScrnScale: Single;
  sTxtFak: Single;
// bIsTablet: Boolean;

begin

// New Approach 24.04.16

    if FShapes.IsSuppressText then
    begin
      Exit; // Don'T want Text here
    end;

    sGetScrnScale := 1.0;

    if TPlatformServices.Current.SupportsPlatformService( IFMXScreenService, FScrn) then
    begin
      sGetScrnScale := FScrn.GetScreenScale;

      FScrn := nil;
    end;


    // New Approach 24.04.16
    pd := TPathData.Create;

    try

        if (FText <> '') and
           (FSelPtsTextIdx[0] >= 0) and
           (FSelPtsTextIdx[1] >= 0) then
        begin
          pd.Clear;

          rcImg := RectF(0, 0,
                         Min(Canvas.Width, Canvas.Height),
                         Max(Canvas.Width, Canvas.Height)
                        );

          if Canvas.TextToPath(pd,
                               rcImg,
// RectF(0,
// 0,
// Min(Canvas.Width, Canvas.Height),
// Max(Canvas.Width, Canvas.Height)),
                               FText,
                               True,
                               TTextAlign.Center,
                               TTextAlign.Leading
                              ) then
          begin

            ptS := FSelPtsList.Items[FSelPtsTextIdx[0]].Position.Point;
            ptE := FSelPtsList.Items[FSelPtsTextIdx[1]].Position.Point;

            len := ptS.Distance( ptE );

            if len >= 10 then
            begin

              // Retrieve ScreenOrient
              bOrientH := TS4View_Manager.Orientation_Current_IsPortrait;

              ang := ptS.Angle( ptE ) + Pi; // As Radian

              ptC := (ptS + ptE) / 2;
              if FSelPtsList.Count >= 3 then
                FSelPtsList.Items[2].Position.Point := ptC
              else
                ptC := ptC;

  // FLine.Center.Offset ang + Pi/2; // Turn 90°
// if bOrientH then
                F_Arm := ang - Pi * 0.5; // 90° direction angFac; // - for L-Arm + for R-Arm
// else
// F_Arm := ang + Pi * 0.5; // 90° direction angFac; // - for L-Arm + for R-Arm
  // len := TextSize * sSclB * sSclP * FShapes.ScaleShapes * 1.0;
  // mtrxOfs := TMatrix.CreateTranslation(Cos(FL) * len, Sin(FL) * len);


// rcImg := RectF(0, 0, Canvas.Width, Canvas.Height);



              pd.FitToRect( rcImg );
              lenOfs := pd.GetBounds.Height;



              sSclScrn := sGetScrnScale;
              sSclCan := Canvas.Scale;
              sSclBmp := FShapes.GetImgViewCtrl.Bitmap.BitmapScale;

              sHeight := rcImg.Width; // Min(Canvas.Width, Canvas.Height );
              sHeight := sHeight / 6;

// sHeight := 40;
  {$IFDEF MSWINDOWS}
// sHeight := 80;
  {$ENDIF MSWINDOWS}
  {$IFDEF MACOS}
// sHeight := 80;
  {$ENDIF MACOS}
  {$IF DEFINED(IOS) or DEFINED(ANDROID)}

  {$IF    DEFINED(IOS)}
              sHeight := 40;
  {$ENDIF DEFINED(IOS)}
  {$IF    DEFINED(ANDROID)}
              sHeight := 20;
  {$ENDIF DEFINED(ANDROID)}


              if sSclScrn <= 2 then
              begin
                sHeight := sHeight * 1.5;
              end
              else
              begin
                sHeight := sHeight / 1.5;
              end;

              if not FShapes.IsInMakeScreenshot then
                sHeight := sHeight * sSclScrn;
  {$ENDIF DEFINED(IOS) or DEFINED(ANDROID)}


              rcTxt := RectF(0,0,
                             len * sSclScrn,
                             sHeight * sSclScrn); // Height/Size of Text

              sTxtFak := 1.5; //!!! Hier ist der Faktor der die Größe bestimmt ??

              if FText.Length >= 3 then
              begin
                sTxtFak := sTxtFak * (Min(Max(FText.Length, 2), 10) / 6); // Get TextLen dependend Factor
                lenOfs := lenOfs * 0.95;
              end
              else
              begin
                sTxtFak := sTxtFak * (Min(Max(FText.Length, 1), 10) / 7); // Get TextLen dependend Factor
                lenOfs := lenOfs * 0.80;
              end;

              rcImg.FitInto(rcTxt, sScale);
              if sScale > 0.0 then
                sScale := Max(0.1, 1 / sScale) * sTxtFak
              else
                sScale := Max(0.1, 1 / 1.0) * sTxtFak;

              lenOfs := 1.05 * lenOfs * sScale;

              mat := TMatrix.Identity;
              // Center at 0/0
              mat := mat * TMatrix.CreateTranslation( -rcImg.Width /2, // -Canvas.Width /2,
                                                      -rcImg.Height/2); // -Canvas.Height/2 );
              // Scale to TextRect
              mat := mat * TMatrix.CreateScaling(sScale, sScale);
              // Rotate to TextRect
              mat := mat * TMatrix.CreateRotation( ang ); // ang );

              // Translate OffCenter, to Upper Line
// if bOrientH then
                mat := mat * TMatrix.CreateTranslation( Cos(F_Arm) * lenOfs,
                                                        Sin(F_Arm) * lenOfs);
// else
// mat := mat * TMatrix.CreateTranslation( Cos(F_Arm) * lenOfs * 4,
// Sin(F_Arm) * lenOfs * 4);

              // Translate to TextRect Center
              mat := mat * TMatrix.CreateTranslation( ptC.X, // + rcTxt.Width /2,
                                                      ptC.Y // + rcTxt.Height/2 );
                                                    );


              pd.ApplyMatrix( mat );

              Canvas.Stroke.Color := Canvas.Fill.Color;

              Canvas.FillPath( pd, 1);
              Canvas.DrawPath( pd, 1);

            end;

          end;


        end;


    finally

      pd.Free;

    end;

end;
Rollo

Geändert von Rollo62 (25. Jul 2016 um 13:42 Uhr)
  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 14:34 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