Basically I need to convert a bitmap image into a string but it is not a common one.
The dilemma is that this string is composed of two parts:
1) Points 2) Lines
I figured the encoding out from the code you posted (had to port it to C++ though) so the encoding:
string starts with list of points
Each point is present as 4-digit hex number. First 2 hex digits are x
coordinate and the second 2 digits are y
coordinate of point. (probably marking each mouse down event so it holds the info on how many continuous draws the image was drawn)
then separator *
follows
after that list of lines is present
Each line contains 2 points so total of 8-digits hex number per line. The sequence is x0,y0,x1,y1
2-digit hex number per coordinate. If the string contains only 4-digit hex number (the end) it marks the end of signature string.
So when you want to make own signature code then:
clear list of points and list of lines
on mouse down (left button click on or pen hit) event
Add current mouse/pen position to the point list and as a start point to line list
on mouse/pen move event
First find out if the mouse button is still clicked or pen still hitting the pad. If not ignore this event. If yes then add current mouse position to line list twice (that is why they are duplicated the first ends current line and the second starts new line)
on mouse/pen up event
close the actual line so add current mouse position to line list once
before exporting
duplicate last point in lines list to mark end of string
That is all. If you need to convert already drawed image (raster) then you may have problems with comparison because is very unlikely you vectorize the image the same way as the author signs it. Resulting in miss-match of the same images. Also the tripled last point is most likely because of wrong encoding of mouse/pen up event adding the same point inside on mouse move
and on mouse up
events at once
The images encoded this way are limited to 256x256 pixels.
Here example of decoded image for your first signature string:
signature="221A*221A270A270A2503250320072007171617160D2A0D2A07380738073F073F0B3E0B3E15311531222122212C182C183016301631173117311A311A302230222E272E272D2C2D2C2C2F2C2F2C312C312C2F2C2F2E2B2E2B3126312633223322371D371D381C381C3B1B3B1B3C1C3C1C3D1F3D1F3D243D243C2D3C2D3A333A333A363A36393939393B383B383D363D36412E412E46264626492049204B1B4B1B4E184E184F174F175017501751185118511D511D51225122502450244F294F294F2C4F2C4E2F4E2F4F314F315030503052305230552C552C582958295D225D22601E601E611C611C621B621B621A621A601A601A5D1B5D1B5B1E5B1E5723572353285328512B512B502E502E502F502F513151315231523154305430582E582E592D592D5C2C5C2C5F2A5F2A6428642865286528692669266D246D247122712275207520791D791D7D1B7D1B81198119841884188618861887198719881A881A891B891B881C881C871E871E861F861F852085208421842182228222812481247F257F257E257E257D257D257C247C247C217C217D1F7D1F7E1C7E1C801A801A81198119821782178317831784188418851A851A851C851C86208620862286228625862587278727872B872B882E882E893289328A338A338E348E349033903393329332972F972F9A2D9A2D9F299F29A426A426AB20AB20AF1CAF1CB517B517B716B716B716";
here square example
signature="0808*080820082008202020200820082008080808";
so when reordered:
0808 // point(8h,8h);
* // separator
08 08 20 08 // line( 8h, 8h,20h, 8h)
20 08 20 20 // line(20h, 8h,20h,20h)
20 20 08 20 // line(20h,20h, 8h,20h)
08 20 08 08 // line( 8h,20h, 8h, 8h)
08 08 // not enough points -> end of string
[Edit1] raster image to string conversion
First you need to convert your image to vector form. There are many sophistikated approaches to polygonize raster image to vector form but they are usually using advanced things from math,image processing,structures etc... requiring extensive knowledge on the subject. As I assume you need this just to visualize something on the device so Instead I would use very simple conversion resulting in unreasonable big results (in comparison to the advanced approaches). If your device does not have too small limit on the string size then you should be fine otherwise you would need use something more advanced then this:
clear your vector representation
list of points and list of lines
loop through all horizontal lines of image
process each line
x0
x1
if x0,x1
found then
(x0,y)
(x0,y,x1-1,y)
after whole image processed convert vector form to string
*
to stringThis is how it looks like in C++:
// load input 2D BW (binary) image
backbuffer in;
in.bmp->LoadFromFile("in.bmp");
in.resize(in.bmp->Width,in.bmp->Height);
int x0,x1,x,y;
// clear signature vecor represenytation
gSigPoints.num=0;
gSigLines.num=0;
for (y=0;y<in.ys;y++)
for (x=0;x<in.xs;)
{
for (;(x<in.xs)&&(!in.pyx[y][x]);x++); x0=x; // find start of V-line
for (;(x<in.xs)&&( in.pyx[y][x]);x++) x1=x; // find end of V-line
if (x0<in.xs) // add pnt,line to signature
{
gSigPoints.add(x0);
gSigPoints.add(y );
gSigLines.add(x0);
gSigLines.add(y );
gSigLines.add(x1);
gSigLines.add(y );
}
}
// update string and screen
txt=PackBMP();
draw();
in.xs,in.ys
is input image resolutionin.pyx[y][x]
is the image pixel accesstxt
is the signature stringgSigPoints,gSigLines
are lists holding the signature points and lines.num
the number of items and .add(a)
adds a
to the end of the listThe pack/unpack ported from your VB code looks like this:
//---------------------------------------------------------------------------
#include "list.h"
//---------------------------------------------------------------------------
List<DWORD> gSigPoints;
List<DWORD> gSigLines;
// some test examples:
//AnsiString txt="221A*221A270A270A2503250320072007171617160D2A0D2A07380738073F073F0B3E0B3E15311531222122212C182C183016301631173117311A311A302230222E272E272D2C2D2C2C2F2C2F2C312C312C2F2C2F2E2B2E2B3126312633223322371D371D381C381C3B1B3B1B3C1C3C1C3D1F3D1F3D243D243C2D3C2D3A333A333A363A36393939393B383B383D363D36412E412E46264626492049204B1B4B1B4E184E184F174F175017501751185118511D511D51225122502450244F294F294F2C4F2C4E2F4E2F4F314F315030503052305230552C552C582958295D225D22601E601E611C611C621B621B621A621A601A601A5D1B5D1B5B1E5B1E5723572353285328512B512B502E502E502F502F513151315231523154305430582E582E592D592D5C2C5C2C5F2A5F2A6428642865286528692669266D246D247122712275207520791D791D7D1B7D1B81198119841884188618861887198719881A881A891B891B881C881C871E871E861F861F852085208421842182228222812481247F257F257E257E257D257D257C247C247C217C217D1F7D1F7E1C7E1C801A801A81198119821782178317831784188418851A851A851C851C86208620862286228625862587278727872B872B882E882E893289328A338A338E348E349033903393329332972F972F9A2D9A2D9F299F29A426A426AB20AB20AF1CAF1CB517B517B716B716B716";
//AnsiString txt="3711*371127152715103510351F2C1F2C312231223C1C3C1C3D203D20352D352D333233323D2E3D2E52225222671A671A6C196C196D1A6D1A6D1D6D1D69226922652665266428642864296429652965296E236E23781E781E8718871891179117961896189A199A199B1B9B1B9D1E9D1E9F209F20A021A021A021";
AnsiString txt="0808*08082008200820202020082008200808";
//---------------------------------------------------------------------------
AnsiString Hex(DWORD x,DWORD digits)
{
int i;
char *tab="0123456789ABCDEF";
AnsiString s="";
if (digits>8) digits=8;
s.SetLength(digits);
for (i=digits;i>0;i--,x>>=4) s[i]=tab[x&15];
return s;
}
//---------------------------------------------------------------------------
AnsiString PackBMP()
{
DWORD i;
AnsiString sig="";
// all points
for (i=0;i+1<gSigPoints.num;)
{
sig+=Hex(gSigPoints[i],2); i++; // x
sig+=Hex(gSigPoints[i],2); i++; // y
}
// separator
sig+="*";
// all lines
for (i=0;i+3<gSigLines.num;i++)
{
sig+=Hex(gSigLines[i],2); i++; // x0
sig+=Hex(gSigLines[i],2); i++; // y0
sig+=Hex(gSigLines[i],2); i++; // x1
sig+=Hex(gSigLines[i],2); i++; // y1
}
return sig;
}
//---------------------------------------------------------------------------
void UnpackBMP(AnsiString &sig)
{
DWORD a,x,y;
int i=1,l=sig.Length();
// all points
for(gSigPoints.num=0;(i+3<=l)&&(sig[i]!='*');)
{
a=sig[i]-'0'; if (a>9) a+='0'-'A'+10; x =a; i++;
a=sig[i]-'0'; if (a>9) a+='0'-'A'+10; x<<=4; x|=a; i++;
a=sig[i]-'0'; if (a>9) a+='0'-'A'+10; y =a; i++;
a=sig[i]-'0'; if (a>9) a+='0'-'A'+10; y<<=4; y|=a; i++;
gSigPoints.add(x);
gSigPoints.add(y);
}
// separator
i++;
// all lines
for(gSigLines.num=0;i+7<=l;)
{
a=sig[i]-'0'; if (a>9) a+='0'-'A'+10; x =a; i++;
a=sig[i]-'0'; if (a>9) a+='0'-'A'+10; x<<=4; x|=a; i++;
a=sig[i]-'0'; if (a>9) a+='0'-'A'+10; y =a; i++;
a=sig[i]-'0'; if (a>9) a+='0'-'A'+10; y<<=4; y|=a; i++;
gSigLines.add(x);
gSigLines.add(y);
a=sig[i]-'0'; if (a>9) a+='0'-'A'+10; x =a; i++;
a=sig[i]-'0'; if (a>9) a+='0'-'A'+10; x<<=4; x|=a; i++;
a=sig[i]-'0'; if (a>9) a+='0'-'A'+10; y =a; i++;
a=sig[i]-'0'; if (a>9) a+='0'-'A'+10; y<<=4; y|=a; i++;
gSigLines.add(x);
gSigLines.add(y);
}
}
//---------------------------------------------------------------------------
void DrawBMP(TCanvas *can)
{
DWORD i,x,y;
// all points
for (i=0;i+1<gSigPoints.num;)
{
x=gSigPoints[i]; i++;
y=gSigPoints[i]; i++;
can->Pixels[x][y]=can->Pen->Color;
}
// all lines
for (i=0;i+3<gSigLines.num;)
{
x=gSigLines[i]; i++;
y=gSigLines[i]; i++;
can->MoveTo(x,y);
x=gSigLines[i]; i++;
y=gSigLines[i]; i++;
can->LineTo(x,y);
}
}
//---------------------------------------------------------------------------
void signature_on_mouse(backbuffer &scr)
{
DWORD x,y;
// mouse left button last and actual
bool q0=scr.sh0.Contains(ssLeft);
bool q1=scr.sh1.Contains(ssLeft);
bool _redraw=false;
// actual mouse position
x=scr.mx1;
y=scr.my1;
// on mouse down event
if ((!q0)&&(q1))
{
gSigPoints.add(x); gSigLines.add(x);
gSigPoints.add(y); gSigLines.add(y);
_redraw=true;
}
// on mouse move event
if ((q0)&&(q1))
{
gSigLines.add(x);
gSigLines.add(y);
gSigLines.add(x);
gSigLines.add(y);
_redraw=true;
}
// mouse mouse up event
if ((q0)&&(!q1))
{
gSigLines.add(x);
gSigLines.add(y);
_redraw=true;
txt=PackBMP();
}
// right mouse button clears signature
if (scr.sh1.Contains(ssRight))
{
gSigPoints.num=0;
gSigLines.num=0;
_redraw=true;
}
if ((_redraw)&&(scr.win)) scr.win->Repaint();
scr.rfs_mouse();
}
//---------------------------------------------------------------------------
List<>,AnsiString,Backbuffer
to your platform style.This can handle any raster binary image not just signatures:
But as you can see the size of signature string is ~ 13.9 KByte