From 338be17938d4dd93d83692107330507f23bd1252 Mon Sep 17 00:00:00 2001 From: zadit biasa aja <75159257+insvrgent@users.noreply.github.com> Date: Mon, 30 Jun 2025 03:45:36 +0000 Subject: [PATCH] ok --- package-lock.json | 62 ++++++++---------------- package.json | 1 + src/KTPScanner.js | 33 +++++++++++-- src/PaginatedFormEditable.js | 94 ++++++++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 45 deletions(-) create mode 100644 src/PaginatedFormEditable.js diff --git a/package-lock.json b/package-lock.json index e6ea98a..5f7156d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "react-dom": "^19.1.0", "react-router-dom": "^7.6.2", "react-scripts": "5.0.1", + "resemblejs": "^5.0.0", "tesseract.js": "^6.0.1", "web-vitals": "^2.1.4" } @@ -2777,7 +2778,6 @@ "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", "optional": true, - "peer": true, "dependencies": { "detect-libc": "^2.0.0", "https-proxy-agent": "^5.0.0", @@ -4044,8 +4044,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "optional": true, - "peer": true + "optional": true }, "node_modules/accepts": { "version": "1.3.8", @@ -4283,8 +4282,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "optional": true, - "peer": true + "optional": true }, "node_modules/are-we-there-yet": { "version": "2.0.0", @@ -4292,7 +4290,6 @@ "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", "deprecated": "This package is no longer supported.", "optional": true, - "peer": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -5159,7 +5156,6 @@ "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", "hasInstallScript": true, "optional": true, - "peer": true, "dependencies": { "@mapbox/node-pre-gyp": "^1.0.0", "nan": "^2.17.0", @@ -5244,7 +5240,6 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "optional": true, - "peer": true, "engines": { "node": ">=10" } @@ -5417,7 +5412,6 @@ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "optional": true, - "peer": true, "bin": { "color-support": "bin.js" } @@ -5527,8 +5521,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "optional": true, - "peer": true + "optional": true }, "node_modules/content-disposition": { "version": "0.5.4", @@ -6082,7 +6075,6 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", "optional": true, - "peer": true, "dependencies": { "mimic-response": "^2.0.0" }, @@ -6171,8 +6163,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "optional": true, - "peer": true + "optional": true }, "node_modules/depd": { "version": "2.0.0", @@ -6204,7 +6195,6 @@ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", "optional": true, - "peer": true, "engines": { "node": ">=8" } @@ -7921,7 +7911,6 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "optional": true, - "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -7934,7 +7923,6 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "optional": true, - "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -7946,8 +7934,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true, - "peer": true + "optional": true }, "node_modules/fs-monkey": { "version": "1.0.6", @@ -8013,7 +8000,6 @@ "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "deprecated": "This package is no longer supported.", "optional": true, - "peer": true, "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.2", @@ -8351,8 +8337,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "optional": true, - "peer": true + "optional": true }, "node_modules/hasown": { "version": "2.0.2", @@ -10754,7 +10739,6 @@ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", "optional": true, - "peer": true, "engines": { "node": ">=8" }, @@ -10826,7 +10810,6 @@ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "optional": true, - "peer": true, "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -10840,7 +10823,6 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "optional": true, - "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -10852,8 +10834,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true, - "peer": true + "optional": true }, "node_modules/mkdirp": { "version": "0.5.6", @@ -10897,8 +10878,7 @@ "version": "2.22.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", "integrity": "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==", - "optional": true, - "peer": true + "optional": true }, "node_modules/nanoid": { "version": "3.3.11", @@ -11010,7 +10990,6 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", "optional": true, - "peer": true, "dependencies": { "abbrev": "1" }, @@ -11065,7 +11044,6 @@ "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "deprecated": "This package is no longer supported.", "optional": true, - "peer": true, "dependencies": { "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", @@ -13555,6 +13533,14 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, + "node_modules/resemblejs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resemblejs/-/resemblejs-5.0.0.tgz", + "integrity": "sha512-+B0eP9k9VDP/YhBbH+ZdYmHiotdtuc6blVI+h8wwkY2cOow+uiIpSmgkBBBtrEAL0D31/gR/AJPwDeX5TcwmIA==", + "optionalDependencies": { + "canvas": "2.11.2" + } + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -14119,8 +14105,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "optional": true, - "peer": true + "optional": true }, "node_modules/set-cookie-parser": { "version": "2.7.1", @@ -14296,15 +14281,13 @@ "url": "https://feross.org/support" } ], - "optional": true, - "peer": true + "optional": true }, "node_modules/simple-get": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", "optional": true, - "peer": true, "dependencies": { "decompress-response": "^4.2.0", "once": "^1.3.1", @@ -15167,7 +15150,6 @@ "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "optional": true, - "peer": true, "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -15185,7 +15167,6 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "optional": true, - "peer": true, "engines": { "node": ">=8" } @@ -15195,7 +15176,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "optional": true, - "peer": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -15207,8 +15187,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true, - "peer": true + "optional": true }, "node_modules/temp-dir": { "version": "2.0.0", @@ -16293,7 +16272,6 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "optional": true, - "peer": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } diff --git a/package.json b/package.json index 24a79c0..19f1efe 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "react-dom": "^19.1.0", "react-router-dom": "^7.6.2", "react-scripts": "5.0.1", + "resemblejs": "^5.0.0", "tesseract.js": "^6.0.1", "web-vitals": "^2.1.4" }, diff --git a/src/KTPScanner.js b/src/KTPScanner.js index 311e084..2edf6e5 100644 --- a/src/KTPScanner.js +++ b/src/KTPScanner.js @@ -1,7 +1,8 @@ import React, { useEffect, useRef, useState } from "react"; import Modal from "./Modal"; -import FormComponent from "./FormComponent"; +import PaginatedFormEditable from "./PaginatedFormEditable"; import pixelmatch from "pixelmatch"; +import Tesseract from "tesseract.js"; const STORAGE_KEY = "camera_canvas_gallery"; @@ -53,13 +54,23 @@ const CameraCanvas = () => { null, canvasA.width, canvasA.height, - { threshold: 0.6 } + { threshold: 0.5 } ); const similarity = diffPixels / (canvasA.width * canvasA.height); return similarity < 0.2; // you can adjust the threshold }; + const extractTextFromCanvas = async (canvas) => { + const dataUrl = canvas.toDataURL("image/png"); + + const result = await Tesseract.recognize(dataUrl, "ind", { + logger: (m) => console.log(m), // opsional: untuk melihat progress + }); + + return result.data.text; + }; + const rectRef = useRef({ x: 0, y: 0, @@ -232,7 +243,22 @@ const CameraCanvas = () => { ); const isSimilar = isImageSimilar(cropCanvas, sampleKtpCanvas); - setKTPdetected(isSimilar); + if (isSimilar) { + const extractedText = await extractTextFromCanvas(cropCanvas); + console.log("OCR Result:", extractedText); + + const lowercaseText = extractedText.toLowerCase(); + + if ( + lowercaseText.includes("provinsi") || + lowercaseText.includes("nik") || + lowercaseText.includes("kewarganegaraan") + ) { + setKTPdetected(true); + } else { + setKTPdetected(false); + } + } setLoading(false); // Continue to OCR etc... @@ -582,6 +608,7 @@ const CameraCanvas = () => { )} + {fileTemp && } { + if (!iso) return ""; + const date = new Date(iso); + return date.toISOString().split("T")[0]; // YYYY-MM-DD +}; + +const PaginatedFormEditable = ({ data }) => { + const [formData, setFormData] = useState(() => { + const flat = {}; + Object.entries(data[0]).forEach(([key, value]) => { + if (value && typeof value === "object" && "value" in value) { + flat[key] = formatDate(value.value); + } else { + flat[key] = value; + } + }); + return flat; + }); + + const fields = Object.keys(formData); + const fieldsPerPage = 3; + const [page, setPage] = useState(0); + const totalPages = Math.ceil(fields.length / fieldsPerPage); + + const handleChange = (key, newValue) => { + setFormData((prev) => ({ + ...prev, + [key]: newValue, + })); + }; + + const startIndex = page * fieldsPerPage; + const currentFields = fields.slice(startIndex, startIndex + fieldsPerPage); + + return ( +
+

Edit Form Data

+ + {currentFields.map((key) => ( +
+ + handleChange(key, e.target.value)} + style={{ + width: "100%", + padding: 8, + borderRadius: 5, + border: "1px solid #ddd", + }} + /> +
+ ))} + +
+ + + +
+
+ ); +}; + +export default PaginatedFormEditable;