将签名位图转换为签名字符串(非常奇怪)

时间:2015-10-08 14:14:50

标签: vb.net image graphics bitmap

基本上我需要将位图图像转换为字符串,但这不是常见的。

困境是这个字符串由两部分组成:

1)积分 2)行

我需要将图像转换为由*。

分隔的两个部分

我给出的一个例子是:

"221A*221A270A270A2503250320072007171617160D2A0D2A07380738073F073F0B3E0B3E15311531222122212C182C183016301631173117311A311A302230222E272E272D2C2D2C2C2F2C2F2C312C312C2F2C2F2E2B2E2B3126312633223322371D371D381C381C3B1B3B1B3C1C3C1C3D1F3D1F3D243D243C2D3C2D3A333A333A363A36393939393B383B383D363D36412E412E46264626492049204B1B4B1B4E184E184F174F175017501751185118511D511D51225122502450244F294F294F2C4F2C4E2F4E2F4F314F315030503052305230552C552C582958295D225D22601E601E611C611C621B621B621A621A601A601A5D1B5D1B5B1E5B1E5723572353285328512B512B502E502E502F502F513151315231523154305430582E582E592D592D5C2C5C2C5F2A5F2A6428642865286528692669266D246D247122712275207520791D791D7D1B7D1B81198119841884188618861887198719881A881A891B891B881C881C871E871E861F861F852085208421842182228222812481247F257F257E257E257D257D257C247C247C217C217D1F7D1F7E1C7E1C801A801A81198119821782178317831784188418851A851A851C851C86208620862286228625862587278727872B872B882E882E893289328A338A338E348E349033903393329332972F972F9A2D9A2D9F299F29A426A426AB20AB20AF1CAF1CB517B517B716B716B716"

所以我所知道的是,221A是点,而另一个字符串是线,但需要能够实现这一点。

你以前有没有遇到过这个?

我尝试将位图转换为Base64String,但这并不能让我的任何东西靠近。

如果它帮助我只在VB中反向,即从字符串到图像:

Private Sub unpackBMP(ByVal BITMAP As String)
Dim points As String
Dim lines As String
Dim x As Long
Dim y As Long
Dim x1 As Long
Dim y1 As Long

points = firstItem(BITMAP, "*")
lines = BITMAP


While Len(points) > 0

x = "&H" & Mid(points, 1, 2)
y = "&H" & Mid(points, 3, 2)
points = Mid(points, 5, Len(points) - 4)

'picDraw.PSet (Val(x), Val(y)), vbBlack
'Call picDraw.DrawPoint(CDbl(x), CDbl(y))
'picDraw.Refresh
Wend


While Len(lines) > 0

x = "&H" & Mid(lines, 1, 2)
y = "&H" & Mid(lines, 3, 2)
x1 = "&H" & Mid(lines, 5, 2)
y1 = "&H" & Mid(lines, 7, 2)

lines = Mid(lines, 9, Len(lines) - 8)

'picDraw.Line (Val(x), Val(y))-(Val(x1), Val(y1)), vbBlack
'Call picDraw.DrawLine(CDbl(x), CDbl(y), CDbl(x1), CDbl(y1), 0)
'picDraw.Refresh
Wend

'Call picDraw.DrawLine(lines(1, tmp), lines(2, tmp), lines(3, tmp), lines(4, tmp), 0)
End Sub

Public Function firstItem(pstrItems As String, pstrDelim As String) As String

Dim lngPos As Long
Dim strRes As String
'Dim strDelim As String

strRes = ""

lngPos = InStr(pstrItems, pstrDelim)

If lngPos > 0 Then
  strRes = Left$(pstrItems, lngPos - 1)
  pstrItems = Mid$(pstrItems, lngPos + 1)
Else
  strRes = pstrItems
  pstrItems = ""
End If

firstItem = strRes

End Function

如果您需要任何进一步的详细信息,请与我们联系。

背景:这是Windows Mobile 6.5设备上的图片框中的签名。请参阅下面的图像及其相关字符串。希望这会有所帮助。

280172 - Signature bmp

String for SIGNATURE 280172:
3711*371127152715103510351F2C1F2C312231223C1C3C1C3D203D20352D352D333233323D2E3D2E52225222671A671A6C196C196D1A6D1A6D1D6D1D69226922652665266428642864296429652965296E236E23781E781E8718871891179117961896189A199A199B1B9B1B9D1E9D1E9F209F20A021A021A021

添加附件堆栈使其成为png但它是bmp文件,但它是204 x 64 1位深度图像。

重新排序的字符串(由Spektre提供)

3711*3711
2715 2715
1035 1035
1F2C 1F2C
3122 3122
3C1C 3C1C
3D20 3D20
352D 352D
3332 3332
3D2E 3D2E
5222 5222
671A 671A
6C19 6C19
6D1A 6D1A
6D1D 6D1D
6922 6922
6526 6526
6428 6428
6429 6429
6529 6529
6E23 6E23
781E 781E
8718 8718
9117 9117
9618 9618
9A19 9A19
9B1B 9B1B
9D1E 9D1E
9F20 9F20
A021 A021 A021

单个水平线会生成以下字符串:

101F*101F
1D21 1D21
2121 2121 
2820 2820     
2C20 2C20
3120 3120
3921 3921
3F21 3F21
4521 4521
4A21 4A21
5122 5122
5822 5822
6121 6121
6421 6421
6721 6721
6A20 6A20
6C20 6C20
6F20 6F20
7220 7220
7520 7520
7720 7720
7920 7920
7D20 7D20
8020 8020
8120 8120
8320 8320
861F 861F
871F 871F
891F 891F
8A1F 8A1F
8D1F 8D1F
8F1F 8F1F
931F 931F
961F 961F
971F 971F
9A1F 9A1F
9C1F 9C1F
9D1E 9D1E
A11E A11E
A31E A31E
A51D A51D
A71D A71D
A91D A91D
AA1C AA1C
AB1C AB1C
AD1C AD1C
AE1C AE1C
B01C B01C
B11B B11B
B21B B21B
B41B B41B
B51A B51A
B61A B61A
B81A B81A
B919 B919
BB19 BB19
BC19 BC19
BD19 BD19
BE19 BE19
BF19 BF19
C019 C019
C11A C11A
C31A C31A
C41A C41A
C51A C51A
C61B C61B
C71B C71B
C81C C81C
C81C 

Single Line

因此,这就是使PictureBox签名成为字符串的原因:

'signature
Public gSigPoints() As Long
Public gSigLines() As Long

Public gSigPointCount As Long
Public gSigLinesCount As Long

Public Function PackBMP() As String

Dim tmpStr1 As String
Dim tmpStr2 As String
Dim tmpStr3 As String
Dim tmpStr4 As String
Dim tmp As Long

    gJob_Signature = ""

    For tmp = 1 To gSigPointCount

        tmpStr1 = CStr(Hex(gSigPoints(1, tmp)))
        tmpStr2 = CStr(Hex(gSigPoints(2, tmp)))

        If Len(tmpStr1) = 2 And Len(tmpStr2) = 2 Then
          gJob_Signature = gJob_Signature & tmpStr1 & tmpStr2 '& ";" & ";"
        Else
          If Len(tmpStr1) = 1 Then tmpStr1 = "0" & tmpStr1
          If Len(tmpStr2) = 1 Then tmpStr2 = "0" & tmpStr2
          If Len(tmpStr1) = 2 And Len(tmpStr2) = 2 Then
            gJob_Signature = gJob_Signature & tmpStr1 & tmpStr2  '& ";"& ";"
          End If
        End If


    Next 'tmp

    gJob_Signature = gJob_Signature & "*"

    For tmp = 1 To gSigLinesCount

        tmpStr1 = CStr(Hex(gSigLines(1, tmp)))
        tmpStr2 = CStr(Hex(gSigLines(2, tmp)))
        tmpStr3 = CStr(Hex(gSigLines(3, tmp)))
        tmpStr4 = CStr(Hex(gSigLines(4, tmp)))

        If Len(tmpStr1) = 2 And Len(tmpStr2) = 2 And Len(tmpStr3) = 2 And Len(tmpStr4) = 2 Then
          gJob_Signature = gJob_Signature & tmpStr1 & tmpStr2 & tmpStr3 & tmpStr4  '& ";"
        Else
          If Len(tmpStr1) = 1 Then tmpStr1 = "0" & tmpStr1
          If Len(tmpStr2) = 1 Then tmpStr2 = "0" & tmpStr2
          If Len(tmpStr3) = 1 Then tmpStr3 = "0" & tmpStr3
          If Len(tmpStr4) = 1 Then tmpStr4 = "0" & tmpStr4

          If Len(tmpStr1) = 2 And Len(tmpStr2) = 2 And Len(tmpStr3) = 2 And Len(tmpStr4) = 2 Then
            gJob_Signature = gJob_Signature & tmpStr1 & tmpStr2 & tmpStr3 & tmpStr4   '& ";"
          End If
        End If

    Next 'tmp

End Function


Public Sub DrawBMP(ByRef pic As PictureBox)
Dim x As Long

  pic.Cls
  For x = 1 To gSigPointCount
    Call pic.DrawPoint(gSigPoints(1, x), gSigPoints(2, x))
  Next x

  For x = 1 To gSigLinesCount
    Call pic.DrawLine(gSigLines(1, x), gSigLines(2, x), gSigLines(3, x), gSigLines(4, x), 0)
  Next x
  pic.Refresh

End Sub


Public Sub AddPoint(x As Long, Y As Long)

  gSigPointCount = gSigPointCount + 1
  ReDim Preserve gSigPoints(2, gSigPointCount)
  gSigPoints(1, gSigPointCount) = x
  gSigPoints(2, gSigPointCount) = Y

End Sub



Public Sub AddLine(x As Long, Y As Long, x1 As Long, y1 As Long)

  gSigLinesCount = gSigLinesCount + 1
  ReDim Preserve gSigLines(4, gSigLinesCount)
  gSigLines(1, gSigLinesCount) = x
  gSigLines(2, gSigLinesCount) = Y
  gSigLines(3, gSigLinesCount) = x1
  gSigLines(4, gSigLinesCount) = y1

End Sub

'********signature
Private miX As Double
Private miY As Double
Private isup As Boolean
'*********end of signature

'@@ singnatures
Private Sub picDraw_MouseDown(Button As Long, Shift As Long, x As Double, Y As Double)

    picDraw.DrawPoint x, Y, 0
    picDraw.Refresh
    Call AddPoint(x, Y)
    miX = x
    miY = Y
    isup = False

End Sub



Private Sub picDraw_MouseMove(Button As Long, Shift As Long, x As Double, Y As Double)

  If isup Then
    miX = x
    miY = Y
    isup = False
  Else

    If Button = 1 Then

      picDraw.DrawLine miX, miY, x, Y, 0
      picDraw.Refresh
      Call AddLine(miX, miY, x, Y)
      miX = x
      miY = Y
    End If

  End If

End Sub



Private Sub picDraw_MouseUp(ByVal Button As Long, ByVal Shift As Long, ByVal x As Double, ByVal Y As Double)
  isup = True
End Sub

这是关于签名图片框的全部内容。

1 个答案:

答案 0 :(得分:0)

我从您发布的代码中找出了编码(不得不将其移植到C ++),所以编码:

  1. 字符串以点列表开头

    每个点都以4位十六进制数表示。前2个十六进制数字是x坐标,后2个数字是y坐标点。 (可能标记每个鼠标按下事件,因此它保存有关连续绘制图像的数量的信息)

  2. 然后分隔符*跟随

  3. 在该行列表出现之后
  4. 每行包含2个点,因此每行总共有8位十六进制数。序列是x0,y0,x1,y1每个坐标的2位十六进制数。如果字符串仅包含4位十六进制数字(结尾),则标记签名字符串的结尾。

  5. 因此,当您想制作自己的签名代码时:

    1. 清除点列表和行列表

    2. 鼠标按下(左键单击或笔点击)事件
    3. 将当前鼠标/笔位置添加到点列表中,并作为行列表的起点

    4. 鼠标/笔移动事件
    5. 首先查看鼠标按钮是否仍然被点击或笔仍然敲击打击垫。如果不忽略此事件。如果是,则将当前鼠标位置添加到行列表两次(这就是为什么它们重复第一个结束当前行,第二个开始新行)

    6. 鼠标/笔记事件
    7. 关闭实际行,然后将当前鼠标位置添加到行列表

    8. 导出前
    9. 复制行列表中的最后一个点以标记字符串结尾

    10. 就是这样。如果您需要转换已经绘制的图像(光栅),那么您可能会遇到比较问题,因为您不太可能以与作者签名相同的方式对图像进行矢量化。导致相同图像的错过匹配。另外三倍的最后一点很可能是因为鼠标/笔上事件的编码错误,同时在mouse movemouse up事件中添加相同的点

      以这种方式编码的图像限制为256x256像素。

      这是第一个签名字符串的解码图像示例:

      signature

      signature="221A*221A270A270A2503250320072007171617160D2A0D2A07380738073F073F0B3E0B3E15311531222122212C182C183016301631173117311A311A302230222E272E272D2C2D2C2C2F2C2F2C312C312C2F2C2F2E2B2E2B3126312633223322371D371D381C381C3B1B3B1B3C1C3C1C3D1F3D1F3D243D243C2D3C2D3A333A333A363A36393939393B383B383D363D36412E412E46264626492049204B1B4B1B4E184E184F174F175017501751185118511D511D51225122502450244F294F294F2C4F2C4E2F4E2F4F314F315030503052305230552C552C582958295D225D22601E601E611C611C621B621B621A621A601A601A5D1B5D1B5B1E5B1E5723572353285328512B512B502E502E502F502F513151315231523154305430582E582E592D592D5C2C5C2C5F2A5F2A6428642865286528692669266D246D247122712275207520791D791D7D1B7D1B81198119841884188618861887198719881A881A891B891B881C881C871E871E861F861F852085208421842182228222812481247F257F257E257E257D257D257C247C247C217C217D1F7D1F7E1C7E1C801A801A81198119821782178317831784188418851A851A851C851C86208620862286228625862587278727872B872B882E882E893289328A338A338E348E349033903393329332972F972F9A2D9A2D9F299F29A426A426AB20AB20AF1CAF1CB517B517B716B716B716";

      此处为方形示例

      enter image description here

      signature="0808*080820082008202020200820082008080808";

      所以重新订购时:

      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]光栅图像到字符串转换

      首先,您需要将图像转换为矢量形式。有许多复杂的方法可以将栅格图像多边形化为矢量形式,但它们通常使用来自数学,图像处理,结构等的高级内容......需要有关该主题的广泛知识。我假设你需要这个只是为了在设备上可视化,所以相反我会使用非常简单的转换导致不合理的大结果(与高级方法相比)。如果你的设备对字符串大小没有太小的限制那么你应该没问题,否则你需要使用更先进的东西:

      1. 清除您的矢量表示

        点数列表和行列表

      2. 遍历图像的所有水平线

      3. 处理每一行

        1. 从当前位置x0找到第一个设置的像素
        2. 从当前位置x1找到第一个未设置的像素
        3. 如果找到x0,x1

          • 添加点(x0,y)
          • 添加行(x0,y,x1-1,y)
      4. 整个图像处理后将矢量形式转换为字符串

        1. clear string
        2. 将所有点的列表添加到字符串
        3. 将分隔符*添加到字符串
        4. 将所有行的列表添加到字符串
      5. 这就是它在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是输入图像分辨率
        • in.pyx[y][x]是图像像素访问
        • txt是签名字符串
        • gSigPoints,gSigLines是包含签名点和行
        • 的列表
        • 这些列表包含.num项目数,.add(a)a添加到列表末尾

        从VB代码移植的打包/解压缩包如下所示:

        //---------------------------------------------------------------------------
        #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();
            }
        //---------------------------------------------------------------------------
        
        • 其中backbuffer是我的类,用于连接窗口后备缓冲区图像和鼠标处理程序事件。
        • 所以只需将List<>,AnsiString,Backbuffer更改为您的平台样式。

        这可以处理任何栅格二进制图像,而不仅仅是签名:

        raster -> signature example

        但是你可以看到签名字符串的大小是〜13.9 KByte