@@ -25,6 +25,8 @@ interface
2525 TPixelFontGlyph = record
2626 Value : Char;
2727
28+ Hash: UInt32;
29+
2830 Width: Int16; // image width
2931 Height: Int16; // image height
3032 ForegroundBounds: TBox; // foreground meaning points and shadow
@@ -44,6 +46,11 @@ TPixelFont = record
4446 SpaceWidth: Integer;
4547 MaxGlyphWidth: Integer;
4648 MaxGlyphHeight: Integer;
49+ public
50+ function GetGlyph (const c: Char): PPixelFontGlyph; inline;
51+ function SameGlyph (const a, b: Char): Boolean; inline;
52+ function SameText (const s1, s2: String): Boolean; inline;
53+ procedure ReplaceSameGlyphs (var s1: String; const s2: String); inline;
4754 end ;
4855 PPixelFont = ^TPixelFont;
4956
@@ -112,18 +119,58 @@ function IsShadow(const Image: TSimbaImage; const X, Y: Integer; const Tol: Sing
112119 Result := (R <= Tol) and (G <= Tol) and (B <= Tol + 5 ); // allow a little more in the blue channel only
113120end ;
114121
115- function GetGlyph (const Font: PPixelFont; const c: Char): PPixelFontGlyph; inline;
122+ // slacky hashing algorithm
123+ function HashPoints (const points: TPointArray): UInt32; inline;
124+ var
125+ pt: TPoint;
126+ begin
127+ { $PUSH}
128+ { $Q-}{ $R-}
129+ Result := $811C9DC5;
130+ for pt in points do
131+ Result := (Result xor (UInt32(pt.X) shl 16 or UInt32(pt.Y))) * $01000193 ;
132+ { $POP}
133+ end ;
134+
135+ function TPixelFont.GetGlyph (const c: Char): PPixelFontGlyph; inline;
116136var
117137 I: Integer;
118138begin
119- for I := 0 to High(Font^ .Glyphs) do
120- if (Font^ .Glyphs[I].Value = c) then
121- Exit(@Font^ .Glyphs[I]);
139+ for I := 0 to High(Self .Glyphs) do
140+ if (Self .Glyphs[I].Value = c) then
141+ Exit(@Self .Glyphs[I]);
122142
123143 SimbaException(' Character %s does exist in the Font' , [c]);
124144 Result := nil ;
125145end ;
126146
147+ function TPixelFont.SameGlyph (const a, b: Char): Boolean; inline;
148+ begin
149+ Result := Self.GetGlyph(a)^.Hash = Self.GetGlyph(b)^.Hash;
150+ end ;
151+
152+ function TPixelFont.SameText (const s1, s2: String): Boolean; inline;
153+ var
154+ i: Integer;
155+ begin
156+ if Length(s1) <> Length(s2) then
157+ Exit(False);
158+ for i := 1 to Length(s1) do
159+ if not Self.SameGlyph(s1[i], s2[i]) then
160+ Exit(False);
161+ Result := True;
162+ end ;
163+
164+ procedure TPixelFont.ReplaceSameGlyphs (var s1: String; const s2: String); inline;
165+ var
166+ i: Integer;
167+ begin
168+ for i := 1 to Min(Length(s1), Length(s2)) do
169+ if Self.SameGlyph(s1[i], s2[i]) then
170+ s1[i] := s2[i];
171+ end ;
172+
173+
127174// text contains >= 50% alphanum
128175function IsAlphaNumSym (const Text: String): Boolean; inline;
129176var
@@ -364,6 +411,7 @@ class function TPixelOCR.LoadFont(Dir: String; SpaceWidth: Integer): TPixelFont;
364411 Character: String;
365412 Glyph: TPixelFontGlyph;
366413 B: TBox;
414+ Pt: TPoint;
367415begin
368416 Result := Default(TPixelFont);
369417 Result.SpaceWidth := SpaceWidth;
@@ -410,6 +458,8 @@ class function TPixelOCR.LoadFont(Dir: String; SpaceWidth: Integer): TPixelFont;
410458 Glyph.BackgroundBounds := B;
411459 Glyph.PointsShadowWidth := B.Width;
412460
461+ Glyph.Hash := HashPoints(TPointArray(Glyph.Points + Glyph.Shadow));
462+
413463 if (Length(Glyph.Shadow) > 0 ) then
414464 Glyph.BestMatch := Length(Glyph.Points) + Length(Glyph.Shadow)
415465 else
@@ -442,7 +492,7 @@ class function TPixelOCR.TextToTPA(constref Font: TPixelFont; Text: String; out
442492 X := 0 ;
443493 Count := 0 ;
444494 for I := 1 to Length(Text) do
445- with GetGlyph(@Font, Text[I])^ do
495+ with Font. GetGlyph(Text[I])^ do
446496 begin
447497 if (Points <> nil ) then
448498 begin
@@ -460,7 +510,7 @@ class function TPixelOCR.TextToTPA(constref Font: TPixelFont; Text: String; out
460510
461511 Count := 0 ;
462512 for I := 1 to Length(Text) do
463- with GetGlyph(@Font, Text[I])^ do
513+ with Font. GetGlyph(Text[I])^ do
464514 begin
465515 for J := 0 to High(Points) do
466516 begin
@@ -652,4 +702,5 @@ function TPixelOCR.RecognizeLines(Image: TSimbaImage; constref Font: TPixelFont;
652702 end ;
653703end ;
654704
705+
655706end .
0 commit comments