我正在使用Ingenico i6580 pinpad机器,并以默认的3字节ascii签名格式检索客户的签名。我使用VS2010在VB.NET中编码。有没有人知道是否有可以将此格式转换回图像的实用程序?
答案 0 :(得分:0)
我正在使用这个C#函数在PictureEdit(一个DevExpress控件)上绘制图像
public void getSignGraph(string signatureData)
{
var stringOfPoints = signatureData.Split(',');
var beginStroke = true;
//PictureEdit1 is a DevExpress control where the image will be drawn
using (Graphics g = PictureEdit1.CreateGraphics())
{
g.Clear(Color.White);
var keepx = "";
var keepy = "";
foreach (var pointval in stringOfPoints)
{
if (!String.IsNullOrEmpty(pointval))
{
var point = pointval.Split(',');
var x = point[0];
var y = point[1];
if (x == "#" && y == "#")
{
beginStroke = true;
}
else
{
if (beginStroke)
{
beginStroke = false;
}
else
{
g.DrawLine(new Pen(Color.Black), new Point(Convert.ToInt32(keepx), Convert.ToInt32(keepy)), new Point(Convert.ToInt32(x), Convert.ToInt32(y)));
}
}
keepx = x;
keepy = y;
}
}
}
}
答案 1 :(得分:0)
我看到这个帖子很旧了,但我希望这对未来的人有所帮助。
可以在 here 中找到 SigBin2 格式的文档。
此外,this forum post 在解决这个问题时对我很有帮助。
这是我将 SigBin2 签名渲染到图像的最终代码:
private Bitmap sigBinToImage(string sigBin2Source, float scaleFactor)
{
// Compute all the points for each of the segments in the signature
List<List<Point>> pointLists = sigBinToPoints(sigBin2Source);
// Draw the signature
Bitmap signatureImage = pointsToImage(pointLists, scaleFactor);
return signatureImage;
}
private List<List<Point>> sigBinToPoints(string sigBin2Source)
{
/*
* The SigBin2 format (also called 3-byte Ascii format) is a relative coordinate format.
* The format is structured as follows:
* 1) Segment Start control character
* An ascii character in the range 96-111 containing bits used to determine the
* starting position of the line segment (pen stroke).
*
* 2) Coordinate Data Character 1
* An ascii character in the range 32-95 containing bits used to determine the
* X-offset from the last coordinate.
* Note that the ascii value has to be shifted down by 32 before being used.
*
* 3) Coordinate Data Character 2
* An ascii character in the range 32-95 containing bits used to determine the
* Y-offset from the last coordinate
* Note that the ascii value has to be shifted down by 32 before being used.
*
* 4) Coordinate Data Character 3
* An ascii character in the range 32-95 containing bits used to determine the
* remaining bits of the X-offset and Y-offset from the last coordinate
* Note that the ascii value has to be shifted down by 32 before being used.
*
* *) Items (2), (3), and (4) are repeated for all datapoints in the line segment (pen stroke).
*
* 5) Pen Up control character
* An ascii character (112) signaling that the line segment (pen stroke) has ended
*
* *) Items (1) through (5) are repeated for all line segments (pen strokes)
*
* More information about this format can be found here:
* https://forums.macrumors.com/attachments/3-byte-ascii-doc.295002/
*/
short cX = 0, cY = 0; // Absolute coordinate of last datapoint
short dX = 0, dY = 0; // Offset from last datapoint
int parseMode = 0; // The type of character we are expecting next
bool firstPointInSegment = false; // Disables sign-extension for the first coordinate in the segment
List<List<Point>> points = new List<List<Point>>();
// Loop through all characters in the SigBin2 string
for (int i = 0; i < sigBin2Source.Length; i++)
{
short asciiValue = (short)sigBin2Source[i];
switch (asciiValue)
{
case object _ when asciiValue >= 0x60 && asciiValue <= 0x6F: // Segment Start control character
if (parseMode == 0)
{
// Get the start position bits (b3 = X10, b2 = X9, b1 = Y10, b0 = Y9)
cX = (short)((asciiValue & 0xC) << 7);
cY = (short)((asciiValue & 0x3) << 9);
// Look for the first byte of the 3-byte coordinate
parseMode = 1;
// Ignore relative offset for the first point of the sequence
firstPointInSegment = true;
// Allocate new list for this segment's points
points.Add(new List<Point>());
}
else
{
// Segment Start character is in an invalid position (a Pen Up character needs to precede it)
throw new Exception($"Illegal Segment Start character '{sigBin2Source[i].ToString()}' at position {i.ToString()}");
}
break;
case object _ when asciiValue >= 0x20 && asciiValue <= 0x5F: // Part of a 3-byte coordinate
// Check which byte of the 3-byte coordinate that this is
// Note: ascii values are offset by 0x20
if (parseMode == 1) // First byte
{
// Get X-bits 3 to 8 (bits 0 to 5 of asciiValue)
dX = (short)((asciiValue - 0x20) << 3);
// Look for the second byte
parseMode = 2;
}
else if (parseMode == 2) // Second byte
{
// Get Y-bits 3 to 8 (bits 0 to 5 of asciiValue)
dY = (short)((asciiValue - 0x20) << 3);
// Look for the third byte
parseMode = 3;
}
else if (parseMode == 3) // Third byte
{
// Mask bits 0 to 5 (for safety) and shift ascii value
asciiValue = (short)((asciiValue - 0x20) & 0x3F);
// Get X bits 0 to 2 (bits 3 to 5 of asciiValue)
dX = (short)(dX | ((asciiValue >> 3) & 0x7));
// Get Y bits 0 to 2 (bits 0 to 2 of asciiValue)
dY = (short)(dY | (asciiValue & 0x7));
// Sign extend
if (!firstPointInSegment) // Don't sign-extend offsets for the first point in the segment
{
// If sign bit is 1, sign-extend to bits 9-15 to make it a negative short
if (dX > 255)
dX = (short)(dX | 0xFE00);
if (dY > 255)
dY = (short)(dY | 0xFE00);
}
else
{
firstPointInSegment = false;
}
// Add the coordinate offset to the last absolute coordinate
cX += dX;
cY += dY;
// Add this point to the list
points[points.Count - 1].Add(new Point(cX, cY));
// Assume the next character will be the first byte of another 3-byte coordinate
parseMode = 1;
}
else
{
// Coordinate character is in invalid position (a Segment Start character needs to preceed it)
throw new Exception($"Illegal Coordinate character '{sigBin2Source[i].ToString()}' at position {i.ToString()}");
}
break;
case 0x70: // Pen Up control character
if (parseMode == 1)
{
// Look for the next Segment Start control character
parseMode = 0;
}
else
{
// Pen Up character is in invalid position (the preceding coordinate needs to be complete)
throw new Exception($"Illegal Pen Up character '{sigBin2Source[i].ToString()}' at position {i.ToString()}");
}
break;
default: // Unrecognized character
throw new Exception($"Unrecognized character '{sigBin2Source[i].ToString()}' at position {i.ToString()} (mode: {parseMode.ToString()})");
}
}
// Return the list of coordinate points
return points;
}
private Bitmap pointsToImage(List<List<Point>> pointLists, float scaleFactor)
{
// Find the max and min points
int minX = int.MaxValue, maxX = int.MinValue, minY = int.MaxValue, maxY = int.MinValue;
foreach (List<Point> pointList in pointLists) {
foreach (Point p in pointList)
{
if (p.X > maxX)
maxX = p.X;
if (p.X < minX)
minX = p.X;
if (p.Y > maxY)
maxY = p.Y;
if (p.Y < minY)
minY = p.Y;
}
}
// Create a bitmap from the computed dimensions (with some padding around the edges)
int edgePaddingBase = 5;
int edgePadding = (int)((float)edgePaddingBase * scaleFactor);
int imgWidth = (int)((float)(maxX - minX) * scaleFactor) + (edgePadding * 2);
int imgHeight = (int)((float)(maxY - minY) * scaleFactor) + (edgePadding * 2);
Bitmap signatureImg = new Bitmap(imgWidth, imgHeight);
// Setup drawing settings
// Note that the Y-axis is flipped
Graphics g = Graphics.FromImage(signatureImg);
g.ScaleTransform(scaleFactor, -1F * scaleFactor);
g.TranslateTransform((-1 * minX) + edgePaddingBase, (-1 * minY) + -1.0F * (maxY - minY) - edgePaddingBase);
g.Clear(Color.White);
// Draw each of the segments on the image
foreach (List<Point> pointList in pointLists)
g.DrawLines(Pens.Black, pointList.ToArray<Point>());
g.Dispose();
// Return the signature image
return signatureImg;
}
需要注意的一件事是确保在处理之前取消转义 SigBin 字符串。如果您在 JSON 文件中收到签名数据,则 SigBin 字符串很可能会被转义。例如,在 JSON 中,引号 " 用 \" 表示,因此您必须确保字符串在处理之前未转义。 This 页面对于取消转义 SigBin 字符串很有用。但是,请注意,此工具有时会将事情解释为实际上并非旨在进行转义的转义。如果您在我的代码中遇到“非法字符位置”异常,则很可能是转义问题。