2

I'm going to use the signature tag of PrimeFaces in my site, but I don't know how can I store in a form of an image in my database or if possible any other type.

I just want to display it later in a data table so the admin can manage and verify the authenticity of those signatures.

Jasper de Vries
  • 19,370
  • 6
  • 64
  • 102
javaManiac
  • 51
  • 2
  • 8

3 Answers3

6

Just check the PrimeFaces showcase for p:signature. Signature values are bound to a string, so you can simply store a signature as a string in your database. Later you can simply show the signature using the stored string in combination with the readonly attribute set to true. This is exactly what is demonstrated in the showcase.

Your signature string value will look something like:

{"lines":[[[81,75],[81,78],[81,80],[81,84],[83,87],...]]}

If you really want to store it as an image instead of a string, you have a few options.

SVG

As the string basically is an JSON object with a "lines" array, which per line has the coordinates, you can simply transform it to a SVG. All you need to do is create some paths. A rough implementation:

public String toSvg(String signature, int width, int height) {
  List<String> paths = new ArrayList<>();
  try (JsonReader jsonReader = Json.createReader(new StringReader(signature))) {
    JsonObject jsonObject = jsonReader.readObject();
    JsonArray jsonArray = jsonObject.getJsonArray("lines");
    jsonArray.forEach(line -> paths.add(toSvgPath((JsonArray) line)));
  }
  StringBuilder sb = new StringBuilder();
  sb.append(String.format("<svg width=\"%d\" height=\"%d\" xmlns=\"http://www.w3.org/2000/svg\">\n", width, height));
  paths.forEach(sb::append);
  sb.append("</svg>");
  return sb.toString();
}


private String toSvgPath(JsonArray line) {
  StringBuilder sb = new StringBuilder("<path d=\"");
  for (int i = 0; i < line.size(); i++) {
    JsonArray coords = (JsonArray) line.getJsonArray(i);
    sb.append(String.format("%s%d %d ", (i == 0 ? "M" : "L"), coords.getInt(0), coords.getInt(1)));
  }
  sb.append("\" stroke=\"black\" fill=\"transparent\"/>\n");
  return sb.toString();
}

But, as the SVG can easily be created from the JSON object, you might just want to store the JSON object and create the SVG when you need to render the signature.

See also:

PNG

p:signature has a base64Value attribute which writes a PNG image as base64 encoded data to the provided property:

<p:signature id="signature"
             base64Value="#{myBean.signature}">

This will give you a URL which will look like:

data:image/png;base64,iVBORw0KGgoAAAANSU...

In your bean it's just a matter of getting the data from the URL:

private static final String URL_DATA_PNG_BASE64_PREFIX = "data:image/png;base64,";

..

String encoded = signatureUrl.substring(URL_DATA_PNG_BASE64_PREFIX.length());
byte[] decoded = Base64.getDecoder().decode(encoded);

You could optionally save it as a file:

Path path = Paths.get("path/to/your/image.png");
Files.write(path, decoded);

See also:

Jasper de Vries
  • 19,370
  • 6
  • 64
  • 102
2

I was able to convert the signature into byte array to store it encrypted in my content repository (filenet) using following code:

/**
     * A point along a line within a signature.
     */
    private static class Point {

        private int x;
        private int y;

        public Point(float x, float y) {
            this.x = Math.round(x);
            this.y = Math.round(y);
        }
    }

    public static void generateSignature(String jsonEncoding, OutputStream output) throws IOException {
        output.write(redrawSignature(extractSignature(jsonEncoding)));
        output.close();
    }

    /**
     * Extract the signature lines and points from the JSON encoding.
     * 
     * @param jsonEncoding
     *            the JSON representation of the signature
     * @return the retrieved lines and points
     */
    private static List<List<Point>> extractSignature(String jsonEncoding) {
        List<List<Point>> lines = new ArrayList<List<Point>>();
        Matcher lineMatcher = Pattern.compile("(\\[(?:,?\\[-?[\\d\\.]+,-?[\\d\\.]+\\])+\\])").matcher(jsonEncoding);
        while (lineMatcher.find()) {
            Matcher pointMatcher = Pattern.compile("\\[(-?[\\d\\.]+),(-?[\\d\\.]+)\\]").matcher(lineMatcher.group(1));
            List<Point> line = new ArrayList<Point>();
            lines.add(line);
            while (pointMatcher.find()) {
                line.add(new Point(Float.parseFloat(pointMatcher.group(1)), Float.parseFloat(pointMatcher.group(2))));
            }
        }
        return lines;
    }

    /**
     * Redraw the signature from its lines definition.
     * 
     * @param lines
     *            the individual lines in the signature
     * @return the corresponding signature image
     * @throws IOException
     *             if a problem generating the signature
     */
    private static byte[] redrawSignature(List<List<Point>> lines) throws IOException {
        BufferedImage signature = new BufferedImage(SIGNATURE_WIDTH, SIGNATURE_HEIGHT, BufferedImage.TYPE_BYTE_GRAY);
        Graphics2D g = (Graphics2D) signature.getGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, signature.getWidth(), signature.getHeight());
        g.setColor(Color.BLACK);
        g.setStroke(new BasicStroke(2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        Point lastPoint = null;
        for (List<Point> line : lines) {
            for (Point point : line) {
                if (lastPoint != null) {
                    g.drawLine(lastPoint.x, lastPoint.y, point.x, point.y);
                }
                lastPoint = point;
            }
            lastPoint = null;
        }
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        ImageIO.write(signature, IMAGE_FORMAT, output);
        return output.toByteArray();
    }
Mahmoud Saleh
  • 33,303
  • 119
  • 337
  • 498
-2

Value of p:signature store as a string value in database when you decide to send to database as for example {"lines":[[[308.4,113.86],[284.4,117.86],[233.4,125.86],[168.4,135.86],[116.4,143.86],[89.4,145.86],[90.4,145.86],[106.4,141.86],[144.4,135.86],[180.4,131.86],[184.4,131.86],[184.4,131.86],[177.4,131.86]}