Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions Source/script/imports/simba.import_pixelocr.pas
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,22 @@ implementation
PPixelFont = ^TPixelFont;
PPixelOCR = ^TPixelOCR;

procedure _LapePixelFont_SameChar(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
begin
PBoolean(Result)^ := PPixelFont(Params^[0])^.SameGlyph(PChar(Params^[1])^, PChar(Params^[2])^);
end;

procedure _LapePixelFont_SameText(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
begin
PBoolean(Result)^ := PPixelFont(Params^[0])^.SameText(PString(Params^[1])^, PString(Params^[2])^);
end;

procedure _LapePixelFont_ReplaceSameGlyphs(const Params: PParamArray); LAPE_WRAPPER_CALLING_CONV
begin
PPixelFont(Params^[0])^.ReplaceSameGlyphs(PString(Params^[1])^, PString(Params^[2])^);
end;


procedure _LapePixelOCR_LoadFont(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
begin
PPixelFont(Result)^ := TPixelOCR.LoadFont(PString(Params^[0])^, PInteger(Params^[1])^);
Expand Down Expand Up @@ -59,6 +75,8 @@ procedure ImportPixelOCR(Script: TSimbaScript);
'record',
' Value: Char;',
'',
' Hash: UInt32;',
'',
' Width: Int16;',
' Height: Int16;',
' ForegroundBounds: TBox;',
Expand Down Expand Up @@ -114,6 +132,9 @@ procedure ImportPixelOCR(Script: TSimbaScript);
if (getGlobalType('TPixelOCR').Size <> SizeOf(TPixelOCR)) then
SimbaException('TPixelOCR import is wrong');

addGlobalFunc('function TPixelFont.SameGlyph(const a, b: Char): Boolean;', @_LapePixelFont_SameChar);
addGlobalFunc('function TPixelFont.SameText(const s1, s2: String): Boolean;', @_LapePixelFont_SameText);
addGlobalFunc('procedure TPixelFont.ReplaceSameGlyphs(var s1: String; const s2: String);', @_LapePixelFont_ReplaceSameGlyphs);
addGlobalFunc('function TPixelOCR.LoadFont(Path: String; SpaceWidth: Integer): TPixelFont; static;', @_LapePixelOCR_LoadFont);
addGlobalFunc('function TPixelOCR.TextToTPA(constref Font: TPixelFont; Text: String): TPointArray; static;', @_LapePixelOCR_TextToTPA);
addGlobalFunc('function TPixelOCR.Locate(Image: TImage; constref Font: TPixelFont; Text: String): Single;', @_LapePixelOCR_Locate);
Expand Down
63 changes: 57 additions & 6 deletions Source/simba.pixelocr.pas
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ interface
TPixelFontGlyph = record
Value: Char;

Hash: UInt32;

Width: Int16; // image width
Height: Int16; // image height
ForegroundBounds: TBox; // foreground meaning points and shadow
Expand All @@ -44,6 +46,11 @@ TPixelFont = record
SpaceWidth: Integer;
MaxGlyphWidth: Integer;
MaxGlyphHeight: Integer;
public
function GetGlyph(const c: Char): PPixelFontGlyph; inline;
function SameGlyph(const a, b: Char): Boolean; inline;
function SameText(const s1, s2: String): Boolean; inline;
procedure ReplaceSameGlyphs(var s1: String; const s2: String); inline;
end;
PPixelFont = ^TPixelFont;

Expand Down Expand Up @@ -112,18 +119,58 @@ function IsShadow(const Image: TSimbaImage; const X, Y: Integer; const Tol: Sing
Result := (R <= Tol) and (G <= Tol) and (B <= Tol + 5); // allow a little more in the blue channel only
end;

function GetGlyph(const Font: PPixelFont; const c: Char): PPixelFontGlyph; inline;
//slacky hashing algorithm
function HashPoints(const points: TPointArray): UInt32; inline;
var
pt: TPoint;
begin
{$PUSH}
{$Q-}{$R-}
Result := $811C9DC5;
for pt in points do
Result := (Result xor (UInt32(pt.X) shl 16 or UInt32(pt.Y))) * $01000193;
{$POP}
end;

function TPixelFont.GetGlyph(const c: Char): PPixelFontGlyph; inline;
var
I: Integer;
begin
for I := 0 to High(Font^.Glyphs) do
if (Font^.Glyphs[I].Value = c) then
Exit(@Font^.Glyphs[I]);
for I := 0 to High(Self.Glyphs) do
if (Self.Glyphs[I].Value = c) then
Exit(@Self.Glyphs[I]);

SimbaException('Character %s does exist in the Font', [c]);
Result := nil;
end;

function TPixelFont.SameGlyph(const a, b: Char): Boolean; inline;
begin
Result := Self.GetGlyph(a)^.Hash = Self.GetGlyph(b)^.Hash;
end;

function TPixelFont.SameText(const s1, s2: String): Boolean; inline;
var
i: Integer;
begin
if Length(s1) <> Length(s2) then
Exit(False);
for i := 1 to Length(s1) do
if not Self.SameGlyph(s1[i], s2[i]) then
Exit(False);
Result := True;
end;

procedure TPixelFont.ReplaceSameGlyphs(var s1: String; const s2: String); inline;
var
i: Integer;
begin
for i := 1 to Min(Length(s1), Length(s2)) do
if Self.SameGlyph(s1[i], s2[i]) then
s1[i] := s2[i];
end;


// text contains >= 50% alphanum
function IsAlphaNumSym(const Text: String): Boolean; inline;
var
Expand Down Expand Up @@ -364,6 +411,7 @@ class function TPixelOCR.LoadFont(Dir: String; SpaceWidth: Integer): TPixelFont;
Character: String;
Glyph: TPixelFontGlyph;
B: TBox;
Pt: TPoint;
begin
Result := Default(TPixelFont);
Result.SpaceWidth := SpaceWidth;
Expand Down Expand Up @@ -410,6 +458,8 @@ class function TPixelOCR.LoadFont(Dir: String; SpaceWidth: Integer): TPixelFont;
Glyph.BackgroundBounds := B;
Glyph.PointsShadowWidth := B.Width;

Glyph.Hash := HashPoints(TPointArray(Glyph.Points + Glyph.Shadow));

if (Length(Glyph.Shadow) > 0) then
Glyph.BestMatch := Length(Glyph.Points) + Length(Glyph.Shadow)
else
Expand Down Expand Up @@ -442,7 +492,7 @@ class function TPixelOCR.TextToTPA(constref Font: TPixelFont; Text: String; out
X := 0;
Count := 0;
for I := 1 to Length(Text) do
with GetGlyph(@Font, Text[I])^ do
with Font.GetGlyph(Text[I])^ do
begin
if (Points <> nil) then
begin
Expand All @@ -460,7 +510,7 @@ class function TPixelOCR.TextToTPA(constref Font: TPixelFont; Text: String; out

Count := 0;
for I := 1 to Length(Text) do
with GetGlyph(@Font, Text[I])^ do
with Font.GetGlyph(Text[I])^ do
begin
for J := 0 to High(Points) do
begin
Expand Down Expand Up @@ -652,4 +702,5 @@ function TPixelOCR.RecognizeLines(Image: TSimbaImage; constref Font: TPixelFont;
end;
end;


end.