Some text some message..
Some text some message..
Some text some message..
Some text some message..
  • Beranda
  • »
  • Artikel
  • »
  • Tanda Tangan Digital Dengan Javascript, PHP Dan Menyimpannya Dalam Bentuk Gambar PNG

Tanda Tangan Digital Dengan Javascript, PHP Dan Menyimpannya Dalam Bentuk Gambar PNG

previous Previous Page

Tanda tangan digital atau digital signature merupakan tanda tangan yang dilakukan secara virtual dan disimpan dalam bentuk gambar ataupun dalam bentuk teks murni format base64 encoded. Tanda tangan digital banyak digunakan di berbagai bidang misalnya perbankan, koorporasi dan lembaga formal lainnya dalam menjawab perkembangan tekhnologi dimana customer akan dilayani secara virtual melalui jaringan internet. Tanda tangan digital mengganti peran kertas dan pena sebagai sarana membubuhkan tanda tangannya.

Tanda tangan digital dapat dilakukan secara langsung di atas layar smartphone (touch screen). Dan jika pada PC atau laptop, dilakukan dengan bantuan mouse. Hasil tanda tangan digital akan diproses dan disimpan dalam bentuk gambar murni.

Membuat Tanda Tangan Digital (Digital Signature)

Cara pembuatan tanda tangan digital dilakukan dengan HTML tag canvas. Dimana tag canvas ini merupakan media untuk menggambar suatu objek baik itu titik, lingkaran, teks dan juga gambar. Dengan canvas, tanda tangan digital akan diproses. Hasil dari gambar yang dituliskan pada canvas merupakan data teks murni dalam format base64 encoded pembentuk gambar PNG yang kemudian dikirimkan ke server.

Pengiriman hasil tersebut masih dalam teks murni dan belum dalam bentuk gambar format png. Namun pada dasarnya teks murni tersebut merupakan kumpulan informasi pembentuk gambar aslinya. Data teks tersebut dapat disimpan pada database secara langsung sebagai alternatif lain untuk menampilkan gambar. Untuk menampilkannya dengan menuliskan data teks tersebut sebagai sumber gambar rujukan di atribut src pada elemen tag <img>.

Namun jika ingin menyimpannya dalam gambar, dilakukan dengan konversi teks base64 encoded tersebut menjadi gambar dalam format PNG. Pengerjaanya cukup sederhana yaitu dengan bantuan fungsi file_put_contents().

Membuat Halaman index

Halaman index merupakan halaman utama yang digunakan untuk menampilkan bidang tanda tangan. Bidang ini merupakan kumpulan berbagai tag HTML yang berfungsi sebagai sarana bagi pengguna dalam menuliskan tanda tangannya.

Tag canvas digunakan sebagai media gambar yang bersifat dapat digambari dan ditulisi secara manual melalui pointer mouse. Agar canvas dapat ditulisi, diperlukan library signature.js. Library ini akan menghandle keleluruhan proses gambar hingga diterjemahkan dalam bentuk informasi data teks untuk keperluan konversi ke dalam bentuk gambar format PNG.

Saat pengguna menekan tombol Save as PNG, informasi data dari canvas akan disalin pada input type hidden dengan nama signature. Data dari input ini yang akan dikirimkan menuju halaman process.php untuk dilakukan penyimpanan dalam bentuk gambar murni.

Berikut halaman index.php :

PHP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<!DOCTYPE html>
<html>
<head>
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <title>The Signature</title>
   <link rel="stylesheet" href="../libs/css/bootstrap.v3.3.6.css">
   <script type="text/javascript" src="assets/signature.js"></script>
   <style>
     body{
     padding: 15px;
     }
     #note{position:absolute;left:50px;top:35px;padding:0px;margin:0px;cursor:default;}
</style>
</head>
<body>
<h1>Digital Signature</h1>
<form method="post" action="process.php" enctype="multipart/form-data">
   <div id="signature-pad">
     <div style="border:solid 1px teal; width:360px;height:110px;padding:3px;position:relative;">
        <div id="note" onmouseover="my_function();">The signature should be inside box</div>
        <canvas id="the_canvas" width="350px" height="100px"></canvas>
     </div>
     <div style="margin:10px;">
        <input type="hidden" id="signature" name="signature">
        <button type="button" id="clear_btn" class="btn btn-danger" data-action="clear"><span class="glyphicon glyphicon-remove"></span> Clear</button>
        <button type="submit" id="save_btn" class="btn btn-primary" data-action="save-png"><span class="glyphicon glyphicon-ok"></span> Save as PNG</button>
     </div>
   </div>
<form>
   
<script>
var wrapper = document.getElementById("signature-pad");
var clearButton = wrapper.querySelector("[data-action=clear]");
var savePNGButton = wrapper.querySelector("[data-action=save-png]");
var canvas = wrapper.querySelector("canvas");
var el_note = document.getElementById("note");
var signaturePad;
signaturePad = new SignaturePad(canvas);
clearButton.addEventListener("click", function (event) {
   document.getElementById("note").innerHTML="The signature should be inside box";
   signaturePad.clear();
});
savePNGButton.addEventListener("click", function (event){
   if (signaturePad.isEmpty()){
     alert("Please provide signature first.");
     event.preventDefault();
   }else{
     var canvas = document.getElementById("the_canvas");
     var dataUrl = canvas.toDataURL();
     document.getElementById("signature").value = dataUrl;
   }
});
function my_function(){
   document.getElementById("note").innerHTML="";
}
</script>
</body>
</html>

Halaman signature.js

Halaman signature.js merupakan library untuk menjalankan proses tanda tangan pada canvas. Library ini menangani keseluruhan event saat pengguna mulai menuliskan tanda tangan pada canvas sampai tanda tangannya selesai. Kemudian mencatatnya sebagai koordinat yang mewakili titik dan garis tanda tangan pada canvas.

Berikut halaman signature.js :

JAVASCRIPT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
(function (global, factory) {
   typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
   typeof define === 'function' && define.amd ? define(factory) :
   (global.SignaturePad = factory());
}(this, (function () { 'use strict';
function Point(x, y, time) {
   this.x = x;
   this.y = y;
   this.time = time || new Date().getTime();
}
Point.prototype.velocityFrom = function (start) {
   return this.time !== start.time ? this.distanceTo(start) / (this.time - start.time) : 1;
};
Point.prototype.distanceTo = function (start) {
   return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
};
function Bezier(startPoint, control1, control2, endPoint) {
   this.startPoint = startPoint;
   this.control1 = control1;
   this.control2 = control2;
   this.endPoint = endPoint;
}
Bezier.prototype.length = function () {
   var steps = 10;
   var length = 0;
   var px = void 0;
   var py = void 0;
   for (var i = 0; i <= steps; i += 1) {
     var t = i / steps;
     var cx = this._point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
     var cy = this._point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
     if (i > 0) {
     var xdiff = cx - px;
     var ydiff = cy - py;
     length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
     }
     px = cx;
     py = cy;
   }
   return length;
};
Bezier.prototype._point = function (t, start, c1, c2, end) {
   return start * (1.0 - t) * (1.0 - t) * (1.0 - t) + 3.0 * c1 * (1.0 - t) * (1.0 - t) * t + 3.0 * c2 * (1.0 - t) * t * t + end * t * t * t;
};
function SignaturePad(canvas, options) {
   var self = this;
   var opts = options || {};
   this.velocityFilterWeight = opts.velocityFilterWeight || 0.7;
   this.minWidth = opts.minWidth || 0.5;
   this.maxWidth = opts.maxWidth || 1.5;
   this.dotSize = opts.dotSize || function () {
     return (this.minWidth + this.maxWidth) / 2;
   };
   this.penColor = opts.penColor || '#333';
   this.backgroundColor = opts.backgroundColor || 'rgba(0,0,0,0)';
   this.onBegin = opts.onBegin;
   this.onEnd = opts.onEnd;
   this._canvas = canvas;
   this._ctx = canvas.getContext('2d');
   this.clear();
   this._handleMouseDown = function (event) {
     if (event.which === 1) {
     document.getElementById("note").innerHTML="";
     self._mouseButtonDown = true;
     self._strokeBegin(event);
     }
   };
   this._handleMouseMove = function (event) {
     if (self._mouseButtonDown) {
     self._strokeUpdate(event);
     }
   };
   this._handleMouseUp = function (event) {
     if (event.which === 1 && self._mouseButtonDown) {
     self._mouseButtonDown = false;
     self._strokeEnd(event);
     }
   };
   this._handleTouchStart = function (event) {
     if (event.targetTouches.length === 1) {
     var touch = event.changedTouches[0];
     self._strokeBegin(touch);
     }
   };
   this._handleTouchMove = function (event) {
     event.preventDefault();
     var touch = event.targetTouches[0];
     self._strokeUpdate(touch);
   };
   this._handleTouchEnd = function (event) {
     var wasCanvasTouched = event.target === self._canvas;
     if (wasCanvasTouched) {
     event.preventDefault();
     self._strokeEnd(event);
     }
   };
   this.on();
}
SignaturePad.prototype.clear = function () {
   var ctx = this._ctx;
   var canvas = this._canvas;
   ctx.fillStyle = this.backgroundColor;
   ctx.clearRect(0, 0, canvas.width, canvas.height);
   ctx.fillRect(0, 0, canvas.width, canvas.height);
   this._data = [];
   this._reset();
   this._isEmpty = true;
};
SignaturePad.prototype.fromDataURL = function (dataUrl) {
   var _this = this;
   var image = new Image();
   var ratio = window.devicePixelRatio || 1;
   var width = this._canvas.width / ratio;
   var height = this._canvas.height / ratio;
   this._reset();
   image.src = dataUrl;
   image.onload = function () {
   _this._ctx.drawImage(image, 0, 0, width, height);
   };
   this._isEmpty = false;
};
SignaturePad.prototype.toDataURL = function (type) {
   var _canvas;
   switch (type) {
   case 'image/svg+xml':
   return this._toSVG();
   default:
   for (var _len = arguments.length, options = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
     options[_key - 1] = arguments[_key];
   }
   return (_canvas = this._canvas).toDataURL.apply(_canvas, [type].concat(options));
   }
};
SignaturePad.prototype.on = function () {
   this._handleMouseEvents();
   this._handleTouchEvents();
};
SignaturePad.prototype.off = function () {
   this._canvas.removeEventListener('mousedown', this._handleMouseDown);
   this._canvas.removeEventListener('mousemove', this._handleMouseMove);
   document.removeEventListener('mouseup', this._handleMouseUp);
   this._canvas.removeEventListener('touchstart', this._handleTouchStart);
   this._canvas.removeEventListener('touchmove', this._handleTouchMove);
   this._canvas.removeEventListener('touchend', this._handleTouchEnd);
};
SignaturePad.prototype.isEmpty = function () {
   return this._isEmpty;
};
// Private methods
SignaturePad.prototype._strokeBegin = function (event) {
   this._data.push([]);
   this._reset();
   this._strokeUpdate(event);
   if (typeof this.onBegin === 'function') {
     this.onBegin(event);
   }
};
SignaturePad.prototype._strokeUpdate = function (event) {
   var x = event.clientX;
   var y = event.clientY;
   var point = this._createPoint(x, y);
   var _addPoint = this._addPoint(point),
   curve = _addPoint.curve,
   widths = _addPoint.widths;
   if (curve && widths) {
     this._drawCurve(curve, widths.start, widths.end);
   }
   this._data[this._data.length - 1].push({
     x: point.x,
     y: point.y,
     time: point.time
   });
};
SignaturePad.prototype._strokeEnd = function (event) {
   var canDrawCurve = this.points.length > 2;
   var point = this.points[0];
   if (!canDrawCurve && point) {
     this._drawDot(point);
   }
   if (typeof this.onEnd === 'function') {
     this.onEnd(event);
   }
};
SignaturePad.prototype._handleMouseEvents = function () {
   this._mouseButtonDown = false;
   this._canvas.addEventListener('mousedown', this._handleMouseDown);
   this._canvas.addEventListener('mousemove', this._handleMouseMove);
   document.addEventListener('mouseup', this._handleMouseUp);
};
SignaturePad.prototype._handleTouchEvents = function () {
   this._canvas.style.msTouchAction = 'none';
   this._canvas.style.touchAction = 'none';
   this._canvas.addEventListener('touchstart', this._handleTouchStart);
   this._canvas.addEventListener('touchmove', this._handleTouchMove);
   this._canvas.addEventListener('touchend', this._handleTouchEnd);
};
SignaturePad.prototype._reset = function () {
   this.points = [];
   this._lastVelocity = 0;
   this._lastWidth = (this.minWidth + this.maxWidth) / 2;
   this._ctx.fillStyle = this.penColor;
};
SignaturePad.prototype._createPoint = function (x, y, time) {
   var rect = this._canvas.getBoundingClientRect();
   return new Point(x - rect.left, y - rect.top, time || new Date().getTime());
};
SignaturePad.prototype._addPoint = function (point) {
   var points = this.points;
   var tmp = void 0;
   points.push(point);
   if (points.length > 2) {
     if (points.length === 3) points.unshift(points[0]);
     tmp = this._calculateCurveControlPoints(points[0], points[1], points[2]);
     var c2 = tmp.c2;
     tmp = this._calculateCurveControlPoints(points[1], points[2], points[3]);
     var c3 = tmp.c1;
     var curve = new Bezier(points[1], c2, c3, points[2]);
     var widths = this._calculateCurveWidths(curve);
     points.shift();
     return { curve: curve, widths: widths };
   }
   return {};
};
SignaturePad.prototype._calculateCurveControlPoints = function (s1, s2, s3) {
   var dx1 = s1.x - s2.x;
   var dy1 = s1.y - s2.y;
   var dx2 = s2.x - s3.x;
   var dy2 = s2.y - s3.y;
   var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
   var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
   var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
   var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
   var dxm = m1.x - m2.x;
   var dym = m1.y - m2.y;
   var k = l2 / (l1 + l2);
   var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
   var tx = s2.x - cm.x;
   var ty = s2.y - cm.y;
   return {
   c1: new Point(m1.x + tx, m1.y + ty),
   c2: new Point(m2.x + tx, m2.y + ty)
   };
};
SignaturePad.prototype._calculateCurveWidths = function (curve) {
   var startPoint = curve.startPoint;
   var endPoint = curve.endPoint;
   var widths = { start: null, end: null };
   var velocity = this.velocityFilterWeight * endPoint.velocityFrom(startPoint) + (1 - this.velocityFilterWeight) * this._lastVelocity;
   var newWidth = this._strokeWidth(velocity);
   widths.start = this._lastWidth;
   widths.end = newWidth;
   this._lastVelocity = velocity;
   this._lastWidth = newWidth;
   return widths;
};
SignaturePad.prototype._strokeWidth = function (velocity) {
   return Math.max(this.maxWidth / (velocity + 1), this.minWidth);
};
SignaturePad.prototype._drawPoint = function (x, y, size) {
   var ctx = this._ctx;
   ctx.moveTo(x, y);
   ctx.arc(x, y, size, 0, 2 * Math.PI, false);
   this._isEmpty = false;
};
SignaturePad.prototype._drawCurve = function (curve, startWidth, endWidth) {
   var ctx = this._ctx;
   var widthDelta = endWidth - startWidth;
   var drawSteps = Math.floor(curve.length());
   ctx.beginPath();
   for (var i = 0; i < drawSteps; i += 1) {
     var t = i / drawSteps;
     var tt = t * t;
     var ttt = tt * t;
     var u = 1 - t;
     var uu = u * u;
     var uuu = uu * u;
     var x = uuu * curve.startPoint.x;
     x += 3 * uu * t * curve.control1.x;
     x += 3 * u * tt * curve.control2.x;
     x += ttt * curve.endPoint.x;
     var y = uuu * curve.startPoint.y;
     y += 3 * uu * t * curve.control1.y;
     y += 3 * u * tt * curve.control2.y;
     y += ttt * curve.endPoint.y;
     var width = startWidth + ttt * widthDelta;
     this._drawPoint(x, y, width);
   }
   ctx.closePath();
   ctx.fill();
};
SignaturePad.prototype._drawDot = function (point) {
   var ctx = this._ctx;
   var width = typeof this.dotSize === 'function' ? this.dotSize() : this.dotSize;
   ctx.beginPath();
   this._drawPoint(point.x, point.y, width);
   ctx.closePath();
   ctx.fill();
};
SignaturePad.prototype._fromData = function (pointGroups, drawCurve, drawDot) {
   for (var i = 0; i < pointGroups.length; i += 1) {
     var group = pointGroups[i];
     if (group.length > 1) {
     for (var j = 0; j < group.length; j += 1) {
     var rawPoint = group[j];
     var point = new Point(rawPoint.x, rawPoint.y, rawPoint.time);
     if (j === 0) {
     this._reset();
     this._addPoint(point);
     } else if (j !== group.length - 1) {
     var _addPoint2 = this._addPoint(point),
     curve = _addPoint2.curve,
     widths = _addPoint2.widths;
     if (curve && widths) {
     drawCurve(curve, widths);
     }
     } else {
     }
     }
     } else {
     this._reset();
     var _rawPoint = group[0];
     drawDot(_rawPoint);
     }
   }
};
SignaturePad.prototype._toSVG = function () {
   var _this2 = this;
   var pointGroups = this._data;
   var canvas = this._canvas;
   var minX = 0;
   var minY = 0;
   var maxX = canvas.width;
   var maxY = canvas.height;
   var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
   svg.setAttributeNS(null, 'width', canvas.width);
   svg.setAttributeNS(null, 'height', canvas.height);
   this._fromData(pointGroups, function (curve, widths) {
     var path = document.createElement('path');
     if (!isNaN(curve.control1.x) && !isNaN(curve.control1.y) && !isNaN(curve.control2.x) && !isNaN(curve.control2.y)) {
     var attr = 'M ' + curve.startPoint.x.toFixed(3) + ',' + curve.startPoint.y.toFixed(3) + ' ' + ('C ' + curve.control1.x.toFixed(3) + ',' + curve.control1.y.toFixed(3) + ' ') + (curve.control2.x.toFixed(3) + ',' + curve.control2.y.toFixed(3) + ' ') + (curve.endPoint.x.toFixed(3) + ',' + curve.endPoint.y.toFixed(3));
     path.setAttribute('d', attr);
     path.setAttribute('stroke-width', (widths.end * 2.25).toFixed(3));
     path.setAttribute('stroke', _this2.penColor);
     path.setAttribute('fill', 'none');
     path.setAttribute('stroke-linecap', 'round');
     svg.appendChild(path);
     }
   }, function (rawPoint) {
     var circle = document.createElement('circle');
     var dotSize = typeof _this2.dotSize === 'function' ? _this2.dotSize() : _this2.dotSize;
     circle.setAttribute('r', dotSize);
     circle.setAttribute('cx', rawPoint.x);
     circle.setAttribute('cy', rawPoint.y);
     circle.setAttribute('fill', _this2.penColor);
     svg.appendChild(circle);
   });
   var prefix = 'data:image/svg+xml;base64,';
   var header = '<svg' + ' xmlns="http://www.w3.org/2000/svg"' + ' xmlns:xlink="http://www.w3.org/1999/xlink"' + (' viewBox="' + minX + ' ' + minY + ' ' + maxX + ' ' + maxY + '"') + (' width="' + maxX + '"') + (' height="' + maxY + '"') + '>';
   var body = svg.innerHTML;
   if (body === undefined) {
   var dummy = document.createElement('dummy');
   var nodes = svg.childNodes;
   dummy.innerHTML = '';
   for (var i = 0; i < nodes.length; i += 1) {
     dummy.appendChild(nodes[i].cloneNode(true));
   }
   body = dummy.innerHTML;
   }
   var footer = '</svg>';
   var data = header + body + footer;
   return prefix + btoa(data);
};
SignaturePad.prototype.fromData = function (pointGroups) {
   var _this3 = this;
   this.clear();
   this._fromData(pointGroups, function (curve, widths) {
   return _this3._drawCurve(curve, widths.start, widths.end);
   }, function (rawPoint) {
   return _this3._drawDot(rawPoint);
   });
};
SignaturePad.prototype.toData = function () {
   return this._data;
};
return SignaturePad;
})));

Halaman process.php

Halaman process.php adalah halaman untuk menyimpan data teks yang dikirimkan pada halaman index.php. Data teks tersebut sebenarnya adalah gambar namun dalam bentuk teks format base64 encoded. Jika ingin menyimpannya langsung pada database, itu bukanlah suatu masalah. Karena untuk menampilkan gambar aslinya cukuplah mudah. Yaitu dengan menuliskan data teks yang dikirimkan tersebut pada atribut src tag <img>. Dan saat halaman diload, maka gambar aslinya akan muncul.

Namun di sini, saya akan menyimpannya dalam bentuk file gambar format PNG. Proses nya cukup sederhana, yaitu dengan menggunakan file_get_contents() dengan isian data teks yang dikirim dari halaman index.php. Kemudian untuk mengkonversi ke dalam format PNG menggunakan fungsi file_put_contents().

Berikut halaman process.php :

PHP

1
2
3
4
5
6
7
8
9
<?php
   $sig_string=$_POST['signature'];
   $nama_file="signature_".date("his").".png";
   file_put_contents($nama_file, file_get_contents($sig_string));
   if(file_exists($nama_file)){
     echo "<p>File Signature berhasil disimpan - ".$nama_file."</p>";
     echo "<p style='border:solid 1px teal;width:355px;height:110px;'><img src='".$nama_file."'></p>";
   }
?>

Pengujian Hasil Output

Pengujian hasil output dilakukan untuk memastikan tidak terjadi kesalahan. Hasil output yang diharapkan adalah dalam bentuk file gambar dengan format PNG.

Saat halaman index.php ditampilkan :

tanda tangan digital (digital signature) html

Saat pengguna menuliskan tanda tangan pada layar yang disediakan :

tanda tangan digital (digital signature) html

Saat pengguna menekan tombol Save as PNG, gambar format png berhasil disimpan :

tanda tangan digital (digital signature) html

Tampilan pada File Manager terlihat file signature berhasil dibuat :

tanda tangan digital (digital signature) html

Source Code

Silahkan download source code beserta file pendukung pada tutorial ini.

Demikian tutorial bagaimana cara membuat tanda tangan digital (digital signature) dan menyimpannya dalam format gambar. Semoga bermanfaat.

   0   650

Kategori : tag iconhtml - tag iconjavascript - tag iconphp - tag icontech - tag iconbootstrap

facebooktwitterwhatapplinkedinpinterest

previous Previous Page

Tinggalkan Balasan

Nama Pengguna* :

Email* :

 

Mengirim Komentar

Setiap pengunjung situs ini dapat memposting komentar disini, namun tidak semua komentar dapat ditampilkan. Gunakan kalimat baku bahasa Indonesia yang mudah dimengerti. Dilarang memposting kalimat yang berisi ujaran kebencian, SARA, pornografi, perjudian dan spam. Komentar harus sesuai dengan topik. Untuk bahasan lainnya yang lebih mendalam dapat menggunakan sarana forum. Anda dapat mengirimkan suatu pertanyaan dan member lainnya akan menjawab pertanyaan Anda.
close

News Letters

Silahkan masukkan email Anda untuk berlangganan informasi kami

Polling

1. Apakah website ini menambah pengetahuan Anda?
 Ya
 Tidak
 Tidak Tahu
2. Seberapa sering Anda mengunjungi website ini?
 Sering
 Jarang
 Tidak Pernah
3. Apakah penilaian Anda terhadap website ini, jika melihat dari segi konten/isi?
 Sangat Bagus
 Bagus
 Cukup Bagus
 Kurang Bagus
4. Apakah penilaian Anda terhadap website ini, jika melihat dari segi tampilan?
 Sangat Bagus
 Bagus
 Cukup Bagus
 Kurang Bagus
5. Untuk meningkatkan kualitas website ini, Apakah saran Anda?

 


Visitor Live Chat

Silahkan anda memberikan masukkan chat (obrolan) pada fasilitas chat ini. Konten bebas, sopan dan menghargai pendapat orang lain..

 _Dicky (06 Mar 2021 at 03:24 pm)

Said : Oops, It's nice content

 rizky yuda (07 Mar 2021 at 12:30 pm)

Said : Konten cukup menambah wawasan...

 suryadi (13 Mar 2021 at 06:46 pm)

Said : Boleh request artikel cara koneksi database msyql ke php..

 Nettie Rutherfo (08 Apr 2021 at 12:30 pm)

Said : Auto

 Tedy (29 Mei 2021 at 12:09 pm)

Said : nice blog and articles..

 Ms. Doyle Mann (02 Jun 2021 at 09:56 pm)

Said : card

 flowrie_skylee (12 Jun 2021 at 01:24 pm)

Said : nice content

 Nelson Schaefer (12 Jul 2021 at 04:01 pm)

Said : JSON

 ooppp (18 Jul 2021 at 11:44 pm)

Said : 000popooppi

 Mrs. Jeff Boehm (01 Agt 2021 at 11:01 am)

Said : fuchsia

 dharma (07 Sept 2021 at 05:16 pm)

Said : ini support PHP 8?

 admin (12 Sept 2021 at 12:50 pm)

Said : #dharma masih dalam ruang lingkup PHP versi 7.
Namun untuk ke depannya akan dipertimbangkan agar support PHP 8, jika perubahan dari PHP 7 ke PHP 8 memang dirasa sangat signifikan.

 sadas (13 Jan 2022 at 09:48 am)

Said : Hello

 sutiyono (15 Jan 2022 at 09:36 am)

Said : konten cukup menarik.

 Fuad (08 Mar 2022 at 05:00 pm)

Said : Maksih bang kontennya, sangat membantu.

 admin (10 Mar 2022 at 12:18 pm)

Said : #Fuad Sama sama bang.. terima kasih sudah mampir di blog ini..

 Ferdian (09 Mei 2022 at 11:31 pm)

Said : bang bisa tolong buatkan contoh tamplate kirim email verifikasi gak?

 admin (10 Mei 2022 at 09:44 pm)

Said : Bang #Ferdian, artikelnya belum dibuat. Tapi ada kesamaan konsep yang dapat ditemukan pada halaman : Membuat Form Newsletters Interaktif Dengan Kode Verifikasi Dikirim Via Email,
Silahkan download source code dan file penunjangnya di sana. dan coba kembangkan untuk mengirimkan verifikasi via email untuk penggunaan yang lainnya.

 Abror (11 Jun 2022 at 09:08 am)

Said : Hallo min mau tanya kenapa script yang di konten teknik grabbing tidak bisa dibuka di laptop saya?

 admin (12 Jun 2022 at 12:11 am)

Said : #Abror stuck-nya dibagian mana bang? kalau localhost bisa aktifkan curl pada file php.ini dengan cara menghilangkan semicolon pada ;extension=php_curl.dll. Jika hosting online, dapat langsung dijalankan. cUrl dapat mengambil konten dan menampilkannya secara langsung pada halaman web.

 admin (12 Jun 2022 at 10:29 am)

Said : #Abror Silahkan akses artikel Menyalin konten suatu website teknik grabbing dengan native PHP, jika mengalami kesulitan dengan aktivasi cURL.. Terima kasih.

 SYAHRUL (23 Jun 2022 at 09:40 pm)

Said : oknull

 bang (26 Jun 2022 at 07:55 pm)

Said : bang caranya biar upload file dengan ekstensi tertentu di php gimana bang?

 admin (02 Jul 2022 at 11:34 am)

Said : #bang ??# Silahkan akses halaman Membatasi Upload File Dengan Format Tertentu Melalui Atribut HTML, Javascript Dan PHP. Pembatasan dapat dilakukan via HTML dengan menambahkan atribut accept, via javascipt dan juga via PHP script di sisi server.. have a nice day 😍😍 🤩..

 modas (04 Jul 2022 at 03:47 pm)

Said : halo

 Geoww (15 Agt 2022 at 11:45 pm)

Said : Tolog buat tutorial auto insert mysql, saat discaner kak, dan ditampilkan total yg m***k ke databasenya

Visitor Name
Email

 I'm not a robot