Merge ssh://villavu.com:54367/simba

This commit is contained in:
Niels 2010-10-02 14:58:38 +02:00
commit 38f2192a17
91 changed files with 8075 additions and 60 deletions

View File

@ -1,3 +1,5 @@
.. _mmlref-ocr:
TMOCR Class
===========
@ -6,6 +8,177 @@ useful functions that can be used to create and identify text. It also contains
some functions used in special cases to filter noise. Specifically, these are
all the ``Filter*`` functions.
How the filtering works internally is extensively documented in the code itself
and therefore won't be documented here.
.. _uptext-filter:
Uptext
------
To read the UpText, the TMOCR class applies several filters on the client data
before performing the actual OCR. We will take a look at the two filters first.
Filter 1: The Colour Filter
~~~~~~~~~~~~~~~~~~~~~~~~~~~
We first filter the raw client image with a very rough and tolerant colour
comparison / check.
We first convert the colour to RGB, and if it falls into the following
defined ranges, it may be part of the uptext. We also get the possible
shadows.
We will iterate over each pixel in the bitmap, and if it matches any of the
*rules* for the colour; we will set it to a constant colour which
represents this colour (and corresponding rule). Usually the *base*
colour. If it doesn't match any of the rules, it will be painted black.
We won't just check for colours, but also for differences between specific
R, G, B values. For example, if the colour is white; R, G and B should all
lie very close to each other. (That's what makes a colour white.)
The tolerance for getting the pixels is quite large. The reasons for the
high tolerance is because the uptext colour vary quite a lot. They're also
transparent and vary thus per background.
We will store/match shadow as well; we need it later on in filter 2.
To my knowledge this algorithm doesn't remove any *valid* points. It does
not remove *all* invalid points either; but that is simply not possible
based purely on the colour. (If someone has a good idea, let me know)
In code:
.. code-block:: pascal
for y := 0 to bmp.Height - 1 do
for x := 0 to bmp.Width - 1 do
begin
colortorgb(bmp.fastgetpixel(x,y),r,g,b);
if (r < ocr_Limit_Low) and (g < ocr_Limit_Low) and
(b < ocr_Limit_Low) then
begin
bmp.FastSetPixel(x,y, ocr_Purple);
continue;
end;
// Black if no match
bmp.fastsetpixel(x,y,0);
end;
Filter 2: The Characteristics Filter
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This second filter is easy to understand but also very powerful:
- It removes *all* false shadow pixels.
- It removes uptext pixels that can't be uptext according to specific
rules. These rules are specifically designed so that it will never
throw away proper points.
It also performs another filter right at the start, but we'll disregard that
filter for now.
Removing shadow points is trivial if one understands the following insight.
If there some pixel is shadow on *x, y*, then it's neighbour *x+1, y+1*
may not be a shadow pixel. A shadow is always only one pixel *thick*.
With this in mind, we can easily define an algorithm which removes all false
shadow pixels. In code:
.. code-block:: pascal
{
The tricky part of the algorithm is that it starts at the bottom,
removing shadow point x,y if x-1,y-1 is also shadow. This is
more efficient than the obvious way. (It is also easier to implement)
}
for y := bmp.Height - 1 downto 1 do
for x := bmp.Width - 1 downto 1 do
begin
// Is it shadow?
if bmp.fastgetpixel(x,y) <> clPurple then
continue;
// Is the point at x-1,y-1 shadow? If it is
// then x, y cannot be shadow.
if bmp.fastgetpixel(x,y) = bmp.fastgetpixel(x-1,y-1) then
begin
bmp.fastsetpixel(x,y,clSilver);
continue;
end;
if bmp.fastgetpixel(x-1,y-1) = 0 then
bmp.fastsetpixel(x,y,clSilver);
end;
We are now left with only proper shadow pixels.
Now it is time to filter out false Uptext pixels.
Realize:
- If *x, y* is uptext, then *x+1, y+1* must be either uptext or shadow.
In code:
.. code-block:: pascal
for y := bmp.Height - 2 downto 0 do
for x := bmp.Width - 2 downto 0 do
begin
if bmp.fastgetpixel(x,y) = clPurple then
continue;
if bmp.fastgetpixel(x,y) = clBlack then
continue;
// Is the other pixel also uptext?
// NOTE THAT IT ALSO HAS TO BE THE SAME COLOUR
// UPTEXT IN THIS CASE.
// I'm still not sure if this is a good idea or not.
// Perhaps it should match *any* uptext colour.
if (bmp.fastgetpixel(x,y) = bmp.fastgetpixel(x+1,y+1) ) then
continue;
// If it isn't shadow (and not the same colour uptext, see above)
// then it is not uptext.
if bmp.fastgetpixel(x+1,y+1) <> clPurple then
begin
bmp.fastsetpixel(x,y,clOlive);
continue;
end;
// If we make it to here, it means the pixel is part of the uptext.
end;
Identifying characters
~~~~~~~~~~~~~~~~~~~~~~
.. note::
This part of the documentation is a bit vague and incomplete.
To actually identify the text we split it up into single character and then
pass each character to the OCR engine.
In the function *getTextPointsIn* we will use both the filters mentioned above.
After these have been applied, we will make a bitmap that only contains the
shadows as well as a bitmap that only contains the uptext chars (not the
shadows)
Now it is a good idea to count the occurances of all colours
(on the character bitmap); we will also use this later on.
To split the characters we use the well known *splittpaex* function.
We will then sort the points for in each character TPA, as this makes
makes looping over them and comparing distances easier. We will also
calculate the bounding box of each characters TPA.
.. note::
Some more hackery is then used to seperate the characters and find
spaces; but isn't yet documented here.
Normal OCR
----------
.. note::
To do :-)
A large part is already explained above.
Most of the other OCR functions are simply used for plain identifying
and have no filtering tasks.

View File

@ -21,3 +21,4 @@ default (Pascal) engine.
scriptref/bitmaps.rst
scriptref/string.rst
scriptref/tpa.rst

View File

@ -1,5 +1,5 @@
.. _scriptref_bitmaps:
.. _scriptref-bitmaps:
Bitmaps
=======

View File

@ -83,7 +83,7 @@ GetColors
function GetColors(const Coords : TPointArray) : TIntegerArray;
GetColor returns the color on the coordinate (x, y) defined by *Coords*.
GetColors returns an array of the colours at the given *Coords*.
CountColor

View File

@ -80,7 +80,7 @@ BitmapFromText
This function creates a bitmap from a string *text* with the given *font*.
For an explanation on how to use and work with Bitmaps, please refer to
:ref:`scriptref_bitmaps`.
:ref:`scriptref-bitmaps`.
TPAFromText
~~~~~~~~~~~
@ -91,7 +91,7 @@ TPAFromText
This function creates a TPA from a string *text* with the given *font*.
For an explanation on how to use and work with TPAs, please refer to
:ref:`scriptref_tpointarray`.
:ref:`scriptref-tpointarray`.
TPAFromTextWrap
~~~~~~~~~~~~~~~
@ -112,7 +112,7 @@ MaskFromText
This function creates a Mask from a string *text* with the given *font*.
For an explanation on how to use and work with TPAs, please refer to
:ref:`scriptref_masks`.
:ref:`scriptref-masks`.
Reading Text
------------
@ -127,6 +127,8 @@ rs_GetUpText
This function is a function specific to RuneScape(tm); it reads the text
in the upper left corner into a string.
How these functions actually work can be found here: :ref:`uptext-filter`.
rs_GetUpTextAt
~~~~~~~~~~~~~~

View File

@ -12,6 +12,25 @@ Freeze
function Freeze: boolean;
If you call Freeze, the data that is *currently* currently in the client
is stored into memory. Simba will then target this memory for all further
finding operations; until *Unfreeze* is called. This can dramatically increase
speed if you don't care if the image doesn't change. It can be even more
important if you don't *want* the image to change; if you want to analyze a
specific frame.
Use like:
.. code-block:: pascal
Freeze;
if findcolors(...) then
...
Unfreeze
Make sure you never forget to call Unfreeze!
Unfreeze
--------
@ -19,6 +38,8 @@ Unfreeze
function Unfreeze: boolean;
Unfreeze the client data and restore the original client. See *Freeze* for more
details.
GetClientDimensions
-------------------
@ -27,6 +48,8 @@ GetClientDimensions
procedure GetClientDimensions(var w, h:integer);
Return the size of the client in *w* and *h*.
SetTargetBitmap
---------------
@ -35,6 +58,8 @@ SetTargetBitmap
function SetTargetBitmap(Bitmap : integer): integer;
Set a bitmap as target / client. (It must be loaded by Simba)
SetTargetArray
--------------
@ -43,6 +68,10 @@ SetTargetArray
function SetTargetArray(P: Integer; w, h: integer): integer;
Set a target array as client data. This is generally not something you'd
want to call yourself. It is mainly included for external components to allow
Simba to efficiently target its memory. See the SMART source on how to do this.
SetEIOSTarget
-------------
@ -115,6 +144,7 @@ SetDesktopAsClient
procedure SetDesktopAsClient;
Set the default desktop as client.
ActivateClient
--------------
@ -123,6 +153,8 @@ ActivateClient
procedure ActivateClient;
Set the current target as active for key input.
IsTargetValid
-------------
@ -131,4 +163,5 @@ IsTargetValid
function IsTargetValid: boolean;
Returns true if the current target is valid.

299
Extensions/paster.sex Normal file
View File

@ -0,0 +1,299 @@
program Paster;
//{$DEFINE DEV}
{$IFDEF EXTENSION}
var
Paster_Menu, GetPaste_MenuItem, Private_MenuItem: TMenuItem;
Browser_MenuItem, Paster_MenuItem, AltHost_Menu: TMenuItem;
Divider_MenuItems: array[1..2] of TMenuItem;
AltHost_Menus: array[1..5] of TMenuItem;
AltHost_MenuItems: array[1..5] of array[1..4] of TMenuItem;
function EncodeString(Data: string): string;
var
Pattern, Replacement: TStringArray;
I: integer;
begin
Pattern := ['\', #8, #9, #10, #11, #12, #13, '"', {#39,} '/'];
Replacement := ['\\', '\b', '\t', '\n', '\v', '\f', '\r', '\"', {'\'#39,} '\/'];
Result := Data;
if (Length(Pattern) = Length(Replacement)) then
for I := Low(Pattern) to High(Pattern) do
Result := Replace(Result, Pattern[I], Replacement[I], [rfIgnoreCase, rfReplaceAll]);
end;
function GetName: string;
begin;
Result := 'Paster';
end;
function GetVersion: string;
begin;
Result := '0.2a';
end;
function JSONRequest(var Data: string; const HOST, Method: string): boolean;
begin
{$IFDEF DEV}
WriteLn('(HOST, Method) := ('#39 + HOST + #39', '#39 + Method + #39');');
WriteLn('Data := '#39 + Data + #39';');
{$ENDIF}
Data := GetPageEx('http://' + HOST + '/json/?method=' + Method, Data, 'application/json');
{$IFDEF DEV}WriteLn('Data := '#39 + Data + #39';');{$ENDIF}
if (Data = '') then
begin
Data := '{"data": null, "error": "Server unresponsive!"}';
Result := False;
Exit;
end;
if (Method = 'pastes.getPaste') then
begin
//Little hack for getPaste too work....
Data := Replace(Data, '{"data": {', '{', []);
Data := Replace(Data, '}, "error": ', ', "error": ', []);
end;
Result := True;
end;
function GetPaste(HOST: string): boolean;
var
Data: string;
begin
if (HOST = '') then
HOST := 'paste.sheeva.villavu.com';
if (InputQuery(GetName + ' ' + GetVersion + ' Extension', 'Which ID would you like too grab?', Data)) then
begin
if IntToStr(StrToInt(Data)) = Data then
Data := '{"paste_id": ' + Data + '}'
else
Data := '{"paste_id": "' + Data + '"}';
if (not (JSONRequest(Data, HOST, 'pastes.getPaste'))) then
begin
WriteLn('[Paster]Error: ' + GetJSONValue(Data, 'error'));
Result := False;
Exit;
end;
if ((GetJSONValue(Data, 'data') = 'null') and (GetJSONValue(Data, 'error') = 'null')) then
begin
WriteLn('[Paster]Error: Invalid Paste ID!');
Result := False;
Exit;
end;
WriteLn('Opening Paste #' + GetJSONValue(Data, 'paste_id') + ' in a new tab!');
OpenScript('Paste #' + GetJSONValue(Data, 'paste_id'), GetJSONValue(Data, 'code'));
Result := True;
end;
end;
function PasteIt(out Data: string; HOST: string): boolean;
begin
if (HOST = '') then
HOST := 'paste.sheeva.villavu.com';
if (MessageDlg(GetName + ' ' + GetVersion + ' Extension', 'Upload this script to ' + HOST + '?', mtConfirmation, [mbYes, mbNo], 0) = mrYes) then
begin
Data := '{"language": "delphi", "code": "' + EncodeString(ScriptText) + '", "private": ' + Lowercase(BoolToStr(Private_MenuItem.Checked)) + '}';
JSONRequest(Data, HOST, 'pastes.newPaste');
if (GetJSONValue(Data, 'error') = 'null') then
begin
Data := GetJSONValue(Data, 'data');
Result := True;
end else
Data := '[Paster]Error: ' + GetJSONValue(Data, 'error');
end;
end;
procedure Paste(Host: string);
var
Data: string;
begin
if PasteIt(Data, Host) then
begin
if (Browser_MenuItem.Checked) then
begin
WriteLn('Opening pasted script at "http://' + HOST + '/show/' + Data + '/"!');
OpenWebPage('http://' + HOST + '/show/' + Data + '/');
end else
WriteLn('Script pasted at id "' + Data + '"');
end else
WriteLn(Data);
end;
procedure UpdateHost(I: integer);
var
Data: string;
begin
if InputQuery(GetName + ' ' + GetVersion + ' Extension', 'Please input the LodgeIt Host! (Ex: paste.pocoo.org)', Data) then
begin
{$IFDEF DEV}WriteLn('Data := '#39 + Data + #39';');{$ENDIF}
if (Data = '') then
if (AltHost_Menus[I].Caption = 'Host ' + IntToStr(I)) then
begin
WriteLn('[Paster]Error: The host cannot be blank!');
Exit;
end else
begin
AltHost_Menus[I].Caption := 'Host ' + IntToStr(I);
AltHost_MenuItems[I][1].Enabled := False;
AltHost_MenuItems[I][2].Enabled := False;
Settings.setKeyValue('Host' + IntToStr(I), 'Host ' + IntToStr(I));
Exit;
end;
AltHost_Menus[I].Caption := Data;
AltHost_MenuItems[I][1].Enabled := True;
AltHost_MenuItems[I][2].Enabled := True;
Settings.setKeyValue('Host' + IntToStr(I), Data);
end;
end;
procedure OnClick(Sender: TObject);
var
I, K: integer;
begin;
case Sender of
Paster_MenuItem: Paste('');
GetPaste_MenuItem: GetPaste('');
Private_MenuItem: begin
Private_MenuItem.Checked := (not (Private_MenuItem.Checked));
Settings.setKeyValue('Private', Lowercase(BoolToStr(Private_MenuItem.Checked)));
{$IFDEF DEV}WriteLn('Private = ' + Lowercase(BoolToStr(Private_MenuItem.Checked)));{$ENDIF}
end;
Browser_MenuItem: begin
Browser_MenuItem.Checked := (not (Browser_MenuItem.Checked));
Settings.setKeyValue('OpenBrowser', Lowercase(BoolToStr(Browser_MenuItem.Checked)));
{$IFDEF DEV}WriteLn('OpenBrowser = ' + Lowercase(BoolToStr(Browser_MenuItem.Checked)));{$ENDIF}
end;
end;
for I := 1 to 5 do
for K := 1 to 4 do
if (Sender = AltHost_MenuItems[I][K]) then
begin
{$IFDEF DEV}WriteLn('Sender = ' + IntToStr(I) + ', ' + IntToStr(K));{$ENDIF}
if (K = 4) then
UpdateHost(I);
if (K = 2) then
GetPaste(Settings.getKeyValue('Host' + IntToStr(I)));
if (K = 1) then
Paste(Settings.getKeyValue('Host' + IntToStr(I)));
Break;
end;
end;
procedure Attach;
begin;
WriteLn(GetName + ' ' + GetVersion + ' Plugin Loaded!');
Paster_Menu.Visible := True;
end;
procedure Detach;
begin
Paster_Menu.Visible := False;
end;
procedure Free;
var
I, K: integer;
begin
for I := 5 downto 1 do
begin
for K := 4 downto 1 do
AltHost_MenuItems[I][K].Free;
AltHost_Menus[I].Free;
end;
AltHost_Menu.Free;
Private_MenuItem.Free;
for I := 2 downto 1 do
Divider_MenuItems[I].Free;
Paster_MenuItem.Free;
Paster_Menu.Free;
end;
procedure init;
var
I, K: integer;
begin;
Paster_Menu := TMenuItem.Create(Simba_MainMenu);
Paster_Menu.Caption := GetName;
Simba_MainMenu.Items.Add(Paster_Menu);
Paster_MenuItem := TMenuItem.Create(Paster_Menu);
with Paster_MenuItem do
begin
Caption := 'Paste It!';
OnClick := @OnClick;
end;
Paster_Menu.Add(Paster_MenuItem);
GetPaste_MenuItem := TMenuItem.Create(Paster_Menu);
with GetPaste_MenuItem do
begin
Caption := 'Get Paste!';
OnClick := @OnClick;
end;
Paster_Menu.Add(GetPaste_MenuItem);
for I := 1 to 2 do
begin
Divider_MenuItems[I] := TMenuItem.Create(Paster_Menu);
Divider_MenuItems[I].Caption := '-';
end;
Paster_Menu.Add(Divider_MenuItems[1]);
Private_MenuItem := TMenuItem.Create(Paster_Menu);
with Private_MenuItem do
begin
Caption := 'Private';
OnClick := @OnClick;
Checked := (Lowercase(Settings.getKeyValueDef('Private', 'true')) = 'true');
end;
Paster_Menu.Add(Private_MenuItem);
Browser_MenuItem := TMenuItem.Create(Paster_Menu);
with Browser_MenuItem do
begin
Caption := 'Open in Browser';
OnClick := @OnClick;
Checked := (Lowercase(Settings.getKeyValueDef('OpenBrowser', 'true')) = 'true');
end;
Paster_Menu.Add(Browser_MenuItem);
Paster_Menu.Add(Divider_MenuItems[2]);
AltHost_Menu := TMenuItem.Create(Paster_Menu);
AltHost_Menu.Caption := 'Alternate Hosts';
Paster_Menu.Add(AltHost_Menu);
for I := 1 to 5 do
begin
AltHost_Menus[I] := TMenuItem.Create(AltHost_Menu);
AltHost_Menus[I].Caption := Settings.getKeyValueDef('Host' + IntToStr(I), 'Host ' + IntToStr(I));
AltHost_Menu.Add(AltHost_Menus[I]);
for K := 1 to 4 do
begin
AltHost_MenuItems[I][K] := TMenuItem.Create(AltHost_Menus[I]);
case K of
1: AltHost_MenuItems[I][1].Caption := 'Paste It!';
2: AltHost_MenuItems[I][2].Caption := 'Get Paste!';
3: AltHost_MenuItems[I][3].Caption := '-';
4: AltHost_MenuItems[I][4].Caption := 'Update Host';
end;
AltHost_MenuItems[I][K].OnClick := @OnClick;
if ((not ((K = 3) or (K = 4))) and (AltHost_Menus[I].Caption = 'Host ' + IntToStr(I))) then
AltHost_MenuItems[I][K].Enabled := False;
AltHost_Menus[I].Add(AltHost_MenuItems[I][K]);
end;
end;
end;
{$ENDIF}
begin
{$IFNDEF EXTENSION}
WriteLn('This is a Extension for Simba. If you are in Simba click View->Extensions and enable paster.sex!');
{$ENDIF}
end.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 B

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 B

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 B

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 558 B

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 414 B

After

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 558 B

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 630 B

After

Width:  |  Height:  |  Size: 632 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 558 B

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 B

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 B

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 B

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

After

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 B

After

Width:  |  Height:  |  Size: 272 B

BIN
Fonts/CharsNPC/48.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

BIN
Fonts/CharsNPC/49.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

BIN
Fonts/CharsNPC/50.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

BIN
Fonts/CharsNPC/51.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

BIN
Fonts/CharsNPC/52.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 632 B

BIN
Fonts/CharsNPC/53.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

BIN
Fonts/CharsNPC/54.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

BIN
Fonts/CharsNPC/55.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 632 B

BIN
Fonts/CharsNPC/56.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

BIN
Fonts/CharsNPC/57.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 558 B

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 630 B

After

Width:  |  Height:  |  Size: 632 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 774 B

After

Width:  |  Height:  |  Size: 776 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 630 B

After

Width:  |  Height:  |  Size: 632 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 558 B

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 918 B

After

Width:  |  Height:  |  Size: 920 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 846 B

After

Width:  |  Height:  |  Size: 848 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 558 B

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 918 B

After

Width:  |  Height:  |  Size: 920 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 920 B

After

Width:  |  Height:  |  Size: 920 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 630 B

After

Width:  |  Height:  |  Size: 632 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B

After

Width:  |  Height:  |  Size: 464 B

View File

@ -6,4 +6,5 @@ Linux:
* IsKeyDown doesn't work yet.
Windows:
* Interpreter doesn't work well on x64.

BIN
Plugins/libsmart.dll Normal file → Executable file

Binary file not shown.

Binary file not shown.

View File

@ -64,7 +64,7 @@ begin
AboutMemo.Lines.Add('Simba is released under the GPL license.');
AboutMemo.Lines.Add(format('You are currently using version: %d',[SimbaUnit.SimbaVersion]));
AboutMemo.Lines.Add('');
AboutMemo.Lines.Add('Please report bugs at: http://mufasa.villavu.com/mantis/');
AboutMemo.Lines.Add('Please report bugs at: http://bugs.villavu.com/');
end;
procedure TAboutForm.OkButtonClick(Sender: TObject);

View File

@ -17,7 +17,7 @@ object ScriptFrame: TScriptFrame
Font.Height = -13
Font.Name = 'Courier New'
Font.Pitch = fpFixed
Font.Quality = fqNonAntialiased
Font.Quality = fqProof
ParentColor = False
ParentFont = False
PopupMenu = SimbaForm.ScriptPopup
@ -28,7 +28,7 @@ object ScriptFrame: TScriptFrame
OnKeyPress = SynEditKeyPress
OnClickLink = SynEditClickLink
OnMouseLink = SynEditMouseLink
Gutter.Width = 57
Gutter.Width = 59
Gutter.MouseActions = <
item
Shift = []
@ -627,7 +627,7 @@ object ScriptFrame: TScriptFrame
Width = 24
end
object TSynGutterLineNumber
Width = 17
Width = 19
MouseActions = <>
MarkupInfo.Background = clBtnFace
MarkupInfo.Foreground = clNone

View File

@ -66,6 +66,8 @@ uses
tpa, //Tpa stuff
SynRegExpr,
lclintf,
httpsend,
superobject,
SimbaUnit,updateform, mmisc, mmlpsthread; // for GetTickCount and others.//Writeln
{$ifdef Linux}
@ -181,7 +183,11 @@ begin
AddFunction(@ext_UnTarEx,'function UnTarEx(const Input : string;const outputdir : string; overwrite : boolean): boolean;');
AddFunction(@ext_MessageDlg,'function MessageDlg(const aCaption, aMsg: string; DlgType: TMsgDlgType;Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;');
AddFunction(@ext_InputQuery,'function InputQuery(const ACaption, APrompt : String; var Value : String) : Boolean;');
AddFunction(@ext_ScriptText,'function ScriptText: string;');
AddFunction(@ext_OpenScript,'procedure OpenScript(Name, Data: string);');
AddRegisteredPTRVariable('Settings','TMMLSettingsSandbox');
AddFunction(@ext_GetPageEx,'function GetPageEx(const URL, PostData, MimeType: string): string;');
AddFunction(@ext_GetJSONValue,'function GetJSONValue(const Data, Value: string): string;');
AddRegisteredVariable('Simba','TForm');
AddRegisteredVariable('Simba_MainMenu','TMainMenu');
AddRegisteredVariable('Client','TClient');

View File

@ -45,7 +45,7 @@ uses
CastaliaSimplePasPar, v_AutoCompleteForm, PSDump, settings, updater;
const
SimbaVersion = 715;
SimbaVersion = 720;
interp_PS = 0; //PascalScript
interp_RT = 1; //RUTIS

View File

@ -122,3 +122,53 @@ function ext_InputQuery(const ACaption, APrompt : String; var Value : String) :
begin
result := InputQuery(acaption,aprompt,value);
end;
function ext_ScriptText: string;
begin
Result := SimbaForm.CurrScript.SynEdit.Lines.Text;
Result := ReplaceRegExpr('([N|n][A|a][M|m][E|e]|[P|p][A|a][S|s]{2}|[P|p][I|i][N|n])\s*\:\=\s*\''.*?\'';', Result, '$1 := ''*********'';', True);
end;
procedure ext_OpenScript(Name, Data: string);
begin
if (Name = '') then
Name := 'Untitled';
SimbaForm.AddTab;
SimbaForm.CurrScript.SynEdit.Lines.Text := Data;
SimbaForm.CurrScript.ScriptName := Name;
SimbaForm.RefreshTab;
SimbaForm.UpdateTitle;
end;
function ext_GetPageEx(const URL, PostData, MimeType: string): string;
var
HTTPSend: THTTPSend;
begin
HTTPSend := THTTPSend.Create;
try
HTTPSend.MimeType := MimeType;
HTTPSend.Document.Clear;
HTTPSend.Document.Write(PostData[1], Length(PostData));
try
if HTTPSend.HTTPMethod('POST', URL) then
begin;
SetLength(Result, HTTPSend.Document.Size);
HTTPSend.Document.Read(Result[1], Length(Result));
end else
Result := '';
except
on e : exception do
mDebugLn('Exception in GetPage in Extensions: ' + e.message);
end;
finally
HTTPSend.Free;
end;
end;
function ext_GetJSONValue(const Data, Value: string): string;
var
SuperObject: ISuperObject;
begin
SuperObject := SO(Data);
Result := SuperObject.AsObject.S[Value];
end;

View File

@ -3,6 +3,11 @@ begin
Result := CurrThread.Client.MOCR.GetUpTextAtEx(7, 7, true);
end;
function ps_rs_GetUpTextAtEx(x, y: integer; shadow: boolean): string; extdecl;
begin
result := CurrThread.Client.MOCR.GetUpTextAtEx(x, y, shadow);
end;
function ps_rs_GetUpTextAt(x, y : integer): string; extdecl;
begin
result := CurrThread.Client.MOCR.GetUpTextAtEx(x,y,true);

View File

@ -316,6 +316,7 @@ AddFunction(@ps_GetKeyCode,'function GetKeyCode(c : char) : integer;');
SetCurrSection('OCR');
AddFunction(@ps_rs_GetUpText, 'function rs_GetUpText: string;');
AddFunction(@ps_rs_GetUpTextAt, 'function rs_GetUpTextAt(x, y : integer): string;');
AddFunction(@ps_rs_GetUpTextAtEx, 'function rs_GetUpTextAtEx(x, y: integer; shadow: boolean): string');
AddFunction(@ps_BitmapFromText, 'function BitmapFromText(const text, font: String): integer;');
AddFunction(@ps_TPAFromText, 'function TPAFromText(const text, font: String;var w,h : integer): TPointArray;');
AddFunction(@ps_TPAFromTextWrap,'procedure TPAFromTextWrap(const text, font: String;var w,h : integer;var TPA : TPointArray);');

View File

@ -202,6 +202,7 @@ function TMFonts.LoadFont(const Name: String; Shadow: Boolean): boolean;
var
f: TMFont;
begin
Result := True;
if not DirectoryExists(FPath + Name) then
begin
raise Exception.Create('LoadFont: Directory ' + FPath + Name + ' does not exists.');

View File

@ -23,6 +23,7 @@ interface
procedure FreePlugins;
procedure LoadPluginsDir(DirIndex : integer);
function VerifyPath(Path : string) : string;
function LoadPluginNoFallback(PluginName : string) : integer;
protected
function InitPlugin(plugin: TLibHandle): boolean; virtual; abstract;
public
@ -113,8 +114,7 @@ implementation
end;
end;
function TGenericLoader.LoadPlugin(PluginName: string): Integer;
function TGenericLoader.LoadPluginNoFallback(PluginName: string): Integer;
var
i, ii : integer;
PlugExt: String = {$IFDEF LINUX}'.so';{$ELSE}'.dll';{$ENDIF}
@ -151,6 +151,19 @@ implementation
end;
function TGenericLoader.LoadPlugin(PluginName: string): Integer;
var
CpuBits: String = {$IFDEF CPU32}'32';{$ELSE}'64';{$ENDIF}
begin
try
Result := LoadPluginNoFallback(PluginName);
except
on exception do Result:= LoadPluginNoFallback(PluginName+CpuBits);
end;
end;
constructor TGenericLoader.Create;
begin
inherited Create;

View File

@ -52,7 +52,7 @@ type
function GetUpTextAtEx(atX, atY: integer; shadow: boolean): string;
function GetUpTextAt(atX, atY: integer; shadow: boolean): string;
procedure FilterUpTextByColour(bmp: TMufasaBitmap; w,h: integer);
procedure FilterUpTextByColour(bmp: TMufasaBitmap);
procedure FilterUpTextByCharacteristics(bmp: TMufasaBitmap; w,h: integer);
procedure FilterShadowBitmap(bmp: TMufasaBitmap);
procedure FilterCharsBitmap(bmp: TMufasaBitmap);
@ -197,84 +197,124 @@ end;
Non optimised. We can make it use direct data instead of fastgetpixel and
fastsetpixel, but speed isn't really an issue. The entire algorithm is still
fast enough.
There are some issues with this method; since later on the algorithm
(if I recall correctly) throws aways some pixels if a character isn't just
one colour)
We will match shadow as well; we need it later on.
}
procedure TMOCR.FilterUpTextByColour(bmp: TMufasaBitmap; w,h: integer);
procedure TMOCR.FilterUpTextByColour(bmp: TMufasaBitmap);
var
x, y,r, g, b: Integer;
begin
// We're going to filter the bitmap solely on colours first.
// If we found one, we set it to it's `normal' colour.
{
We're going to filter the bitmap solely on colours first.
If we found one, we set it to it's `normal' colour.
Note that these values aren't randomly chosen, but I didn't spent too
much time on finding the exact values either.
We will iterate over each pixel in the bitmap, and if it matches any of the
``rules'' for the colour; we will set it to a constant colour which
represents this colour (and corresponding rule). Usually the ``base''
colour.
If it doesn't match any rule, we can safely make the pixel black.
To my knowledge this algorithm doesn't remove any valid points. It does
not remove *all* invalid points either; but that is simply not possible
based purely on the colour. (If someone has a good idea, let me know)
}
for y := 0 to bmp.Height - 1 do
for x := 0 to bmp.Width - 1 do
begin
colortorgb(bmp.fastgetpixel(x,y),r,g,b);
// the abs(g-b) < 15 seems to help heaps when taking out crap points
{
abs(g-b) < 15 seems to help heaps when taking out invalid (white) points
obviously if a colour is ``white'' R, G B should all be approx the
same value. That is what the last part of the if statement checks.
}
if (r > ocr_Limit_High) and (g > ocr_Limit_High) and (b > ocr_Limit_High)
// 50 or 55. 55 seems to be better.
and (abs(r-g) + abs(r-b) + abs(g-b) < 55) then
// TODO: make 55 a var, and make it so that it can be set
begin
bmp.fastsetpixel(x,y,ocr_White);
continue;
end;
{ Quite straightforward and works quite well, afaik }
if (r < ocr_Limit_Low) and (g > ocr_Limit_High) and (b > ocr_Limit_High) then
begin
bmp.fastsetpixel(x,y,ocr_Blue);
continue;
end;
{ Ditto }
if (r < ocr_Limit_Low) and (g > ocr_Limit_High) and (b < ocr_Limit_Low) then
begin
bmp.fastsetpixel(x,y,ocr_Green);
continue;
end;
// false results with fire
{ False results with fire }
if(r > ocr_Limit_High) and (g > 100) and (g < ocr_Limit_High) and (b > 40) and (b < 127) then
begin
bmp.fastsetpixel(x,y,ocr_ItemC);
continue;
end;
{ Works fine afaik }
if(r > ocr_Limit_High) and (g > ocr_Limit_High) and (b < ocr_Limit_Low) then
begin
bmp.fastsetpixel(x,y,ocr_Yellow);
continue;
end;
// better use g < 40 than ocr_Limit_Low imo
// better use g < 40 than ocr_Limit_Low imo (TODO)
if (r > ocr_Limit_High) and (g < ocr_Limit_Low) and (b < ocr_Limit_Low) then
begin
bmp.fastsetpixel(x,y,ocr_Red);
continue;
end;
{ Red as well }
if (r > ocr_Limit_High) and (g > ocr_Limit_Low) and (b < ocr_Limit_Low) then
begin
bmp.fastsetpixel(x,y,ocr_Red);
continue;
end;
if (r > ocr_Limit_Med) and (r < (ocr_Limit_High + 10)) and (g > ocr_Limit_Low - 10) and
(b < 20) then
begin
bmp.fastsetpixel(x,y,ocr_Green);
continue;
end;
//shadow
begin
bmp.fastsetpixel(x,y,ocr_Green);
continue;
end;
// Match Shadow as well. We will need it later.
if (r < ocr_Limit_Low) and (g < ocr_Limit_Low) and (b < ocr_Limit_Low) then
begin
bmp.FastSetPixel(x,y, ocr_Purple);
continue;
end;
// Black if no match
bmp.fastsetpixel(x,y,0);
end;
// make outline black for shadow characteristics filter
// first and last horiz line = 0
{
Make outline black for shadow characteristics filter
First and last horiz line = 0. This makes using the shadow algo easier.
We don't really throw away information either since we already took the
bitmap a bit larger than required.
}
for x := 0 to bmp.width -1 do
bmp.fastsetpixel(x,0,0);
for x := 0 to bmp.width -1 do
bmp.fastsetpixel(x,bmp.height-1,0);
// same for vertical lines
// Same for vertical lines
for y := 0 to bmp.Height -1 do
bmp.fastsetpixel(0, y, 0);
for y := 0 to bmp.Height -1 do
@ -288,7 +328,6 @@ end;
on characteristics.
For the uptext, a few things apply...
First of all:
*** Remove False Shadow ***
if shadow[x,y] then not shadow[x-1,y-1]
@ -300,7 +339,6 @@ end;
will soon see that this algorithm will be a *lot* more efficient if we
start at the right bottom, instead of the left top. Which means we should
work with x-1 and y-1, rather than x+1,y+1
Yeah.... My comments are vague.
)
*** UpText chars identity 1 and 2 ***
@ -314,11 +352,14 @@ procedure TMOCR.FilterUpTextByCharacteristics(bmp: TMufasaBitmap; w,h: integer);
var
x,y: Integer;
begin
// Filter 2
// This performs a `simple' filter.
// What we are doing here is simple checking that if Colour[x,y] is part
// of the uptext, then so must Colour[x+1,y+1], or Colour[x+1,y+1] is a shadow.
// if it is neither, we can safely remove it.
{ Filter 2
This performs a `simple' filter.
What we are doing here is simple checking that if Colour[x,y] is part
of the uptext, then so must Colour[x+1,y+1], or Colour[x+1,y+1] is a shadow.
if it is neither, we can safely remove it.
XXX: This causes the previously mentioned fuckup.
}
for y := 0 to bmp.Height - 2 do
for x := 0 to bmp.Width - 2 do
begin
@ -326,11 +367,20 @@ begin
continue;
if bmp.fastgetpixel(x,y) = clBlack then
continue;
if (bmp.fastgetpixel(x,y) <> bmp.fastgetpixel(x+1,y+1)) and (bmp.fastgetpixel(x+1,y+1) <> clpurple) then
if (bmp.fastgetpixel(x,y) <> bmp.fastgetpixel(x+1,y+1)) and
(bmp.fastgetpixel(x+1,y+1) <> clpurple) then
bmp.fastsetpixel(x,y,{clAqua}0);
end;
// Remove false shadow
{
Remove false shadow. (A shadow isn't larger than 1 pixel. So if x, y is
shadow, thex x+1, y+1 can't be shadow. If it is, we can safely remove it.
(As well as x+2, y+2, etc).
The tricky part of the algorithm is that it starts at the bottom,
removing shadow point x,y if x-1,y-1 is also shadow.
}
for y := bmp.Height - 1 downto 1 do
for x := bmp.Width - 1 downto 1 do
begin
@ -346,24 +396,24 @@ begin
end;
// Now we do another filter, with uptext chars identity 1 and 2.
for y := bmp.Height - 2 downto 0 do
for x := bmp.Width - 2 downto 0 do
begin
if bmp.fastgetpixel(x,y) = clPurple then
continue;
if bmp.fastgetpixel(x,y) = clBlack then
continue;
for y := bmp.Height - 2 downto 0 do
for x := bmp.Width - 2 downto 0 do
begin
if bmp.fastgetpixel(x,y) = clPurple then
continue;
if bmp.fastgetpixel(x,y) = clBlack then
continue;
// identity 1
if (bmp.fastgetpixel(x,y) = bmp.fastgetpixel(x+1,y+1) ) then
continue;
// identity 1
if (bmp.fastgetpixel(x,y) = bmp.fastgetpixel(x+1,y+1) ) then
continue;
// identity 2
if bmp.fastgetpixel(x+1,y+1) <> clPurple then
begin
bmp.fastsetpixel(x,y,clOlive);
continue;
end;
// identity 2
if bmp.fastgetpixel(x+1,y+1) <> clPurple then
begin
bmp.fastsetpixel(x,y,clOlive);
continue;
end;
// If we make it to here, it means the pixel is part of the uptext.
end;
@ -505,7 +555,7 @@ begin
{$ENDIF}
// Filter 1
FilterUpTextByColour(bmp,w,h);
FilterUpTextByColour(bmp);
{$IFDEF OCRSAVEBITMAP}
bmp.SaveToFile(OCRDebugPath + 'ocrcol.bmp');
{$ENDIF}
@ -542,8 +592,8 @@ begin
// TODO:
// We should make a different TPA
// for each colour, rather than put them all in one. Noise can be a of a
// differnet colour.
// for each colour, rather than put them all in one. Noise can be of a
// different colour.
setlength(chars, charsbmp.height * charsbmp.width);
charscount:=0;
for y := 0 to charsbmp.height - 1 do

7380
Units/Misc/superobject.pas Normal file

File diff suppressed because it is too large Load Diff