{"version":3,"sources":["jsdelivr-header.js","/gh/ColonelParrot/jscanify@master/src/jscanify.js"],"names":[],"mappings":"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","file":"/gh/ColonelParrot/jscanify@master/src/jscanify.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.37.0.\n * Original file: /gh/ColonelParrot/jscanify@master/src/jscanify.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","/*! jscanify v1.3.2 | (c) ColonelParrot and other contributors | MIT License */\n\n(function (global, factory) {\n  typeof exports === \"object\" && typeof module !== \"undefined\"\n    ? (module.exports = factory())\n    : typeof define === \"function\" && define.amd\n      ? define(factory)\n      : (global.jscanify = factory());\n})(this, function () {\n  \"use strict\";\n\n  /**\n   * Calculates distance between two points. Each point must have `x` and `y` property\n   * @param {*} p1 point 1\n   * @param {*} p2 point 2\n   * @returns distance between two points\n   */\n  function distance(p1, p2) {\n    return Math.hypot(p1.x - p2.x, p1.y - p2.y);\n  }\n\n  class jscanify {\n    constructor() { }\n\n    /**\n     * Finds the contour of the paper within the image\n     * @param {*} img image to process (cv.Mat)\n     * @returns the biggest contour inside the image\n     */\n    findPaperContour(img) {\n      const imgGray = new cv.Mat();\n      cv.Canny(img, imgGray, 50, 200);\n\n      const imgBlur = new cv.Mat();\n      cv.GaussianBlur(\n        imgGray,\n        imgBlur,\n        new cv.Size(3, 3),\n        0,\n        0,\n        cv.BORDER_DEFAULT\n      );\n\n      const imgThresh = new cv.Mat();\n      cv.threshold(\n        imgBlur,\n        imgThresh,\n        0,\n        255,\n        cv.THRESH_OTSU\n      );\n\n      let contours = new cv.MatVector();\n      let hierarchy = new cv.Mat();\n\n      cv.findContours(\n        imgThresh,\n        contours,\n        hierarchy,\n        cv.RETR_CCOMP,\n        cv.CHAIN_APPROX_SIMPLE\n      );\n\n      let maxArea = 0;\n      let maxContourIndex = -1;\n      for (let i = 0; i < contours.size(); ++i) {\n        let contourArea = cv.contourArea(contours.get(i));\n        if (contourArea > maxArea) {\n          maxArea = contourArea;\n          maxContourIndex = i;\n        }\n      }\n\n      const maxContour = contours.get(maxContourIndex);\n\n      imgGray.delete();\n      imgBlur.delete();\n      imgThresh.delete();\n      contours.delete();\n      hierarchy.delete();\n      return maxContour;\n    }\n\n    /**\n     * Highlights the paper detected inside the image.\n     * @param {*} image image to process\n     * @param {*} options options for highlighting. Accepts `color` and `thickness` parameter\n     * @returns `HTMLCanvasElement` with original image and paper highlighted\n     */\n    highlightPaper(image, options) {\n      options = options || {};\n      options.color = options.color || \"orange\";\n      options.thickness = options.thickness || 10;\n      const canvas = document.createElement(\"canvas\");\n      const ctx = canvas.getContext(\"2d\");\n      const img = cv.imread(image);\n\n      const maxContour = this.findPaperContour(img);\n      cv.imshow(canvas, img);\n      if (maxContour) {\n        const {\n          topLeftCorner,\n          topRightCorner,\n          bottomLeftCorner,\n          bottomRightCorner,\n        } = this.getCornerPoints(maxContour, img);\n\n        if (\n          topLeftCorner &&\n          topRightCorner &&\n          bottomLeftCorner &&\n          bottomRightCorner\n        ) {\n          ctx.strokeStyle = options.color;\n          ctx.lineWidth = options.thickness;\n          ctx.beginPath();\n          ctx.moveTo(...Object.values(topLeftCorner));\n          ctx.lineTo(...Object.values(topRightCorner));\n          ctx.lineTo(...Object.values(bottomRightCorner));\n          ctx.lineTo(...Object.values(bottomLeftCorner));\n          ctx.lineTo(...Object.values(topLeftCorner));\n          ctx.stroke();\n        }\n      }\n\n      img.delete();\n      return canvas;\n    }\n\n    /**\n     * Extracts and undistorts the image detected within the frame.\n     * @param {*} image image to process\n     * @param {*} resultWidth desired result paper width\n     * @param {*} resultHeight desired result paper height\n     * @param {*} cornerPoints optional custom corner points, in case automatic corner points are incorrect\n     * @returns `HTMLCanvasElement` containing undistorted image\n     */\n    extractPaper(image, resultWidth, resultHeight, cornerPoints) {\n      const canvas = document.createElement(\"canvas\");\n\n      const img = cv.imread(image);\n\n      const maxContour = this.findPaperContour(img);\n\n      const {\n        topLeftCorner,\n        topRightCorner,\n        bottomLeftCorner,\n        bottomRightCorner,\n      } = cornerPoints || this.getCornerPoints(maxContour, img);\n      let warpedDst = new cv.Mat();\n\n      let dsize = new cv.Size(resultWidth, resultHeight);\n      let srcTri = cv.matFromArray(4, 1, cv.CV_32FC2, [\n        topLeftCorner.x,\n        topLeftCorner.y,\n        topRightCorner.x,\n        topRightCorner.y,\n        bottomLeftCorner.x,\n        bottomLeftCorner.y,\n        bottomRightCorner.x,\n        bottomRightCorner.y,\n      ]);\n\n      let dstTri = cv.matFromArray(4, 1, cv.CV_32FC2, [\n        0,\n        0,\n        resultWidth,\n        0,\n        0,\n        resultHeight,\n        resultWidth,\n        resultHeight,\n      ]);\n\n      let M = cv.getPerspectiveTransform(srcTri, dstTri);\n      cv.warpPerspective(\n        img,\n        warpedDst,\n        M,\n        dsize,\n        cv.INTER_LINEAR,\n        cv.BORDER_CONSTANT,\n        new cv.Scalar()\n      );\n\n      cv.imshow(canvas, warpedDst);\n\n      img.delete()\n      warpedDst.delete()\n      return canvas;\n    }\n\n    /**\n     * Calculates the corner points of a contour.\n     * @param {*} contour contour from {@link findPaperContour}\n     * @returns object with properties `topLeftCorner`, `topRightCorner`, `bottomLeftCorner`, `bottomRightCorner`, each with `x` and `y` property\n     */\n    getCornerPoints(contour) {\n      let rect = cv.minAreaRect(contour);\n      const center = rect.center;\n\n      let topLeftCorner;\n      let topLeftCornerDist = 0;\n\n      let topRightCorner;\n      let topRightCornerDist = 0;\n\n      let bottomLeftCorner;\n      let bottomLeftCornerDist = 0;\n\n      let bottomRightCorner;\n      let bottomRightCornerDist = 0;\n\n      for (let i = 0; i < contour.data32S.length; i += 2) {\n        const point = { x: contour.data32S[i], y: contour.data32S[i + 1] };\n        const dist = distance(point, center);\n        if (point.x < center.x && point.y < center.y) {\n          // top left\n          if (dist > topLeftCornerDist) {\n            topLeftCorner = point;\n            topLeftCornerDist = dist;\n          }\n        } else if (point.x > center.x && point.y < center.y) {\n          // top right\n          if (dist > topRightCornerDist) {\n            topRightCorner = point;\n            topRightCornerDist = dist;\n          }\n        } else if (point.x < center.x && point.y > center.y) {\n          // bottom left\n          if (dist > bottomLeftCornerDist) {\n            bottomLeftCorner = point;\n            bottomLeftCornerDist = dist;\n          }\n        } else if (point.x > center.x && point.y > center.y) {\n          // bottom right\n          if (dist > bottomRightCornerDist) {\n            bottomRightCorner = point;\n            bottomRightCornerDist = dist;\n          }\n        }\n      }\n\n      return {\n        topLeftCorner,\n        topRightCorner,\n        bottomLeftCorner,\n        bottomRightCorner,\n      };\n    }\n  }\n\n  return jscanify;\n});\n"]}