From c3ad3a8ed07b6d6a53c20c4358b412e18a45993f Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 27 Aug 2019 21:38:39 +0900 Subject: [PATCH 001/201] Update dev dependencies. --- package-lock.json | 299 +++++++++++++++++++++++----------------------- 1 file changed, 150 insertions(+), 149 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7cd552f..cca7c80 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", "dev": true, "requires": { "@babel/highlight": "^7.0.0" @@ -25,21 +25,21 @@ } }, "@types/node": { - "version": "12.6.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.6.2.tgz", - "integrity": "sha512-gojym4tX0FWeV2gsW4Xmzo5wxGjXGm550oVUII7f7G5o4BV6c7DBdiG1RRQd+y1bvqRyYtPfMK85UM95vsapqQ==", + "version": "12.7.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.2.tgz", + "integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg==", "dev": true }, "acorn": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.0.tgz", - "integrity": "sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.0.0.tgz", + "integrity": "sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ==", "dev": true }, "acorn-jsx": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", - "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz", + "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==", "dev": true }, "ajv": { @@ -109,9 +109,9 @@ "dev": true }, "async-limiter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", "dev": true }, "balanced-match": { @@ -278,9 +278,9 @@ "dev": true }, "comment-parser": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-0.5.5.tgz", - "integrity": "sha512-oB3TinFT+PV3p8UwDQt71+HkG03+zwPwikDlKU6ZDmql6QX2zFlQ+G0GGSDqyJhdZi4PSlzFBm+YJ+ebOX3Vgw==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-0.6.2.tgz", + "integrity": "sha512-Wdms0Q8d4vvb2Yk72OwZjwNWtMklbC5Re7lD9cjCP/AG1fhocmc0TrxGBBAXPLy8fZQPrfHGgyygwI0lA7pbzA==", "dev": true }, "concat-map": { @@ -290,20 +290,20 @@ "dev": true }, "concurrently": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-4.1.1.tgz", - "integrity": "sha512-48+FE5RJ0qc8azwKv4keVQWlni1hZeSjcWr8shBelOBtBHcKj1aJFM9lHRiSc1x7lq416pkvsqfBMhSRja+Lhw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-4.1.2.tgz", + "integrity": "sha512-Kim9SFrNr2jd8/0yNYqDTFALzUX1tvimmwFWxmp/D4mRI+kbqIIwE2RkBDrxS2ic25O1UgQMI5AtBqdtX3ynYg==", "dev": true, "requires": { - "chalk": "^2.4.1", - "date-fns": "^1.23.0", - "lodash": "^4.17.10", + "chalk": "^2.4.2", + "date-fns": "^1.30.1", + "lodash": "^4.17.15", "read-pkg": "^4.0.1", - "rxjs": "^6.3.3", + "rxjs": "^6.5.2", "spawn-command": "^0.0.2-1", "supports-color": "^4.5.0", - "tree-kill": "^1.1.0", - "yargs": "^12.0.1" + "tree-kill": "^1.2.1", + "yargs": "^12.0.5" } }, "corser": { @@ -448,9 +448,9 @@ "dev": true }, "eslint": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.0.1.tgz", - "integrity": "sha512-DyQRaMmORQ+JsWShYsSg4OPTjY56u1nCjAmICrE8vLWqyLKxhFXOthwMj1SA8xwfrv0CofLNVnqbfyhwCkaO0w==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.2.2.tgz", + "integrity": "sha512-mf0elOkxHbdyGX1IJEUsNBzCDdyoUgljF3rRlgfyYh0pwGnreLc0jjD6ZuleOibjmnUWZLY2eXwSooeOgGJ2jw==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -459,64 +459,88 @@ "cross-spawn": "^6.0.5", "debug": "^4.0.1", "doctrine": "^3.0.0", - "eslint-scope": "^4.0.3", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^6.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.2", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.1", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^3.1.0", + "glob-parent": "^5.0.0", "globals": "^11.7.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.2.2", + "inquirer": "^6.4.1", "is-glob": "^4.0.0", "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.3.0", - "lodash": "^4.17.11", + "lodash": "^4.17.14", "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "optionator": "^0.8.2", "progress": "^2.0.0", "regexpp": "^2.0.1", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", "table": "^5.2.3", - "text-table": "^0.2.0" + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, "eslint-config-blueimp": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-blueimp/-/eslint-config-blueimp-1.3.0.tgz", - "integrity": "sha512-6JPmtGdIamQ1AN9X9ejR9pa5kY2aS8s1EJss4ZWj4jLcEmJEGdehQAxSI9H7kT6uUpKPbEx5g5QhpQqCASxwSA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-config-blueimp/-/eslint-config-blueimp-1.4.0.tgz", + "integrity": "sha512-OWTLOSmsjDglgNvKKtb0t3iRPpyzFvXszXJkSS1w5oqkgVmFaKiNeoU6qOyZF2Q78rIog77RgIhzyA387b+7qA==", "dev": true }, "eslint-config-prettier": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.0.0.tgz", - "integrity": "sha512-vDrcCFE3+2ixNT5H83g28bO/uYAwibJxerXPj+E7op4qzBCsAV36QfvdAyVOoNxKAH2Os/e01T/2x++V0LPukA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.1.0.tgz", + "integrity": "sha512-k9fny9sPjIBQ2ftFTesJV21Rg4R/7a7t7LCtZVrYQiHEp8Nnuk3EGaDmsKSAnsPj0BYcgB2zxzHa2NTkIxcOLg==", "dev": true, "requires": { "get-stdin": "^6.0.0" } }, "eslint-plugin-jsdoc": { - "version": "15.5.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-15.5.1.tgz", - "integrity": "sha512-ZE2UyTfikhkS9XatRo+UhTFJVrW0XIpK19XQdlFkgpq/BWcewRPYZdO1nJ3r5Z/o4oITfASCPZMArW9Wjhiukg==", + "version": "15.8.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-15.8.3.tgz", + "integrity": "sha512-p2O6SYetuSD5gWV04HHevIfp2WfimXReYwINuB4iC33hm1jrYoP+t2XbJtCBYvjhoRjjw8w4NfnyZKixte1fug==", "dev": true, "requires": { - "comment-parser": "^0.5.5", + "comment-parser": "^0.6.2", "debug": "^4.1.1", - "flat-map-polyfill": "^0.3.8", "jsdoctypeparser": "5.0.1", - "lodash": "^4.17.14", + "lodash": "^4.17.15", + "object.entries-ponyfill": "^1.0.1", "regextras": "^0.6.1" } }, @@ -530,9 +554,9 @@ } }, "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -540,29 +564,29 @@ } }, "eslint-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.0.tgz", - "integrity": "sha512-7ehnzPaP5IIEh1r1tkjuIrxqhNkzUJa9z3R92tLJdZIVdWaczEhr3EbhGtsMrVxi1KeR8qA7Off6SWc5WNQqyQ==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", + "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", "dev": true, "requires": { "eslint-visitor-keys": "^1.0.0" } }, "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", "dev": true }, "espree": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.0.0.tgz", - "integrity": "sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.1.tgz", + "integrity": "sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==", "dev": true, "requires": { - "acorn": "^6.0.7", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" + "acorn": "^7.0.0", + "acorn-jsx": "^5.0.2", + "eslint-visitor-keys": "^1.1.0" } }, "esprima": { @@ -590,15 +614,15 @@ } }, "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, "eventemitter3": { @@ -695,12 +719,6 @@ "write": "1.0.3" } }, - "flat-map-polyfill": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/flat-map-polyfill/-/flat-map-polyfill-0.3.8.tgz", - "integrity": "sha512-ZfmD5MnU7GglUEhiky9C7yEPaNq1/wh36RDohe+Xr3nJVdccwHbdTkFIYvetcdsoAckUKT51fuf44g7Ni5Doyg==", - "dev": true - }, "flatted": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", @@ -708,23 +726,12 @@ "dev": true }, "follow-redirects": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz", - "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.8.0.tgz", + "integrity": "sha512-eYyazyi+vwXZ6LfSQicvqFwaNEF5xTvnB/rpzRLuqwK45u7WbBEnQ/dDic66KD/A8IzTXFlj2ROAcaP0f2v4lg==", "dev": true, "requires": { - "debug": "^3.2.6" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } + "debug": "^4.1.1" } }, "fs.realpath": { @@ -791,24 +798,12 @@ } }, "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", + "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", "dev": true, "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } + "is-glob": "^4.0.1" } }, "globals": { @@ -818,9 +813,9 @@ "dev": true }, "graceful-fs": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", - "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", "dev": true }, "has-flag": { @@ -836,9 +831,9 @@ "dev": true }, "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz", + "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==", "dev": true }, "http-proxy": { @@ -932,9 +927,9 @@ "dev": true }, "inquirer": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.0.tgz", - "integrity": "sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", "dev": true, "requires": { "ansi-escapes": "^3.2.0", @@ -1147,9 +1142,9 @@ } }, "lodash": { - "version": "4.17.14", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", - "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==", + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, "loglevel": { @@ -1385,6 +1380,12 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, + "object.entries-ponyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.entries-ponyfill/-/object.entries-ponyfill-1.0.1.tgz", + "integrity": "sha1-Kavfd8v70mVm3RqiTp2I9lQz0lY=", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1485,9 +1486,9 @@ "dev": true }, "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -1527,12 +1528,6 @@ "json-parse-better-errors": "^1.0.1" } }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -1582,9 +1577,9 @@ } }, "portfinder": { - "version": "1.0.21", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.21.tgz", - "integrity": "sha512-ESabpDCzmBS3ekHbmpAIiESq3udRsCBGiBZLsC+HgBKv2ezb0R4oG+7RnYEVZ/ZCfhel5Tx3UzdNWA0Lox2QCA==", + "version": "1.0.23", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.23.tgz", + "integrity": "sha512-B729mL/uLklxtxuiJKfQ84WPxNw5a7Yhx3geQZdcA4GjNjZSTSSMMWyoennMVnTWSmAR0lMdzWYN0JLnHrg1KQ==", "dev": true, "requires": { "async": "^1.5.2", @@ -1788,9 +1783,9 @@ "dev": true }, "resolve": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", - "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -1863,9 +1858,9 @@ "dev": true }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, "set-blocking": { @@ -1994,9 +1989,9 @@ "dev": true }, "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", "dev": true }, "supports-color": { @@ -2017,13 +2012,13 @@ } }, "table": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.1.tgz", - "integrity": "sha512-E6CK1/pZe2N75rGZQotFOdmzWQ1AILtgYbMAbAjvms0S1l5IDB47zG3nCnFGB/w+7nB3vKofbLXCH7HPBo864w==", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", "dev": true, "requires": { - "ajv": "^6.9.1", - "lodash": "^4.17.11", + "ajv": "^6.10.2", + "lodash": "^4.17.14", "slice-ansi": "^2.1.0", "string-width": "^3.0.0" }, @@ -2146,6 +2141,12 @@ "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", "dev": true }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", From 1196b4ce3c56f01cacf90fc5527b324ecccdf3b0 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 27 Aug 2019 21:38:48 +0900 Subject: [PATCH 002/201] 2.24.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index cca7c80..d0bd2b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "blueimp-load-image", - "version": "2.23.0", + "version": "2.24.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 39e1643..6cbe3c6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blueimp-load-image", - "version": "2.23.0", + "version": "2.24.0", "title": "JavaScript Load Image", "description": "JavaScript Load Image is a library to load images provided as File or Blob objects or via URL. It returns an optionally scaled and/or cropped HTML img or canvas element. It also provides methods to parse image meta data to extract IPTC and Exif tags as well as embedded thumbnail images and to restore the complete image header after resizing.", "keywords": [ From 3a5535831e2029113f473588161013ba06a51877 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sat, 28 Sep 2019 20:47:00 +0900 Subject: [PATCH 003/201] Add GitHub NodeJS workflow. --- .github/workflows/nodejs.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/nodejs.yml diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 0000000..b15baf3 --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,26 @@ +name: Node CI + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [8.x, 10.x, 12.x] + + steps: + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: npm install, build, and test + run: | + npm install + npm run build --if-present + npm test + env: + CI: true From ead9b7e314cbc1eb4bdeb275d9067901d4de6e05 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sat, 28 Sep 2019 20:54:13 +0900 Subject: [PATCH 004/201] Remove obsolete travis config. --- .travis.yml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 878ef22..0000000 --- a/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -dist: trusty -addons: - chrome: stable -# Using sudo as workaround for -# https://github.com/shellscape/mocha-chrome/pull/21 -sudo: required -language: node_js -node_js: - - "stable" From ebf4cfa3b57dfe01a914fa9b35d1eb5581fd7a37 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 20 Oct 2019 15:34:00 +0900 Subject: [PATCH 005/201] Run workflow on push and pull_request. Format YAML with prettier. --- .github/workflows/nodejs.yml | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index b15baf3..89973ab 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -1,10 +1,9 @@ name: Node CI -on: [push] +on: [push, pull_request] jobs: build: - runs-on: ubuntu-latest strategy: @@ -12,15 +11,15 @@ jobs: node-version: [8.x, 10.x, 12.x] steps: - - uses: actions/checkout@v1 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: npm install, build, and test - run: | - npm install - npm run build --if-present - npm test - env: - CI: true + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: npm install, build, and test + run: | + npm install + npm run build --if-present + npm test + env: + CI: true From ae40880049220d8283abd880e3f95c53581548a0 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 3 Nov 2019 10:20:22 +0900 Subject: [PATCH 006/201] Add GitHub Sponsors config. --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..048b1cf --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [blueimp] From 3ed1e0a30da5f63cd7670d22788628776e9e501a Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sat, 21 Dec 2019 21:41:09 +0900 Subject: [PATCH 007/201] Update dev dependencies. --- package-lock.json | 521 +++++++++++++++++++++++++--------------------- 1 file changed, 289 insertions(+), 232 deletions(-) diff --git a/package-lock.json b/package-lock.json index d0bd2b9..39e7529 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,21 +25,21 @@ } }, "@types/node": { - "version": "12.7.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.2.tgz", - "integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg==", + "version": "12.12.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.21.tgz", + "integrity": "sha512-8sRGhbpU+ck1n0PGAUgVrWrWdjSW2aqNeyC15W88GRsMpSwzv6RJGlLhE7s2RhVSOdyDmxbqlWSeThq4/7xqlA==", "dev": true }, "acorn": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.0.0.tgz", - "integrity": "sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", "dev": true }, "acorn-jsx": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz", - "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", + "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", "dev": true }, "ajv": { @@ -55,10 +55,13 @@ } }, "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", + "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } }, "ansi-regex": { "version": "3.0.0", @@ -103,16 +106,13 @@ "dev": true }, "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "dev": true + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } }, "balanced-match": { "version": "1.0.0", @@ -120,6 +120,12 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "basic-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -190,26 +196,26 @@ "dev": true }, "chrome-launcher": { - "version": "0.10.7", - "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.10.7.tgz", - "integrity": "sha512-IoQLp64s2n8OQuvKZwt77CscVj3UlV2Dj7yZtd1EBMld9mSdGcsGy9fN5hd/r4vJuWZR09it78n1+A17gB+AIQ==", + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.11.2.tgz", + "integrity": "sha512-jx0kJDCXdB2ARcDMwNCtrf04oY1Up4rOmVu+fqJ5MTPOOIG8EhRcEU9NZfXZc6dMw9FU8o1r21PNp8V2M0zQ+g==", "dev": true, "requires": { "@types/node": "*", - "is-wsl": "^1.1.0", + "is-wsl": "^2.1.0", "lighthouse-logger": "^1.0.0", "mkdirp": "0.5.1", "rimraf": "^2.6.1" } }, "chrome-remote-interface": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.27.2.tgz", - "integrity": "sha512-pVLljQ29SAx8KIv5tSa9sIf8GrEsAZdPJoeWOmY3/nrIzFmE+EryNNHvDkddGod0cmAFTv+GmPG0uvzxi2NWsA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.28.1.tgz", + "integrity": "sha512-OnVjEOuZtPDImShaWSQPKPZMNnUnoZfLKhayeXUWOyqir3MT1OTqMzUDEnIVx1itPnsW7CiKgyNLLgvgdniJgQ==", "dev": true, "requires": { "commander": "2.11.x", - "ws": "^6.1.0" + "ws": "^7.2.0" } }, "chrome-unmirror": { @@ -219,12 +225,12 @@ "dev": true }, "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, "requires": { - "restore-cursor": "^2.0.0" + "restore-cursor": "^3.1.0" } }, "cli-width": { @@ -266,9 +272,9 @@ "dev": true }, "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true }, "commander": { @@ -418,15 +424,15 @@ } }, "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "requires": { "once": "^1.4.0" @@ -448,9 +454,9 @@ "dev": true }, "eslint": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.2.2.tgz", - "integrity": "sha512-mf0elOkxHbdyGX1IJEUsNBzCDdyoUgljF3rRlgfyYh0pwGnreLc0jjD6ZuleOibjmnUWZLY2eXwSooeOgGJ2jw==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -460,19 +466,19 @@ "debug": "^4.0.1", "doctrine": "^3.0.0", "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.2", + "eslint-utils": "^1.4.3", "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.1", + "espree": "^6.1.2", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^5.0.0", - "globals": "^11.7.0", + "globals": "^12.1.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.4.1", + "inquirer": "^7.0.0", "is-glob": "^4.0.0", "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", @@ -481,7 +487,7 @@ "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "optionator": "^0.8.2", + "optionator": "^0.8.3", "progress": "^2.0.0", "regexpp": "^2.0.1", "semver": "^6.1.2", @@ -522,32 +528,32 @@ "dev": true }, "eslint-config-prettier": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.1.0.tgz", - "integrity": "sha512-k9fny9sPjIBQ2ftFTesJV21Rg4R/7a7t7LCtZVrYQiHEp8Nnuk3EGaDmsKSAnsPj0BYcgB2zxzHa2NTkIxcOLg==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.7.0.tgz", + "integrity": "sha512-FamQVKM3jjUVwhG4hEMnbtsq7xOIDm+SY5iBPfR8gKsJoAB2IQnNF+bk1+8Fy44Nq7PPJaLvkRxILYdJWoguKQ==", "dev": true, "requires": { "get-stdin": "^6.0.0" } }, "eslint-plugin-jsdoc": { - "version": "15.8.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-15.8.3.tgz", - "integrity": "sha512-p2O6SYetuSD5gWV04HHevIfp2WfimXReYwINuB4iC33hm1jrYoP+t2XbJtCBYvjhoRjjw8w4NfnyZKixte1fug==", + "version": "15.12.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-15.12.2.tgz", + "integrity": "sha512-QHzPc3VKTEbTn369/HpqDjl/czv3fCei/bZg5NA5tu9Od10MfpTH4kc1xnRDobhQoDs3AMz9wuaI4coHWRzMQw==", "dev": true, "requires": { "comment-parser": "^0.6.2", "debug": "^4.1.1", - "jsdoctypeparser": "5.0.1", + "jsdoctypeparser": "^5.1.1", "lodash": "^4.17.15", "object.entries-ponyfill": "^1.0.1", "regextras": "^0.6.1" } }, "eslint-plugin-prettier": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.0.tgz", - "integrity": "sha512-XWX2yVuwVNLOUhQijAkXz+rMPPoCr7WFiAl8ig6I7Xn+pPVhDhzg4DxHpmbeb0iqjO9UronEA3Tb09ChnFVHHA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz", + "integrity": "sha512-GlolCC9y3XZfv3RQfwGew7NnuFDKsfI4lbvRK+PIIo23SFH+LemGs4cKwzAaRa+Mdb+lQO/STaIayno8T5sJJA==", "dev": true, "requires": { "prettier-linter-helpers": "^1.0.0" @@ -564,12 +570,12 @@ } }, "eslint-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", - "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.0.0" + "eslint-visitor-keys": "^1.1.0" } }, "eslint-visitor-keys": { @@ -579,13 +585,13 @@ "dev": true }, "espree": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.1.tgz", - "integrity": "sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", + "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", "dev": true, "requires": { - "acorn": "^7.0.0", - "acorn-jsx": "^5.0.2", + "acorn": "^7.1.0", + "acorn-jsx": "^5.1.0", "eslint-visitor-keys": "^1.1.0" } }, @@ -626,9 +632,9 @@ "dev": true }, "eventemitter3": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", "dev": true }, "execa": { @@ -670,9 +676,9 @@ "dev": true }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, "fast-levenshtein": { @@ -682,9 +688,9 @@ "dev": true }, "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", + "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", "dev": true, "requires": { "escape-string-regexp": "^1.0.5" @@ -726,12 +732,23 @@ "dev": true }, "follow-redirects": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.8.0.tgz", - "integrity": "sha512-eYyazyi+vwXZ6LfSQicvqFwaNEF5xTvnB/rpzRLuqwK45u7WbBEnQ/dDic66KD/A8IzTXFlj2ROAcaP0f2v4lg==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz", + "integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==", "dev": true, "requires": { - "debug": "^4.1.1" + "debug": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } } }, "fs.realpath": { @@ -784,9 +801,9 @@ } }, "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -798,24 +815,27 @@ } }, "glob-parent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", - "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", "dev": true, "requires": { "is-glob": "^4.0.1" } }, "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz", + "integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } }, "graceful-fs": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", - "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", "dev": true }, "has-flag": { @@ -831,36 +851,38 @@ "dev": true }, "hosted-git-info": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz", - "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==", + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", + "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", "dev": true }, "http-proxy": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", - "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", + "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", "dev": true, "requires": { - "eventemitter3": "^3.0.0", + "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", "requires-port": "^1.0.0" } }, "http-server": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.11.1.tgz", - "integrity": "sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.0.tgz", + "integrity": "sha512-imGLDSTT1BZ0QG1rBFnaZ6weK5jeisUnCxZQI1cpYTdz0luPUM5e3s+WU5zRWEkiI6DQxL2p54oeKrDlzO6bRw==", "dev": true, "requires": { - "colors": "1.0.3", - "corser": "~2.0.0", - "ecstatic": "^3.0.0", - "http-proxy": "^1.8.1", - "opener": "~1.4.0", - "optimist": "0.6.x", - "portfinder": "^1.0.13", - "union": "~0.4.3" + "basic-auth": "^1.0.3", + "colors": "^1.3.3", + "corser": "^2.0.1", + "ecstatic": "^3.3.2", + "http-proxy": "^1.17.0", + "opener": "^1.5.1", + "optimist": "~0.6.1", + "portfinder": "^1.0.20", + "secure-compare": "3.0.1", + "union": "~0.5.0" } }, "iconv-lite": { @@ -879,9 +901,9 @@ "dev": true }, "import-fresh": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", - "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -927,32 +949,60 @@ "dev": true }, "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.1.tgz", + "integrity": "sha512-V1FFQ3TIO15det8PijPLFR9M9baSlnRs9nL7zWu1MNVA2T9YVl9ZbrHJhYs7e9X8jeMZ3lr2JH/rdHFgNCBdYw==", "dev": true, "requires": { - "ansi-escapes": "^3.2.0", + "ansi-escapes": "^4.2.1", "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", + "cli-cursor": "^3.1.0", "cli-width": "^2.0.0", "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", "strip-ansi": "^5.1.0", "through": "^2.3.6" }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -960,6 +1010,14 @@ "dev": true, "requires": { "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } } } } @@ -1022,9 +1080,9 @@ "dev": true }, "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz", + "integrity": "sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog==", "dev": true }, "isexe": { @@ -1050,9 +1108,9 @@ } }, "jsdoctypeparser": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-5.0.1.tgz", - "integrity": "sha512-dYwcK6TKzvq+ZKtbp4sbQSW9JMo6s+4YFfUs5D/K7bZsn3s1NhEhZ+jmIPzby0HbkbECBe+hNPEa6a+E21o94w==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-5.1.1.tgz", + "integrity": "sha512-APGygIJrT5bbz5lsVt8vyLJC0miEbQf/z9ZBfTr4RYvdia8AhWMRlYgivvwHG5zKD/VW3d6qpChCy64hpQET3A==", "dev": true }, "json-parse-better-errors": { @@ -1148,9 +1206,9 @@ "dev": true }, "loglevel": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.3.tgz", - "integrity": "sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA==", + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.6.tgz", + "integrity": "sha512-Sgr5lbboAUBo3eXCSPL4/KoVz3ROKquOjcctxmHIt+vol2DrqTQe3SwkKKuYhEiWB5kYa13YyopJ69deJ1irzQ==", "dev": true }, "loud-rejection": { @@ -1276,14 +1334,14 @@ } }, "mocha-chrome": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mocha-chrome/-/mocha-chrome-2.0.0.tgz", - "integrity": "sha512-Kq6W9jdXY3C2PhNHtSrk3GnDuoAKN+DbgJKCLfXtc5cql8oHB8+rUYlq9t1c8in6vQ6/X432E/U8h0pV5QlAug==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/mocha-chrome/-/mocha-chrome-2.2.0.tgz", + "integrity": "sha512-RXP6Q2mlM2X+eO2Z8gribmiH4J9x5zu/JcTZ3deQSwiC5260BzizOc0eD1NWP3JuypGCKRwReicv4KCNIFtTZQ==", "dev": true, "requires": { "chalk": "^2.0.1", - "chrome-launcher": "^0.10.2", - "chrome-remote-interface": "^0.27.0", + "chrome-launcher": "^0.11.2", + "chrome-remote-interface": "^0.28.0", "chrome-unmirror": "^0.1.0", "debug": "^4.1.1", "deep-assign": "^3.0.0", @@ -1300,9 +1358,9 @@ "dev": true }, "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, "nanoassert": { @@ -1396,26 +1454,18 @@ } }, "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", "dev": true, "requires": { - "mimic-fn": "^1.0.0" - }, - "dependencies": { - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - } + "mimic-fn": "^2.1.0" } }, "opener": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz", - "integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz", + "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==", "dev": true }, "optimist": { @@ -1426,28 +1476,20 @@ "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - } } }, "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "dev": true, "requires": { "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", + "fast-levenshtein": "~2.0.6", "levn": "~0.3.0", "prelude-ls": "~1.1.2", "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "word-wrap": "~1.2.3" } }, "os-locale": { @@ -1577,30 +1619,24 @@ } }, "portfinder": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.23.tgz", - "integrity": "sha512-B729mL/uLklxtxuiJKfQ84WPxNw5a7Yhx3geQZdcA4GjNjZSTSSMMWyoennMVnTWSmAR0lMdzWYN0JLnHrg1KQ==", + "version": "1.0.25", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz", + "integrity": "sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==", "dev": true, "requires": { - "async": "^1.5.2", - "debug": "^2.2.0", - "mkdirp": "0.5.x" + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.1" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true } } }, @@ -1611,9 +1647,9 @@ "dev": true }, "prettier": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", - "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", "dev": true }, "prettier-linter-helpers": { @@ -1648,9 +1684,9 @@ "dev": true }, "qs": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz", - "integrity": "sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=", + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.1.tgz", + "integrity": "sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA==", "dev": true }, "quick-lru": { @@ -1783,9 +1819,9 @@ "dev": true }, "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.1.tgz", + "integrity": "sha512-fn5Wobh4cxbLzuHaE+nphztHy43/b++4M6SsGFC2gB8uYwf0C8LcarfCz1un7UTW8OFQg9iNjZ4xpcFVGebDPg==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -1815,12 +1851,12 @@ "dev": true }, "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, "requires": { - "onetime": "^2.0.0", + "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, @@ -1843,9 +1879,9 @@ } }, "rxjs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", - "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", "dev": true, "requires": { "tslib": "^1.9.0" @@ -1857,6 +1893,12 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=", + "dev": true + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -2029,6 +2071,12 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -2073,9 +2121,9 @@ } }, "tree-kill": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", - "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true }, "trim-newlines": { @@ -2099,31 +2147,37 @@ "prelude-ls": "~1.1.2" } }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, "uglify-js": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", - "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.2.tgz", + "integrity": "sha512-uhRwZcANNWVLrxLfNFEdltoPNhECUR3lc+UdJoG9CBpMcSnKyWA94tc3eAujB1GcMY5Uwq8ZMp4qWpxWYDQmaA==", "dev": true, "requires": { - "commander": "~2.20.0", + "commander": "~2.20.3", "source-map": "~0.6.1" }, "dependencies": { "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true } } }, "union": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/union/-/union-0.4.6.tgz", - "integrity": "sha1-GY+9rrolTniLDvy2MLwR8kopWeA=", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", "dev": true, "requires": { - "qs": "~2.3.3" + "qs": "^6.4.0" } }, "uri-js": { @@ -2172,10 +2226,16 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", "dev": true }, "wrap-ansi": { @@ -2241,13 +2301,10 @@ } }, "ws": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", - "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.1.tgz", + "integrity": "sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==", + "dev": true }, "y18n": { "version": "4.0.0", From 9326d2ae5bbfd7e9c9cb7e00264030756746d389 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sat, 21 Dec 2019 21:42:15 +0900 Subject: [PATCH 008/201] Check if blob argument is a Blob instance. --- js/load-image.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/load-image.js b/js/load-image.js index 0119c63..2e158f5 100644 --- a/js/load-image.js +++ b/js/load-image.js @@ -37,7 +37,7 @@ loadImage.fetchBlob( file, function(blob) { - if (blob) { + if (blob && loadImage.isInstanceOf('Blob', blob)) { // eslint-disable-next-line no-param-reassign file = blob url = loadImage.createObjectURL(file) From f1a1080b82247bb1bf6a255125a4832101368b8d Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sat, 21 Dec 2019 21:46:24 +0900 Subject: [PATCH 009/201] Add XHR2 fallback if fetch API is not available. This adds support to parse meta data for images loaded via URL for Internet Explorer 10+. --- js/load-image-fetch.js | 35 +++++++++++++++++++++++++++++++++-- test/test.js | 5 ++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/js/load-image-fetch.js b/js/load-image-fetch.js index 5dcd119..ab64665 100644 --- a/js/load-image-fetch.js +++ b/js/load-image-fetch.js @@ -28,7 +28,7 @@ if (typeof fetch !== 'undefined' && typeof Request !== 'undefined') { loadImage.fetchBlob = function(url, callback, options) { if (loadImage.hasMetaOption(options)) { - return fetch(new Request(url, options)) + fetch(new Request(url, options)) .then(function(response) { return response.blob() }) @@ -37,8 +37,39 @@ console.log(err) // eslint-disable-line no-console callback() }) + } else { + callback() + } + } + } else if ( + // Check for XHR2 support: + typeof XMLHttpRequest !== 'undefined' && + typeof ProgressEvent !== 'undefined' + ) { + loadImage.fetchBlob = function(url, callback, options) { + if (loadImage.hasMetaOption(options)) { + // eslint-disable-next-line no-param-reassign + options = options || {} + var req = new XMLHttpRequest() + req.open(options.method || 'GET', url) + if (options.headers) { + Object.keys(options.headers).forEach(function(key) { + req.setRequestHeader(key, options.headers[key]) + }) + } + req.withCredentials = options.credentials === 'include' + req.responseType = 'blob' + req.onload = function() { + callback(req.response) + } + req.onerror = req.onabort = req.ontimeout = function(e) { + console.log(e) // eslint-disable-line no-console + callback() + } + req.send(options.body) + } else { + callback() } - callback() } } }) diff --git a/test/test.js b/test/test.js index 09f4cb3..fc1d1a7 100644 --- a/test/test.js +++ b/test/test.js @@ -875,7 +875,10 @@ }) }) - if ('fetch' in window && 'Request' in window) { + if ( + ('fetch' in window && 'Request' in window) || + ('XMLHttpRequest' in window && 'ProgressEvent' in window) + ) { describe('Fetch', function() { it('Should fetch image URL as blob if meta option is true', function(done) { expect( From e9343c4a00d052cb9c0bfd2c04527ade1a800896 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sat, 21 Dec 2019 21:47:41 +0900 Subject: [PATCH 010/201] Add loading images via URL support to the demo. --- index.html | 8 ++++++- js/demo/demo.js | 58 +++++++++++++++++++++++++++++-------------------- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/index.html b/index.html index 2240e6e..3610e16 100644 --- a/index.html +++ b/index.html @@ -72,7 +72,13 @@

JavaScript Load Image Demo

  • © Sebastian Tschan
  • Select an image file

    -

    +

    + +

    +

    Or enter an image URL into the following field:

    +

    + +

    Or drag & drop an image file onto this webpage.

    Result

    Result

    diff --git a/js/demo/demo.js b/js/demo/demo.js index cd9b62d..6dc9fa3 100644 --- a/js/demo/demo.js +++ b/js/demo/demo.js @@ -29,12 +29,16 @@ $(function () { * @param {object} tags Tags object */ function displayTagData(node, tags) { - var table = node.find('table').empty() + var table = $('') var row = $('') var cell = $('') var prop for (prop in tags) { if (Object.prototype.hasOwnProperty.call(tags, prop)) { + if (typeof tags[prop] === 'object') { + displayTagData(node, tags[prop]) + continue + } table.append( row .clone() @@ -43,7 +47,7 @@ $(function () { ) } } - node.show() + node.append(table).show() } /** @@ -55,11 +59,15 @@ $(function () { */ function displayThumbnailImage(node, thumbnail, options) { if (thumbnail) { - thumbNode.empty() + var link = $('') + .attr('href', loadImage.createObjectURL(thumbnail)) + .attr('download', 'thumbnail.jpg') + .appendTo(node) loadImage( thumbnail, function (img) { - node.append(img).show() + link.append(img) + node.show() }, options ) @@ -136,9 +144,9 @@ $(function () { orientation: true, meta: true } - exifNode.hide() - iptcNode.hide() - thumbNode.hide() + exifNode.hide().find('table').remove() + iptcNode.hide().find('table').remove() + thumbNode.hide().empty() if (!loadImage(file, updateResults, options)) { result .children() diff --git a/js/load-image-exif-map.js b/js/load-image-exif-map.js index 68d90d3..9684ae8 100644 --- a/js/load-image-exif-map.js +++ b/js/load-image-exif-map.js @@ -28,15 +28,14 @@ })(function (loadImage) { 'use strict' - loadImage.ExifMap.prototype.tags = { + var ExifMapProto = loadImage.ExifMap.prototype + + ExifMapProto.tags = { // ================= // TIFF tags (IFD0): // ================= 0x0100: 'ImageWidth', 0x0101: 'ImageHeight', - 0x8769: 'ExifIFDPointer', - 0x8825: 'GPSInfoIFDPointer', - 0xa005: 'InteroperabilityIFDPointer', 0x0102: 'BitsPerSample', 0x0103: 'Compression', 0x0106: 'PhotometricInterpretation', @@ -65,116 +64,120 @@ 0x0131: 'Software', 0x013b: 'Artist', 0x8298: 'Copyright', - // ================== - // Exif Sub IFD tags: - // ================== - 0x9000: 'ExifVersion', // EXIF version - 0xa000: 'FlashpixVersion', // Flashpix format version - 0xa001: 'ColorSpace', // Color space information tag - 0xa002: 'PixelXDimension', // Valid width of meaningful image - 0xa003: 'PixelYDimension', // Valid height of meaningful image - 0xa500: 'Gamma', - 0x9101: 'ComponentsConfiguration', // Information about channels - 0x9102: 'CompressedBitsPerPixel', // Compressed bits per pixel - 0x927c: 'MakerNote', // Any desired information written by the manufacturer - 0x9286: 'UserComment', // Comments by user - 0xa004: 'RelatedSoundFile', // Name of related sound file - 0x9003: 'DateTimeOriginal', // Date and time when the original image was generated - 0x9004: 'DateTimeDigitized', // Date and time when the image was stored digitally - 0x9290: 'SubSecTime', // Fractions of seconds for DateTime - 0x9291: 'SubSecTimeOriginal', // Fractions of seconds for DateTimeOriginal - 0x9292: 'SubSecTimeDigitized', // Fractions of seconds for DateTimeDigitized - 0x829a: 'ExposureTime', // Exposure time (in seconds) - 0x829d: 'FNumber', - 0x8822: 'ExposureProgram', // Exposure program - 0x8824: 'SpectralSensitivity', // Spectral sensitivity - 0x8827: 'PhotographicSensitivity', // EXIF 2.3, ISOSpeedRatings in EXIF 2.2 - 0x8828: 'OECF', // Optoelectric conversion factor - 0x8830: 'SensitivityType', - 0x8831: 'StandardOutputSensitivity', - 0x8832: 'RecommendedExposureIndex', - 0x8833: 'ISOSpeed', - 0x8834: 'ISOSpeedLatitudeyyy', - 0x8835: 'ISOSpeedLatitudezzz', - 0x9201: 'ShutterSpeedValue', // Shutter speed - 0x9202: 'ApertureValue', // Lens aperture - 0x9203: 'BrightnessValue', // Value of brightness - 0x9204: 'ExposureBias', // Exposure bias - 0x9205: 'MaxApertureValue', // Smallest F number of lens - 0x9206: 'SubjectDistance', // Distance to subject in meters - 0x9207: 'MeteringMode', // Metering mode - 0x9208: 'LightSource', // Kind of light source - 0x9209: 'Flash', // Flash status - 0x9214: 'SubjectArea', // Location and area of main subject - 0x920a: 'FocalLength', // Focal length of the lens in mm - 0xa20b: 'FlashEnergy', // Strobe energy in BCPS - 0xa20c: 'SpatialFrequencyResponse', - 0xa20e: 'FocalPlaneXResolution', // Number of pixels in width direction per FPRUnit - 0xa20f: 'FocalPlaneYResolution', // Number of pixels in height direction per FPRUnit - 0xa210: 'FocalPlaneResolutionUnit', // Unit for measuring the focal plane resolution - 0xa214: 'SubjectLocation', // Location of subject in image - 0xa215: 'ExposureIndex', // Exposure index selected on camera - 0xa217: 'SensingMethod', // Image sensor type - 0xa300: 'FileSource', // Image source (3 == DSC) - 0xa301: 'SceneType', // Scene type (1 == directly photographed) - 0xa302: 'CFAPattern', // Color filter array geometric pattern - 0xa401: 'CustomRendered', // Special processing - 0xa402: 'ExposureMode', // Exposure mode - 0xa403: 'WhiteBalance', // 1 = auto white balance, 2 = manual - 0xa404: 'DigitalZoomRatio', // Digital zoom ratio - 0xa405: 'FocalLengthIn35mmFilm', - 0xa406: 'SceneCaptureType', // Type of scene - 0xa407: 'GainControl', // Degree of overall image gain adjustment - 0xa408: 'Contrast', // Direction of contrast processing applied by camera - 0xa409: 'Saturation', // Direction of saturation processing applied by camera - 0xa40a: 'Sharpness', // Direction of sharpness processing applied by camera - 0xa40b: 'DeviceSettingDescription', - 0xa40c: 'SubjectDistanceRange', // Distance to subject - 0xa420: 'ImageUniqueID', // Identifier assigned uniquely to each image - 0xa430: 'CameraOwnerName', - 0xa431: 'BodySerialNumber', - 0xa432: 'LensSpecification', - 0xa433: 'LensMake', - 0xa434: 'LensModel', - 0xa435: 'LensSerialNumber', - // ============== - // GPS Info tags: - // ============== - 0x0000: 'GPSVersionID', - 0x0001: 'GPSLatitudeRef', - 0x0002: 'GPSLatitude', - 0x0003: 'GPSLongitudeRef', - 0x0004: 'GPSLongitude', - 0x0005: 'GPSAltitudeRef', - 0x0006: 'GPSAltitude', - 0x0007: 'GPSTimeStamp', - 0x0008: 'GPSSatellites', - 0x0009: 'GPSStatus', - 0x000a: 'GPSMeasureMode', - 0x000b: 'GPSDOP', - 0x000c: 'GPSSpeedRef', - 0x000d: 'GPSSpeed', - 0x000e: 'GPSTrackRef', - 0x000f: 'GPSTrack', - 0x0010: 'GPSImgDirectionRef', - 0x0011: 'GPSImgDirection', - 0x0012: 'GPSMapDatum', - 0x0013: 'GPSDestLatitudeRef', - 0x0014: 'GPSDestLatitude', - 0x0015: 'GPSDestLongitudeRef', - 0x0016: 'GPSDestLongitude', - 0x0017: 'GPSDestBearingRef', - 0x0018: 'GPSDestBearing', - 0x0019: 'GPSDestDistanceRef', - 0x001a: 'GPSDestDistance', - 0x001b: 'GPSProcessingMethod', - 0x001c: 'GPSAreaInformation', - 0x001d: 'GPSDateStamp', - 0x001e: 'GPSDifferential', - 0x001f: 'GPSHPositioningError' + 0x8769: { + // ExifIFDPointer + 0x9000: 'ExifVersion', // EXIF version + 0xa000: 'FlashpixVersion', // Flashpix format version + 0xa001: 'ColorSpace', // Color space information tag + 0xa002: 'PixelXDimension', // Valid width of meaningful image + 0xa003: 'PixelYDimension', // Valid height of meaningful image + 0xa500: 'Gamma', + 0x9101: 'ComponentsConfiguration', // Information about channels + 0x9102: 'CompressedBitsPerPixel', // Compressed bits per pixel + 0x927c: 'MakerNote', // Any desired information written by the manufacturer + 0x9286: 'UserComment', // Comments by user + 0xa004: 'RelatedSoundFile', // Name of related sound file + 0x9003: 'DateTimeOriginal', // Date and time when the original image was generated + 0x9004: 'DateTimeDigitized', // Date and time when the image was stored digitally + 0x9290: 'SubSecTime', // Fractions of seconds for DateTime + 0x9291: 'SubSecTimeOriginal', // Fractions of seconds for DateTimeOriginal + 0x9292: 'SubSecTimeDigitized', // Fractions of seconds for DateTimeDigitized + 0x829a: 'ExposureTime', // Exposure time (in seconds) + 0x829d: 'FNumber', + 0x8822: 'ExposureProgram', // Exposure program + 0x8824: 'SpectralSensitivity', // Spectral sensitivity + 0x8827: 'PhotographicSensitivity', // EXIF 2.3, ISOSpeedRatings in EXIF 2.2 + 0x8828: 'OECF', // Optoelectric conversion factor + 0x8830: 'SensitivityType', + 0x8831: 'StandardOutputSensitivity', + 0x8832: 'RecommendedExposureIndex', + 0x8833: 'ISOSpeed', + 0x8834: 'ISOSpeedLatitudeyyy', + 0x8835: 'ISOSpeedLatitudezzz', + 0x9201: 'ShutterSpeedValue', // Shutter speed + 0x9202: 'ApertureValue', // Lens aperture + 0x9203: 'BrightnessValue', // Value of brightness + 0x9204: 'ExposureBias', // Exposure bias + 0x9205: 'MaxApertureValue', // Smallest F number of lens + 0x9206: 'SubjectDistance', // Distance to subject in meters + 0x9207: 'MeteringMode', // Metering mode + 0x9208: 'LightSource', // Kind of light source + 0x9209: 'Flash', // Flash status + 0x9214: 'SubjectArea', // Location and area of main subject + 0x920a: 'FocalLength', // Focal length of the lens in mm + 0xa20b: 'FlashEnergy', // Strobe energy in BCPS + 0xa20c: 'SpatialFrequencyResponse', + 0xa20e: 'FocalPlaneXResolution', // Number of pixels in width direction per FPRUnit + 0xa20f: 'FocalPlaneYResolution', // Number of pixels in height direction per FPRUnit + 0xa210: 'FocalPlaneResolutionUnit', // Unit for measuring the focal plane resolution + 0xa214: 'SubjectLocation', // Location of subject in image + 0xa215: 'ExposureIndex', // Exposure index selected on camera + 0xa217: 'SensingMethod', // Image sensor type + 0xa300: 'FileSource', // Image source (3 == DSC) + 0xa301: 'SceneType', // Scene type (1 == directly photographed) + 0xa302: 'CFAPattern', // Color filter array geometric pattern + 0xa401: 'CustomRendered', // Special processing + 0xa402: 'ExposureMode', // Exposure mode + 0xa403: 'WhiteBalance', // 1 = auto white balance, 2 = manual + 0xa404: 'DigitalZoomRatio', // Digital zoom ratio + 0xa405: 'FocalLengthIn35mmFilm', + 0xa406: 'SceneCaptureType', // Type of scene + 0xa407: 'GainControl', // Degree of overall image gain adjustment + 0xa408: 'Contrast', // Direction of contrast processing applied by camera + 0xa409: 'Saturation', // Direction of saturation processing applied by camera + 0xa40a: 'Sharpness', // Direction of sharpness processing applied by camera + 0xa40b: 'DeviceSettingDescription', + 0xa40c: 'SubjectDistanceRange', // Distance to subject + 0xa420: 'ImageUniqueID', // Identifier assigned uniquely to each image + 0xa430: 'CameraOwnerName', + 0xa431: 'BodySerialNumber', + 0xa432: 'LensSpecification', + 0xa433: 'LensMake', + 0xa434: 'LensModel', + 0xa435: 'LensSerialNumber' + }, + 0x8825: { + // GPSInfoIFDPointer + 0x0000: 'GPSVersionID', + 0x0001: 'GPSLatitudeRef', + 0x0002: 'GPSLatitude', + 0x0003: 'GPSLongitudeRef', + 0x0004: 'GPSLongitude', + 0x0005: 'GPSAltitudeRef', + 0x0006: 'GPSAltitude', + 0x0007: 'GPSTimeStamp', + 0x0008: 'GPSSatellites', + 0x0009: 'GPSStatus', + 0x000a: 'GPSMeasureMode', + 0x000b: 'GPSDOP', + 0x000c: 'GPSSpeedRef', + 0x000d: 'GPSSpeed', + 0x000e: 'GPSTrackRef', + 0x000f: 'GPSTrack', + 0x0010: 'GPSImgDirectionRef', + 0x0011: 'GPSImgDirection', + 0x0012: 'GPSMapDatum', + 0x0013: 'GPSDestLatitudeRef', + 0x0014: 'GPSDestLatitude', + 0x0015: 'GPSDestLongitudeRef', + 0x0016: 'GPSDestLongitude', + 0x0017: 'GPSDestBearingRef', + 0x0018: 'GPSDestBearing', + 0x0019: 'GPSDestDistanceRef', + 0x001a: 'GPSDestDistance', + 0x001b: 'GPSProcessingMethod', + 0x001c: 'GPSAreaInformation', + 0x001d: 'GPSDateStamp', + 0x001e: 'GPSDifferential', + 0x001f: 'GPSHPositioningError' + }, + 0xa005: { + // InteroperabilityIFDPointer + 0x0001: 'InteroperabilityIndex' + } } - loadImage.ExifMap.prototype.stringValues = { + ExifMapProto.stringValues = { ExposureProgram: { 0: 'Undefined', 1: 'Manual', @@ -321,9 +324,9 @@ } } - loadImage.ExifMap.prototype.getText = function (id) { - var value = this.get(id) - switch (id) { + ExifMapProto.getText = function (name) { + var value = this.get(name) + switch (name) { case 'LightSource': case 'Flash': case 'MeteringMode': @@ -340,7 +343,7 @@ case 'SubjectDistanceRange': case 'FileSource': case 'Orientation': - return this.stringValues[id][value] + return this.stringValues[name][value] case 'ExifVersion': case 'FlashpixVersion': if (!value) return @@ -348,10 +351,10 @@ case 'ComponentsConfiguration': if (!value) return return ( - this.stringValues[id][value[0]] + - this.stringValues[id][value[1]] + - this.stringValues[id][value[2]] + - this.stringValues[id][value[3]] + this.stringValues[name][value[0]] + + this.stringValues[name][value[1]] + + this.stringValues[name][value[2]] + + this.stringValues[name][value[3]] ) case 'GPSVersionID': if (!value) return @@ -359,30 +362,53 @@ } return String(value) } - ;(function (exifMapPrototype) { - var tags = exifMapPrototype.tags - var map = exifMapPrototype.map - var prop - // Map the tag names to tags: - for (prop in tags) { - if (Object.prototype.hasOwnProperty.call(tags, prop)) { - map[tags[prop]] = prop - } - } - })(loadImage.ExifMap.prototype) - loadImage.ExifMap.prototype.getAll = function () { + ExifMapProto.getAll = function () { var map = {} var prop - var id + var obj + var name for (prop in this) { if (Object.prototype.hasOwnProperty.call(this, prop)) { - id = this.tags[prop] - if (id) { - map[id] = this.getText(id) + obj = this[prop] + if (obj && obj.getAll) { + map[this.privateIFDs[prop].name] = obj.getAll() + } else { + name = this.tags[prop] + if (name) map[name] = this.getText(name) } } } return map } + + ExifMapProto.getName = function (tagCode) { + var name = this.tags[tagCode] + if (typeof name === 'object') return this.privateIFDs[tagCode].name + return name + } + + // Extend the map of tag names to tag codes: + ;(function () { + var tags = ExifMapProto.tags + var prop + var privateIFD + var subTags + // Map the tag names to tags: + for (prop in tags) { + if (Object.prototype.hasOwnProperty.call(tags, prop)) { + privateIFD = ExifMapProto.privateIFDs[prop] + if (privateIFD) { + subTags = tags[prop] + for (prop in subTags) { + if (Object.prototype.hasOwnProperty.call(subTags, prop)) { + privateIFD.map[subTags[prop]] = Number(prop) + } + } + } else { + ExifMapProto.map[tags[prop]] = Number(prop) + } + } + } + })() }) diff --git a/js/load-image-exif.js b/js/load-image-exif.js index 74c2632..7dff053 100644 --- a/js/load-image-exif.js +++ b/js/load-image-exif.js @@ -27,28 +27,67 @@ })(function (loadImage) { 'use strict' - loadImage.ExifMap = function () { - return this + /** + * Exif tag map + * + * @name ExifMap + * @class + * @param {number} tagCode Private IFD tag code + */ + function ExifMap(tagCode) { + if (tagCode) { + Object.defineProperty(this, 'map', { + value: this.privateIFDs[tagCode].map + }) + Object.defineProperty(this, 'tags', { + value: (this.tags && this.tags[tagCode]) || {} + }) + } } - loadImage.ExifMap.prototype.map = { + ExifMap.prototype.map = { Orientation: 0x0112, - Thumbnail: 0x0201 + Thumbnail: 0x0201, + Exif: 0x8769, + GPSInfo: 0x8825, + Interoperability: 0xa005 + } + + ExifMap.prototype.privateIFDs = { + 0x8769: { name: 'Exif', map: {} }, + 0x8825: { name: 'GPSInfo', map: {} }, + 0xa005: { name: 'Interoperability', map: {} } } - loadImage.ExifMap.prototype.get = function (id) { + /** + * Retrieves exif tag value + * + * @param {number|string} id Exif tag code or name + * @returns {object} Exif tag value + */ + ExifMap.prototype.get = function (id) { return this[id] || this[this.map[id]] } - loadImage.getExifThumbnail = function (dataView, offset, length) { + /** + * Returns the Exif Thumbnail data as Blob. + * + * @param {DataView} dataView Data view interface + * @param {number} offset Thumbnail data offset + * @param {number} length Thumbnail data length + * @returns {undefined|Blob} Returns the Thumbnail Blob or undefined + */ + function getExifThumbnail(dataView, offset, length) { if (!length || offset + length > dataView.byteLength) { console.log('Invalid Exif data: Invalid thumbnail data.') return } - return new Blob([dataView.buffer.slice(offset, offset + length)]) + return new Blob([dataView.buffer.slice(offset, offset + length)], { + type: 'image/jpeg' + }) } - loadImage.exifTagTypes = { + var ExifTagTypes = { // byte, 8-bit unsigned int: 1: { getValue: function (dataView, dataOffset) { @@ -107,9 +146,20 @@ } } // undefined, 8-bit byte, value depending on field: - loadImage.exifTagTypes[7] = loadImage.exifTagTypes[1] + ExifTagTypes[7] = ExifTagTypes[1] - loadImage.getExifValue = function ( + /** + * Returns Exif tag value. + * + * @param {DataView} dataView Data view interface + * @param {number} tiffOffset TIFF offset + * @param {number} offset Tag offset + * @param {number} type Tag type + * @param {number} length Tag length + * @param {boolean} littleEndian Little endian encoding + * @returns {object} Tag value + */ + function getExifValue( dataView, tiffOffset, offset, @@ -117,7 +167,7 @@ length, littleEndian ) { - var tagType = loadImage.exifTagTypes[type] + var tagType = ExifTagTypes[type] var tagSize var dataOffset var values @@ -166,33 +216,30 @@ return values } - loadImage.parseExifTag = function ( - dataView, - tiffOffset, - offset, - littleEndian - ) { - return { - number: dataView.getUint16(offset, littleEndian), - value: loadImage.getExifValue( - dataView, - tiffOffset, - offset, - dataView.getUint16(offset + 2, littleEndian), // tag type - dataView.getUint32(offset + 4, littleEndian), // tag length - littleEndian - ) - } - } - - loadImage.parseExifTags = function ( + /** + * Parses Exif tags. + * + * @param {DataView} dataView Data view interface + * @param {number} tiffOffset TIFF offset + * @param {number} dirOffset Directory offset + * @param {boolean} littleEndian Little endian encoding + * @param {ExifMap} tags Map to store parsed exif tags + * @param {ExifMap} tagOffsets Map to store parsed exif tag offsets + * @param {object} includeTags Map of tags to include + * @param {object} excludeTags Map of tags to exclude + * @returns {number} Next directory offset + */ + function parseExifTags( dataView, tiffOffset, dirOffset, littleEndian, - data + tags, + tagOffsets, + includeTags, + excludeTags ) { - var tagsNumber, dirEndOffset, i, tagOffset, tag + var tagsNumber, dirEndOffset, i, tagOffset, tagNumber, tagValue if (dirOffset + 6 > dataView.byteLength) { console.log('Invalid Exif data: Invalid directory offset.') return @@ -205,29 +252,80 @@ } for (i = 0; i < tagsNumber; i += 1) { tagOffset = dirOffset + 2 + 12 * i - tag = this.parseExifTag( + tagNumber = dataView.getUint16(tagOffset, littleEndian) + if (includeTags && !includeTags[tagNumber]) continue + if (excludeTags && excludeTags[tagNumber] === true) continue + tagValue = getExifValue( dataView, tiffOffset, tagOffset, - littleEndian, - data + dataView.getUint16(tagOffset + 2, littleEndian), // tag type + dataView.getUint32(tagOffset + 4, littleEndian), // tag length + littleEndian ) - data.exif[tag.number] = tag.value - if (data.exifOffsets) { - data.exifOffsets[tag.number] = tagOffset + tags[tagNumber] = tagValue + if (tagOffsets) { + tagOffsets[tagNumber] = tagOffset } } // Return the offset to the next directory: return dataView.getUint32(dirEndOffset, littleEndian) } + /** + * Parses Private IFD tags. + * + * @param {object} data Data object to store exif tags and offsets + * @param {number} tagCode Private IFD tag code + * @param {DataView} dataView Data view interface + * @param {number} tiffOffset TIFF offset + * @param {boolean} littleEndian Little endian encoding + * @param {object} includeTags Map of tags to include + * @param {object} excludeTags Map of tags to exclude + */ + function parseExifPrivateIFD( + data, + tagCode, + dataView, + tiffOffset, + littleEndian, + includeTags, + excludeTags + ) { + var dirOffset = data.exif[tagCode] + if (dirOffset) { + data.exif[tagCode] = new ExifMap(tagCode) + if (data.exifOffsets) { + data.exifOffsets[tagCode] = new ExifMap(tagCode) + } + parseExifTags( + dataView, + tiffOffset, + tiffOffset + dirOffset, + littleEndian, + data.exif[tagCode], + data.exifOffsets && data.exifOffsets[tagCode], + includeTags && includeTags[tagCode], + excludeTags && excludeTags[tagCode] + ) + } + } + loadImage.parseExifData = function (dataView, offset, length, data, options) { if (options.disableExif) { return } + var includeTags = options.includeExifTags + var excludeTags = options.excludeExifTags || { + 0x8769: { + // ExifIFDPointer + 0x927c: true // MakerNote + } + } var tiffOffset = offset + 10 var littleEndian var dirOffset + var privateIFDs // Check for the ASCII code for "Exif" (0x45786966): if (dataView.getUint32(offset + 4) !== 0x45786966) { // No Exif data, might be XMP data instead @@ -262,58 +360,56 @@ // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal: dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian) // Create the exif object to store the tags: - data.exif = new loadImage.ExifMap() + data.exif = new ExifMap() if (!options.disableExifOffsets) { - data.exifOffsets = new loadImage.ExifMap() + data.exifOffsets = new ExifMap() data.exifTiffOffset = tiffOffset data.exifLittleEndian = littleEndian } // Parse the tags of the main image directory and retrieve the // offset to the next directory, usually the thumbnail directory: - dirOffset = loadImage.parseExifTags( + dirOffset = parseExifTags( dataView, tiffOffset, tiffOffset + dirOffset, littleEndian, - data + data.exif, + data.exifOffsets, + includeTags, + excludeTags ) if (dirOffset && !options.disableExifThumbnail) { - dirOffset = loadImage.parseExifTags( + dirOffset = parseExifTags( dataView, tiffOffset, tiffOffset + dirOffset, littleEndian, - data + data.exif, + data.exifOffsets, + includeTags, + excludeTags ) // Check for JPEG Thumbnail offset: - if (data.exif[0x0201]) { - data.exif[0x0201] = loadImage.getExifThumbnail( + if (data.exif[0x0201] && data.exif[0x0202]) { + data.exif[0x0201] = getExifThumbnail( dataView, tiffOffset + data.exif[0x0201], data.exif[0x0202] // Thumbnail data length ) } } - // Check for Exif Sub IFD Pointer: - if (data.exif[0x8769] && !options.disableExifSub) { - loadImage.parseExifTags( - dataView, - tiffOffset, - tiffOffset + data.exif[0x8769], // directory offset - littleEndian, - data - ) - } - // Check for GPS Info IFD Pointer: - if (data.exif[0x8825] && !options.disableExifGps) { - loadImage.parseExifTags( + privateIFDs = Object.keys(data.exif.privateIFDs) + privateIFDs.forEach(function (tagCode) { + parseExifPrivateIFD( + data, + tagCode, dataView, tiffOffset, - tiffOffset + data.exif[0x8825], // directory offset littleEndian, - data + includeTags, + excludeTags ) - } + }) } // Registers the Exif parser for the APP1 JPEG meta data segment: @@ -332,16 +428,18 @@ loadImage.exifWriters[data.exif.map[id]](buffer, data, value) } + loadImage.ExifMap = ExifMap + // Adds the following properties to the parseMetaData callback data: - // * exif: The parsed Exif tags - // * exifOffsets: The parsed Exif tag offsets - // * exifTiffOffset: TIFF header offset (used for offset pointers) - // * exifLittleEndian: little endian order if true, big endian if false + // - exif: The parsed Exif tags + // - exifOffsets: The parsed Exif tag offsets + // - exifTiffOffset: TIFF header offset (used for offset pointers) + // - exifLittleEndian: little endian order if true, big endian if false // Adds the following options to the parseMetaData method: - // * disableExif: Disables Exif parsing. - // * disableExifThumbnail: Disables parsing of the Exif Thumbnail. - // * disableExifSub: Disables parsing of the Exif Sub IFD. - // * disableExifGps: Disables parsing of the Exif GPS Info IFD. - // * disableExifOffsets: Disables storing Exif tag offsets + // - disableExif: Disables Exif parsing when true. + // - disableExifThumbnail: Disables parsing of Thumbnail data when true. + // - disableExifOffsets: Disables storing Exif tag offsets when true. + // - includeExifTags: A map of Exif tags to include for parsing. + // - excludeExifTags: A map of Exif tags to exclude from parsing. }) diff --git a/js/load-image-iptc-map.js b/js/load-image-iptc-map.js index adffa21..165d17d 100644 --- a/js/load-image-iptc-map.js +++ b/js/load-image-iptc-map.js @@ -6,9 +6,8 @@ * Copyright 2018, Dave Bevan * * IPTC tags mapping based on - * https://github.com/jseidelin/exif-js * https://iptc.org/standards/photo-metadata - * http://www.iptc.org/std/IIM/4.1/specification/IIMV4.1.pdf + * https://exiftool.org/TagNames/IPTC.html * * Licensed under the MIT license: * https://opensource.org/licenses/MIT @@ -30,100 +29,141 @@ })(function (loadImage) { 'use strict' - loadImage.IptcMap.prototype.tags = { - // ========== - // IPTC tags: - // ========== - 0x03: 'ObjectType', - 0x04: 'ObjectAttribute', - 0x05: 'ObjectName', - 0x07: 'EditStatus', - 0x08: 'EditorialUpdate', - 0x0a: 'Urgency', - 0x0c: 'SubjectRef', - 0x0f: 'Category', - 0x14: 'SupplCategory', - 0x16: 'FixtureID', - 0x19: 'Keywords', - 0x1a: 'ContentLocCode', - 0x1b: 'ContentLocName', - 0x1e: 'ReleaseDate', - 0x23: 'ReleaseTime', - 0x25: 'ExpirationDate', - 0x26: 'ExpirationTime', - 0x28: 'SpecialInstructions', - 0x2a: 'ActionAdvised', - 0x2d: 'RefService', - 0x2f: 'RefDate', - 0x32: 'RefNumber', - 0x37: 'DateCreated', - 0x3c: 'TimeCreated', - 0x3e: 'DigitalCreationDate', - 0x3f: 'DigitalCreationTime', - 0x41: 'OriginatingProgram', - 0x46: 'ProgramVersion', - 0x4b: 'ObjectCycle', - 0x50: 'Byline', - 0x55: 'BylineTitle', - 0x5a: 'City', - 0x5c: 'Sublocation', - 0x5f: 'State', - 0x64: 'CountryCode', - 0x65: 'CountryName', - 0x67: 'OrigTransRef', - 0x69: 'Headline', - 0x6e: 'Credit', - 0x73: 'Source', - 0x74: 'CopyrightNotice', - 0x76: 'Contact', - 0x78: 'Caption', - 0x7a: 'WriterEditor', - 0x82: 'ImageType', - 0x83: 'ImageOrientation', - 0x87: 'LanguageID' + var IptcMapProto = loadImage.IptcMap.prototype - // We don't record these tags: - // - // 0x00: 'RecordVersion', - // 0x7d: 'RasterizedCaption', - // 0x96: 'AudioType', - // 0x97: 'AudioSamplingRate', - // 0x98: 'AudioSamplingRes', - // 0x99: 'AudioDuration', - // 0x9a: 'AudioOutcue', - // 0xc8: 'PreviewFileFormat', - // 0xc9: 'PreviewFileFormatVer', - // 0xca: 'PreviewData' + IptcMapProto.tags = { + 0: 'ApplicationRecordVersion', + 3: 'ObjectTypeReference', + 4: 'ObjectAttributeReference', + 5: 'ObjectName', + 7: 'EditStatus', + 8: 'EditorialUpdate', + 10: 'Urgency', + 12: 'SubjectReference', + 15: 'Category', + 20: 'SupplementalCategories', + 22: 'FixtureIdentifier', + 25: 'Keywords', + 26: 'ContentLocationCode', + 27: 'ContentLocationName', + 30: 'ReleaseDate', + 35: 'ReleaseTime', + 37: 'ExpirationDate', + 38: 'ExpirationTime', + 40: 'SpecialInstructions', + 42: 'ActionAdvised', + 45: 'ReferenceService', + 47: 'ReferenceDate', + 50: 'ReferenceNumber', + 55: 'DateCreated', + 60: 'TimeCreated', + 62: 'DigitalCreationDate', + 63: 'DigitalCreationTime', + 65: 'OriginatingProgram', + 70: 'ProgramVersion', + 75: 'ObjectCycle', + 80: 'Byline', + 85: 'BylineTitle', + 90: 'City', + 92: 'Sublocation', + 95: 'State', + 100: 'CountryCode', + 101: 'Country', + 103: 'OriginalTransmissionReference', + 105: 'Headline', + 110: 'Credit', + 115: 'Source', + 116: 'CopyrightNotice', + 118: 'Contact', + 120: 'Caption', + 121: 'LocalCaption', + 122: 'Writer', + 125: 'RasterizedCaption', + 130: 'ImageType', + 131: 'ImageOrientation', + 135: 'LanguageIdentifier', + 150: 'AudioType', + 151: 'AudioSamplingRate', + 152: 'AudioSamplingResolution', + 153: 'AudioDuration', + 154: 'AudioOutcue', + 184: 'JobID', + 185: 'MasterDocumentID', + 186: 'ShortDocumentID', + 187: 'UniqueDocumentID', + 188: 'OwnerID', + 200: 'ObjectPreviewFileFormat', + 201: 'ObjectPreviewFileVersion', + 202: 'ObjectPreviewData', + 221: 'Prefs', + 225: 'ClassifyState', + 228: 'SimilarityIndex', + 230: 'DocumentNotes', + 231: 'DocumentHistory', + 232: 'ExifCameraInfo', + 255: 'CatalogSets' } - loadImage.IptcMap.prototype.getText = function (id) { + IptcMapProto.stringValues = { + 10: { + 0: '0 (reserved)', + 1: '1 (most urgent)', + 2: '2', + 3: '3', + 4: '4', + 5: '5 (normal urgency)', + 6: '6', + 7: '7', + 8: '8 (least urgent)', + 9: '9 (user-defined priority)' + }, + 75: { + a: 'Morning', + b: 'Both Morning and Evening', + p: 'Evening' + }, + 131: { + L: 'Landscape', + P: 'Portrait', + S: 'Square' + } + } + + IptcMapProto.getText = function (id) { var value = this.get(id) + var tagCode = this.map[id] + var stringValue = this.stringValues[tagCode] + if (stringValue) return stringValue[value] return String(value) } - ;(function (iptcMapPrototype) { - var tags = iptcMapPrototype.tags - var map = iptcMapPrototype.map || {} - var prop - // Map the tag names to tags: - for (prop in tags) { - if (Object.prototype.hasOwnProperty.call(tags, prop)) { - map[tags[prop]] = prop - } - } - })(loadImage.IptcMap.prototype) - loadImage.IptcMap.prototype.getAll = function () { + IptcMapProto.getAll = function () { var map = {} var prop - var id + var name for (prop in this) { if (Object.prototype.hasOwnProperty.call(this, prop)) { - id = this.tags[prop] - if (id) { - map[id] = this.getText(id) - } + name = this.tags[prop] + if (name) map[name] = this.getText(name) } } return map } + + IptcMapProto.getName = function (tagCode) { + return this.tags[tagCode] + } + + // Extend the map of tag names to tag codes: + ;(function () { + var tags = IptcMapProto.tags + var map = IptcMapProto.map || {} + var prop + // Map the tag names to tags: + for (prop in tags) { + if (Object.prototype.hasOwnProperty.call(tags, prop)) { + map[tags[prop]] = Number(prop) + } + } + })() }) diff --git a/js/load-image-iptc.js b/js/load-image-iptc.js index c7ce7c1..9f6a900 100644 --- a/js/load-image-iptc.js +++ b/js/load-image-iptc.js @@ -10,7 +10,7 @@ * https://opensource.org/licenses/MIT */ -/* global define, module, require, Buffer */ +/* global define, module, require, DataView */ ;(function (factory) { 'use strict' @@ -26,128 +26,214 @@ })(function (loadImage) { 'use strict' - loadImage.IptcMap = function () { - return this + /** + * IPTC tag map + * + * @name IptcMap + * @class + */ + function IptcMap() {} + + IptcMap.prototype.map = { + ObjectName: 5 } - loadImage.IptcMap.prototype.map = { - ObjectName: 0x5 + IptcMap.prototype.types = { + 0: 'Uint16', // ApplicationRecordVersion + 200: 'Uint16', // ObjectPreviewFileFormat + 201: 'Uint16', // ObjectPreviewFileVersion + 202: 'binary' // ObjectPreviewData } - loadImage.IptcMap.prototype.get = function (id) { + /** + * Retrieves IPTC tag value + * + * @param {number|string} id IPTC tag code or name + * @returns {object} IPTC tag value + */ + IptcMap.prototype.get = function (id) { return this[id] || this[this.map[id]] } - loadImage.parseIptcTags = function ( + /** + * Retrieves string for the given DataView and range + * + * @param {DataView} dataView Data view interface + * @param {number} offset Offset start + * @param {number} length Offset length + * @returns {string} String value + */ + function getStringValue(dataView, offset, length) { + var outstr = '' + var end = offset + length + for (var n = offset; n < end; n += 1) { + outstr += String.fromCharCode(dataView.getUint8(n)) + } + return outstr + } + + /** + * Retrieves tag value for the given DataView and range + * + * @param {number} tagCode Private IFD tag code + * @param {IptcMap} map IPTC tag map + * @param {DataView} dataView Data view interface + * @param {number} offset Range start + * @param {number} length Range length + * @returns {object} Tag value + */ + function getTagValue(tagCode, map, dataView, offset, length) { + if (map.types[tagCode] === 'binary') { + return new Blob([dataView.buffer.slice(offset, offset + length)]) + } + if (map.types[tagCode] === 'Uint16') { + return dataView.getUint16(offset) + } + return getStringValue(dataView, offset, length) + } + + /** + * Combines IPTC value with existing ones. + * + * @param {object} value Existing IPTC field value + * @param {object} newValue New IPTC field value + * @returns {object} Resulting IPTC field value + */ + function combineTagValues(value, newValue) { + if (value === undefined) return newValue + if (value instanceof Array) { + value.push(newValue) + return value + } + return [value, newValue] + } + + /** + * Parses IPTC tags. + * + * @param {DataView} dataView Data view interface + * @param {number} segmentOffset Segment offset + * @param {number} segmentLength Segment length + * @param {object} data Data export object + * @param {object} includeTags Map of tags to include + * @param {object} excludeTags Map of tags to exclude + */ + function parseIptcTags( dataView, - startOffset, - sectionLength, - data + segmentOffset, + segmentLength, + data, + includeTags, + excludeTags ) { - /** - * Retrieves string for the given Buffer and range - * - * @param {Buffer} buffer IPTC buffer - * @param {number} start Range start - * @param {number} length Range length - * @returns {string} String value - */ - function getStringFromDB(buffer, start, length) { - var outstr = '' - for (var n = start; n < start + length; n++) { - outstr += String.fromCharCode(buffer.getUint8(n)) - } - return outstr - } - var fieldValue, dataSize, segmentType - var segmentStartPos = startOffset - while (segmentStartPos < startOffset + sectionLength) { - // we currently handle the 2: class of iptc tag + var value, tagSize, tagCode + var segmentEnd = segmentOffset + segmentLength + var offset = segmentOffset + while (offset < segmentEnd) { if ( - dataView.getUint8(segmentStartPos) === 0x1c && - dataView.getUint8(segmentStartPos + 1) === 0x02 + dataView.getUint8(offset) === 0x1c && // tag marker + dataView.getUint8(offset + 1) === 0x02 // record number, only handles v2 ) { - segmentType = dataView.getUint8(segmentStartPos + 2) - // only store data for known tags - if (segmentType in data.iptc.tags) { - dataSize = dataView.getInt16(segmentStartPos + 3) - fieldValue = getStringFromDB(dataView, segmentStartPos + 5, dataSize) - // Check if we already stored a value with this name - if (Object.prototype.hasOwnProperty.call(data.iptc, segmentType)) { - // Value already stored with this name, create multivalue field - if (data.iptc[segmentType] instanceof Array) { - data.iptc[segmentType].push(fieldValue) - } else { - data.iptc[segmentType] = [data.iptc[segmentType], fieldValue] - } - } else { - data.iptc[segmentType] = fieldValue + tagCode = dataView.getUint8(offset + 2) + if ( + (!includeTags || includeTags[tagCode]) && + (!excludeTags || !excludeTags[tagCode]) + ) { + tagSize = dataView.getInt16(offset + 3) + value = getTagValue(tagCode, data.iptc, dataView, offset + 5, tagSize) + data.iptc[tagCode] = combineTagValues(data.iptc[tagCode], value) + if (data.iptcOffsets) { + data.iptcOffsets[tagCode] = offset } } } - segmentStartPos++ + offset += 1 } } + /** + * Tests if field segment starts at offset. + * + * @param {DataView} dataView Data view interface + * @param {number} offset Segment offset + * @returns {boolean} True if '8BIM' exists at offset + */ + function isSegmentStart(dataView, offset) { + return ( + dataView.getUint32(offset) === 0x3842494d && // Photoshop segment start + dataView.getUint16(offset + 4) === 0x0404 // IPTC segment start + ) + } + + /** + * Returns header length. + * + * @param {DataView} dataView Data view interface + * @param {number} offset Segment offset + * @returns {number} Header length + */ + function getHeaderLength(dataView, offset) { + var length = dataView.getUint8(offset + 7) + if (length % 2 !== 0) length += 1 + // Check for pre photoshop 6 format + if (length === 0) { + // Always 4 + length = 4 + } + return length + } + loadImage.parseIptcData = function (dataView, offset, length, data, options) { if (options.disableIptc) { return } var markerLength = offset + length - // Found '8BIM' ? - var isFieldSegmentStart = function (dataView, offset) { - return ( - dataView.getUint32(offset) === 0x3842494d && - dataView.getUint16(offset + 4) === 0x0404 - ) - } - // Hunt forward, looking for the correct IPTC block signature: - // Reference: https://metacpan.org/pod/distribution/Image-MetaData-JPEG/lib/Image/MetaData/JPEG/Structures.pod#Structure-of-a-Photoshop-style-APP13-segment - // From https://github.com/exif-js/exif-js/blob/master/exif.js ~ line 474 on while (offset + 8 < markerLength) { - if (isFieldSegmentStart(dataView, offset)) { - var nameHeaderLength = dataView.getUint8(offset + 7) - if (nameHeaderLength % 2 !== 0) nameHeaderLength += 1 - // Check for pre photoshop 6 format - if (nameHeaderLength === 0) { - // Always 4 - nameHeaderLength = 4 - } - var startOffset = offset + 8 + nameHeaderLength - if (startOffset > markerLength) { + if (isSegmentStart(dataView, offset)) { + var headerLength = getHeaderLength(dataView, offset) + var segmentOffset = offset + 8 + headerLength + if (segmentOffset > markerLength) { // eslint-disable-next-line no-console console.log('Invalid IPTC data: Invalid segment offset.') break } - var sectionLength = dataView.getUint16(offset + 6 + nameHeaderLength) - if (offset + sectionLength > markerLength) { + var segmentLength = dataView.getUint16(offset + 6 + headerLength) + if (offset + segmentLength > markerLength) { // eslint-disable-next-line no-console console.log('Invalid IPTC data: Invalid segment size.') break } // Create the iptc object to store the tags: - data.iptc = new loadImage.IptcMap() - // Parse the tags - return loadImage.parseIptcTags( + data.iptc = new IptcMap() + if (!options.disableIptcOffsets) { + data.iptcOffsets = new IptcMap() + } + parseIptcTags( dataView, - startOffset, - sectionLength, - data + segmentOffset, + segmentLength, + data, + options.includeIptcTags, + options.excludeIptcTags || { 202: true } // ObjectPreviewData ) + return } // eslint-disable-next-line no-param-reassign - offset++ + offset += 1 } - // eslint-disable-next-line no-console - console.log('No IPTC data at this offset - could be XMP') } // Registers this IPTC parser for the APP13 JPEG meta data segment: loadImage.metaDataParsers.jpeg[0xffed].push(loadImage.parseIptcData) + loadImage.IptcMap = IptcMap + // Adds the following properties to the parseMetaData callback data: - // * iptc: The iptc tags, parsed by the parseIptcData method + // - iptc: The iptc tags, parsed by the parseIptcData method // Adds the following options to the parseMetaData method: - // * disableIptc: Disables IPTC parsing. + // - disableIptc: Disables IPTC parsing when true. + // - disableIptcOffsets: Disables storing IPTC tag offsets when true. + // - includeIptcTags: A map of IPTC tags to include for parsing. + // - excludeIptcTags: A map of IPTC tags to exclude from parsing. }) diff --git a/test/test.js b/test/test.js index e33843c..6f2b039 100644 --- a/test/test.js +++ b/test/test.js @@ -989,6 +989,17 @@ }) }) + it('Should not parse Exif tags if disabled', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.exif).to.be.undefined + done() + }, + { disableExif: true } + ) + }) + it('Should parse Exif tag offsets', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.exifOffsets).to.be.ok @@ -999,6 +1010,57 @@ }) }) + it('Should not parse Exif tag offsets if disabled', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.exifOffsets).to.be.undefined + done() + }, + { disableExifOffsets: true } + ) + }) + + it('Should only parse included Exif tags', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.exif).to.be.ok + expect(data.exif.get('Orientation')).to.equal(6) + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.exif).to.be.ok + expect(data.exif.get('Orientation')).to.be.undefined + done() + }, + { includeExifTags: { 0x0132: true } } // DateTime + ) + }, + { includeExifTags: { 0x0112: true } } // Orientation + ) + }) + + it('Should not parse excluded Exif tags', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.exif).to.be.ok + expect(data.exif.get('Orientation')).to.equal(6) + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.exif).to.be.ok + expect(data.exif.get('Orientation')).to.be.undefined + done() + }, + { excludeExifTags: { 0x0112: true } } // Orientation + ) + }, + { excludeExifTags: { 0x0132: true } } // DateTime + ) + }) + it('Should parse IPTC tags', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.iptc).to.be.ok @@ -1007,6 +1069,80 @@ }) }) + it('Should not parse IPTC tags if disabled', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.iptc).to.be.undefined + done() + }, + { disableIptc: true } + ) + }) + + it('Should parse IPTC tag offsets', function (done) { + loadImage.parseMetaData(blobJPEG, function (data) { + expect(data.iptcOffsets).to.be.ok + expect(data.iptcOffsets.get('ObjectName')).to.equal(0x44) + done() + }) + }) + + it('Should not parse IPTC tag offsets if disabled', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.iptcOffsets).to.be.undefined + done() + }, + { disableIptcOffsets: true } + ) + }) + + it('Should only parse included IPTC tags', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.iptc).to.be.ok + expect(data.iptc.get('ApplicationRecordVersion')).to.be.undefined + expect(data.iptc.get('ObjectName')).to.equal('blueimp.net') + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.iptc).to.be.ok + expect(data.iptc.get('ApplicationRecordVersion')).to.equal(4) + expect(data.iptc.get('ObjectName')).to.be.undefined + done() + }, + { includeIptcTags: { 0: true } } // ApplicationRecordVersion + ) + }, + { includeIptcTags: { 5: true } } // ObjectName + ) + }) + + it('Should not parse excluded IPTC tags', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.iptc).to.be.ok + expect(data.iptc.get('ApplicationRecordVersion')).to.equal(4) + expect(data.iptc.get('ObjectName')).to.be.undefined + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.iptc).to.be.ok + expect(data.iptc.get('ApplicationRecordVersion')).to.be.undefined + expect(data.iptc.get('ObjectName')).to.equal('blueimp.net') + done() + }, + { excludeIptcTags: { 0: true } } // Orientation + ) + }, + { excludeIptcTags: { 5: true } } // DateTime + ) + }) + it('Should parse the complete image head', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.imageHead).to.be.ok @@ -1021,6 +1157,17 @@ }) }) + it('Should not parse the complete image head if disabled', function (done) { + loadImage.parseMetaData( + blobJPEG, + function (data) { + expect(data.imageHead).to.be.undefined + done() + }, + { disableImageHead: true } + ) + }) + it('Should parse meta data automatically', function (done) { expect( loadImage( From 79fdc82d6fe5fdd4ce037d184202708dac87349c Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sat, 11 Apr 2020 23:54:11 +0900 Subject: [PATCH 039/201] Fix ObjectURL revoke tests for Edge Legacy and IE. --- test/test.js | 72 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/test/test.js b/test/test.js index 6f2b039..35f9eab 100644 --- a/test/test.js +++ b/test/test.js @@ -68,6 +68,25 @@ } } + /** + * Request helper function. + * + * @param {string} url URL to request + * @param {Function} callback Request callback + */ + function request(url, callback) { + var xhr = new XMLHttpRequest() + xhr.onload = callback + xhr.onerror = callback + try { + xhr.open('GET', url, true) + } catch (e) { + callback.call(xhr, e) + return + } + xhr.send() + } + describe('Loading', function () { it('Return an object with onload and onerror methods', function () { var img = loadImage(blobGIF, function () {}) @@ -116,32 +135,37 @@ ).to.be.ok }) - it('Keep object URL if noRevoke is true', function (done) { - expect( - loadImage( - blobGIF, - function (img) { - loadImage(img.src, function (img2) { - expect(img.width).to.equal(img2.width) - expect(img.height).to.equal(img2.height) + describe('ObjectURL revoke', function () { + // Using XMLHttpRequest via the request helper function to test Object + // URLs to work around Edge Legacy and IE caching image URLs. + if (!window.XMLHttpRequest) return + + it('Keep object URL if noRevoke is set to true', function (done) { + expect( + loadImage( + blobGIF, + function (img) { + request(img.src, function (event) { + expect(event.type).to.equal('load') + done() + }) + }, + { noRevoke: true } + ) + ).to.be.ok + }) + + it('Discard object URL if noRevoke is not set', function (done) { + expect( + loadImage(blobGIF, function (img) { + request(img.src, function (event) { + // IE throws an error that has no type property: + expect(event.type).to.be.oneOf(['error', undefined]) done() }) - }, - { noRevoke: true } - ) - ).to.be.ok - }) - - it('Discard object URL if noRevoke is undefined/false', function (done) { - expect( - loadImage(blobGIF, function (img) { - loadImage(img.src, function (img2) { - expect(img2).to.be.an.instanceOf(window.Event) - expect(img2.type).to.equal('error') - done() }) - }) - ).to.be.ok + ).to.be.ok + }) }) }) @@ -1232,7 +1256,7 @@ it('Should fetch image URL as blob if meta option is true', function (done) { expect( loadImage( - // IE11 does not allow XMLHttpRequest access to data URLs, + // IE does not allow XMLHttpRequest access to data URLs, // so we use an ObjectURL instead of imageUrlJPEG directly: loadImage.createObjectURL(blobJPEG), function (img, data) { From 95b46948e57a6c719d119db3ac1454320c0f2d02 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sat, 11 Apr 2020 23:57:56 +0900 Subject: [PATCH 040/201] Add url to load/error event handler params. --- js/load-image.js | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/js/load-image.js b/js/load-image.js index a93ea13..ea633e4 100644 --- a/js/load-image.js +++ b/js/load-image.js @@ -28,10 +28,10 @@ var img = document.createElement('img') var url img.onerror = function (event) { - return loadImage.onerror(img, event, file, callback, options) + return loadImage.onerror(img, event, file, url, callback, options) } img.onload = function (event) { - return loadImage.onload(img, event, file, callback, options) + return loadImage.onload(img, event, file, url, callback, options) } if (typeof file === 'string') { loadImage.fetchBlob( @@ -58,7 +58,7 @@ // (Firefox 3.6) support the File API but not Blobs: loadImage.isInstanceOf('File', file) ) { - url = img._objectURL = loadImage.createObjectURL(file) + url = loadImage.createObjectURL(file) if (url) { img.src = url return img @@ -83,13 +83,12 @@ /** * Helper function to revoke an object URL * - * @param {HTMLImageElement} img Image element + * @param {string} url Blob Object URL * @param {object} [options] Options object */ - function revokeHelper(img, options) { - if (img._objectURL && !(options && options.noRevoke)) { - loadImage.revokeObjectURL(img._objectURL) - delete img._objectURL + function revokeHelper(url, options) { + if (url && url.slice(0, 5) === 'blob:' && !(options && options.noRevoke)) { + loadImage.revokeObjectURL(url) } } @@ -109,15 +108,15 @@ callback(img, data) } - loadImage.onerror = function (img, event, file, callback, options) { - revokeHelper(img, options) + loadImage.onerror = function (img, event, file, url, callback, options) { + revokeHelper(url, options) if (callback) { callback.call(img, event) } } - loadImage.onload = function (img, event, file, callback, options) { - revokeHelper(img, options) + loadImage.onload = function (img, event, file, url, callback, options) { + revokeHelper(url, options) if (callback) { loadImage.transform(img, options, callback, file, { originalWidth: img.naturalWidth || img.width, From 6b38e52d6525415f08785ee571529f63b72cbc51 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 12 Apr 2020 00:00:47 +0900 Subject: [PATCH 041/201] Remove the meta dependency from the fetch plugin. --- js/load-image-fetch.js | 64 ++++++++++++++++++------------------------ js/load-image-meta.js | 5 ---- js/load-image.js | 48 ++++++++++++++++++++----------- 3 files changed, 58 insertions(+), 59 deletions(-) diff --git a/js/load-image-fetch.js b/js/load-image-fetch.js index 83fbfd5..7aabda1 100644 --- a/js/load-image-fetch.js +++ b/js/load-image-fetch.js @@ -15,9 +15,9 @@ 'use strict' if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: - define(['./load-image', './load-image-meta'], factory) + define(['./load-image'], factory) } else if (typeof module === 'object' && module.exports) { - factory(require('./load-image'), require('./load-image-meta')) + factory(require('./load-image')) } else { // Browser globals: factory(window.loadImage) @@ -27,19 +27,14 @@ if (typeof fetch !== 'undefined' && typeof Request !== 'undefined') { loadImage.fetchBlob = function (url, callback, options) { - if (loadImage.hasMetaOption(options)) { - fetch(new Request(url, options)) - .then(function (response) { - return response.blob() - }) - .then(callback) - .catch(function (err) { - console.log(err) // eslint-disable-line no-console - callback() - }) - } else { - callback() - } + fetch(new Request(url, options)) + .then(function (response) { + return response.blob() + }) + .then(callback) + .catch(function (err) { + callback(null, err) + }) } } else if ( // Check for XHR2 support: @@ -47,29 +42,24 @@ typeof ProgressEvent !== 'undefined' ) { loadImage.fetchBlob = function (url, callback, options) { - if (loadImage.hasMetaOption(options)) { - // eslint-disable-next-line no-param-reassign - options = options || {} - var req = new XMLHttpRequest() - req.open(options.method || 'GET', url) - if (options.headers) { - Object.keys(options.headers).forEach(function (key) { - req.setRequestHeader(key, options.headers[key]) - }) - } - req.withCredentials = options.credentials === 'include' - req.responseType = 'blob' - req.onload = function () { - callback(req.response) - } - req.onerror = req.onabort = req.ontimeout = function (e) { - console.log(e) // eslint-disable-line no-console - callback() - } - req.send(options.body) - } else { - callback() + // eslint-disable-next-line no-param-reassign + options = options || {} + var req = new XMLHttpRequest() + req.open(options.method || 'GET', url) + if (options.headers) { + Object.keys(options.headers).forEach(function (key) { + req.setRequestHeader(key, options.headers[key]) + }) + } + req.withCredentials = options.credentials === 'include' + req.responseType = 'blob' + req.onload = function () { + callback(req.response) + } + req.onerror = req.onabort = req.ontimeout = function (err) { + callback(null, err) } + req.send(options.body) } } }) diff --git a/js/load-image-meta.js b/js/load-image-meta.js index 2bcb8e6..ecdb077 100644 --- a/js/load-image-meta.js +++ b/js/load-image-meta.js @@ -179,11 +179,6 @@ ) } - // Determines if meta data should be loaded automatically: - loadImage.hasMetaOption = function (options) { - return options && options.meta - } - var originalTransform = loadImage.transform loadImage.transform = function (img, options, callback, file, data) { if (loadImage.hasMetaOption(options)) { diff --git a/js/load-image.js b/js/load-image.js index ea633e4..50a36cd 100644 --- a/js/load-image.js +++ b/js/load-image.js @@ -27,6 +27,26 @@ function loadImage(file, callback, options) { var img = document.createElement('img') var url + /** + * Callback for the fetchBlob call. + * + * @param {Blob} blob Blob object + * @param {Error} err Error object + */ + function fetchBlobCallback(blob, err) { + if (err) console.log(err) // eslint-disable-line no-console + if (blob && loadImage.isInstanceOf('Blob', blob)) { + // eslint-disable-next-line no-param-reassign + file = blob + url = loadImage.createObjectURL(file) + } else { + url = file + if (options && options.crossOrigin) { + img.crossOrigin = options.crossOrigin + } + } + img.src = url + } img.onerror = function (event) { return loadImage.onerror(img, event, file, url, callback, options) } @@ -34,23 +54,11 @@ return loadImage.onload(img, event, file, url, callback, options) } if (typeof file === 'string') { - loadImage.fetchBlob( - file, - function (blob) { - if (blob && loadImage.isInstanceOf('Blob', blob)) { - // eslint-disable-next-line no-param-reassign - file = blob - url = loadImage.createObjectURL(file) - } else { - url = file - if (options && options.crossOrigin) { - img.crossOrigin = options.crossOrigin - } - } - img.src = url - }, - options - ) + if (loadImage.hasMetaOption(options)) { + loadImage.fetchBlob(file, fetchBlobCallback, options) + } else { + fetchBlobCallback() + } return img } else if ( loadImage.isInstanceOf('Blob', file) || @@ -92,6 +100,12 @@ } } + // Determines if meta data should be loaded automatically. + // Requires the load image meta extension to load meta data. + loadImage.hasMetaOption = function (options) { + return options && options.meta + } + // If the callback given to this function returns a blob, it is used as image // source instead of the original url and overrides the file argument used in // the onload and onerror event callbacks: From ff22e11daa25d0cff328124abf1cca22ffaa4be5 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 12 Apr 2020 00:09:31 +0900 Subject: [PATCH 042/201] 3.0.0 --- js/load-image.all.min.js | 2 +- js/load-image.all.min.js.map | 2 +- package-lock.json | 2 +- package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/js/load-image.all.min.js b/js/load-image.all.min.js index f09182f..a1522ed 100644 --- a/js/load-image.all.min.js +++ b/js/load-image.all.min.js @@ -1,2 +1,2 @@ -!function(o){"use strict";function r(t,i,a){var o,n=document.createElement("img");return n.onerror=function(e){return r.onerror(n,e,t,i,a)},n.onload=function(e){return r.onload(n,e,t,i,a)},"string"==typeof t?(r.fetchBlob(t,function(e){e&&r.isInstanceOf("Blob",e)?o=r.createObjectURL(t=e):(o=t,a&&a.crossOrigin&&(n.crossOrigin=a.crossOrigin)),n.src=o},a),n):r.isInstanceOf("Blob",t)||r.isInstanceOf("File",t)?(o=n._objectURL=r.createObjectURL(t))?(n.src=o,n):r.readFile(t,function(e){var t=e.target;t&&t.result?n.src=t.result:i&&i(e)}):void 0}var t=o.createObjectURL&&o||o.URL&&URL.revokeObjectURL&&URL||o.webkitURL&&webkitURL;function n(e,t){!e._objectURL||t&&t.noRevoke||(r.revokeObjectURL(e._objectURL),delete e._objectURL)}r.fetchBlob=function(e,t){t()},r.isInstanceOf=function(e,t){return Object.prototype.toString.call(t)==="[object "+e+"]"},r.transform=function(e,t,i,a,o){i(e,o)},r.onerror=function(e,t,i,a,o){n(e,o),a&&a.call(e,t)},r.onload=function(e,t,i,a,o){n(e,o),a&&r.transform(e,o,a,i,{originalWidth:e.naturalWidth||e.width,originalHeight:e.naturalHeight||e.height})},r.createObjectURL=function(e){return!!t&&t.createObjectURL(e)},r.revokeObjectURL=function(e){return!!t&&t.revokeObjectURL(e)},r.readFile=function(e,t,i){if(o.FileReader){var a=new FileReader;if(a.onload=a.onerror=t,a[i=i||"readAsDataURL"])return a[i](e),a}return!1},"function"==typeof define&&define.amd?define(function(){return r}):"object"==typeof module&&module.exports?module.exports=r:o.loadImage=r}("undefined"!=typeof window&&window||this),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image"],e):"object"==typeof module&&module.exports?e(require("./load-image")):e(window.loadImage)}(function(x){"use strict";var n=x.transform;x.transform=function(e,t,i,a,o){n.call(x,x.scale(e,t,o),t,i,a,o)},x.transformCoordinates=function(){},x.getTransformedOptions=function(e,t){var i,a,o,n,r=t.aspectRatio;if(!r)return t;for(a in i={},t)Object.prototype.hasOwnProperty.call(t,a)&&(i[a]=t[a]);return i.crop=!0,r<(o=e.naturalWidth||e.width)/(n=e.naturalHeight||e.height)?(i.maxWidth=n*r,i.maxHeight=n):(i.maxWidth=o,i.maxHeight=o/r),i},x.renderImageToCanvas=function(e,t,i,a,o,n,r,s,l,c,d){var u=e.getContext("2d");return!1===d.imageSmoothingEnabled?u.imageSmoothingEnabled=!1:d.imageSmoothingQuality&&(u.imageSmoothingQuality=d.imageSmoothingQuality),u.drawImage(t,i,a,o,n,r,s,l,c),e},x.hasCanvasOption=function(e){return e.canvas||e.crop||!!e.aspectRatio},x.scale=function(e,t,i){t=t||{};var a,o,n,r,s,l,c,d,u,f,g,p=document.createElement("canvas"),m=e.getContext||x.hasCanvasOption(t)&&p.getContext,h=e.naturalWidth||e.width,A=e.naturalHeight||e.height,b=h,y=A;function S(){var e=Math.max((n||b)/b,(r||y)/y);1r.byteLength){console.log("Invalid meta data: Invalid segment size.");break}if((a=p.metaDataParsers.jpeg[t])&&!u.disableMetaDataParsers)for(o=0;oe.byteLength))return g.createObjectURL(new Blob([e.buffer.slice(t,t+i)]));console.log("Invalid Exif data: Invalid thumbnail data.")},g.exifTagTypes={1:{getValue:function(e,t){return e.getUint8(t)},size:1},2:{getValue:function(e,t){return String.fromCharCode(e.getUint8(t))},size:1,ascii:!0},3:{getValue:function(e,t,i){return e.getUint16(t,i)},size:2},4:{getValue:function(e,t,i){return e.getUint32(t,i)},size:4},5:{getValue:function(e,t,i){return e.getUint32(t,i)/e.getUint32(t+4,i)},size:8},9:{getValue:function(e,t,i){return e.getInt32(t,i)},size:4},10:{getValue:function(e,t,i){return e.getInt32(t,i)/e.getInt32(t+4,i)},size:8}},g.exifTagTypes[7]=g.exifTagTypes[1],g.getExifValue=function(e,t,i,a,o,n){var r,s,l,c,d,u,f=g.exifTagTypes[a];if(f){if(!((s=4<(r=f.size*o)?t+e.getUint32(i+8,n):i+8)+r>e.byteLength)){if(1===o)return f.getValue(e,s,n);for(l=[],c=0;ce.byteLength)console.log("Invalid Exif data: Invalid directory offset.");else{if(!((r=i+2+12*(n=e.getUint16(i,a)))+4>e.byteLength)){for(s=0;se.byteLength)console.log("Invalid Exif data: Invalid segment size.");else if(0===e.getUint16(t+8)){switch(e.getUint16(l)){case 18761:n=!0;break;case 19789:n=!1;break;default:return void console.log("Invalid Exif data: Invalid byte alignment marker.")}42===e.getUint16(l+2,n)?(r=e.getUint32(l+4,n),a.exif=new g.ExifMap,o.disableExifOffsets||(a.exifOffsets=new g.ExifMap,a.exifTiffOffset=l,a.exifLittleEndian=n),(r=g.parseExifTags(e,l,l+r,n,a))&&!o.disableExifThumbnail&&(s={exif:{}},r=g.parseExifTags(e,l,l+r,n,s),s.exif[513]&&(a.exif.Thumbnail=g.getExifThumbnail(e,l+s.exif[513],s.exif[514]))),a.exif[34665]&&!o.disableExifSub&&g.parseExifTags(e,l,l+a.exif[34665],n,a),a.exif[34853]&&!o.disableExifGps&&g.parseExifTags(e,l,l+a.exif[34853],n,a)):console.log("Invalid Exif data: Missing TIFF marker.")}else console.log("Invalid Exif data: Missing byte alignment offset.")}},g.metaDataParsers.jpeg[65505].push(g.parseExifData),g.exifWriters={274:function(e,t,i){return new DataView(e,t.exifOffsets[274]+8,2).setUint16(0,i,t.exifLittleEndian),e}},g.writeExifData=function(e,t,i,a){g.exifWriters[t.exif.map[i]](e,t,a)}}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-exif"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-exif")):e(window.loadImage)}(function(e){"use strict";e.ExifMap.prototype.tags={256:"ImageWidth",257:"ImageHeight",34665:"ExifIFDPointer",34853:"GPSInfoIFDPointer",40965:"InteroperabilityIFDPointer",258:"BitsPerSample",259:"Compression",262:"PhotometricInterpretation",274:"Orientation",277:"SamplesPerPixel",284:"PlanarConfiguration",530:"YCbCrSubSampling",531:"YCbCrPositioning",282:"XResolution",283:"YResolution",296:"ResolutionUnit",273:"StripOffsets",278:"RowsPerStrip",279:"StripByteCounts",513:"JPEGInterchangeFormat",514:"JPEGInterchangeFormatLength",301:"TransferFunction",318:"WhitePoint",319:"PrimaryChromaticities",529:"YCbCrCoefficients",532:"ReferenceBlackWhite",306:"DateTime",270:"ImageDescription",271:"Make",272:"Model",305:"Software",315:"Artist",33432:"Copyright",36864:"ExifVersion",40960:"FlashpixVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",42240:"Gamma",37121:"ComponentsConfiguration",37122:"CompressedBitsPerPixel",37500:"MakerNote",37510:"UserComment",40964:"RelatedSoundFile",36867:"DateTimeOriginal",36868:"DateTimeDigitized",37520:"SubSecTime",37521:"SubSecTimeOriginal",37522:"SubSecTimeDigitized",33434:"ExposureTime",33437:"FNumber",34850:"ExposureProgram",34852:"SpectralSensitivity",34855:"PhotographicSensitivity",34856:"OECF",34864:"SensitivityType",34865:"StandardOutputSensitivity",34866:"RecommendedExposureIndex",34867:"ISOSpeed",34868:"ISOSpeedLatitudeyyy",34869:"ISOSpeedLatitudezzz",37377:"ShutterSpeedValue",37378:"ApertureValue",37379:"BrightnessValue",37380:"ExposureBias",37381:"MaxApertureValue",37382:"SubjectDistance",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37396:"SubjectArea",37386:"FocalLength",41483:"FlashEnergy",41484:"SpatialFrequencyResponse",41486:"FocalPlaneXResolution",41487:"FocalPlaneYResolution",41488:"FocalPlaneResolutionUnit",41492:"SubjectLocation",41493:"ExposureIndex",41495:"SensingMethod",41728:"FileSource",41729:"SceneType",41730:"CFAPattern",41985:"CustomRendered",41986:"ExposureMode",41987:"WhiteBalance",41988:"DigitalZoomRatio",41989:"FocalLengthIn35mmFilm",41990:"SceneCaptureType",41991:"GainControl",41992:"Contrast",41993:"Saturation",41994:"Sharpness",41995:"DeviceSettingDescription",41996:"SubjectDistanceRange",42016:"ImageUniqueID",42032:"CameraOwnerName",42033:"BodySerialNumber",42034:"LensSpecification",42035:"LensMake",42036:"LensModel",42037:"LensSerialNumber",0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude",5:"GPSAltitudeRef",6:"GPSAltitude",7:"GPSTimeStamp",8:"GPSSatellites",9:"GPSStatus",10:"GPSMeasureMode",11:"GPSDOP",12:"GPSSpeedRef",13:"GPSSpeed",14:"GPSTrackRef",15:"GPSTrack",16:"GPSImgDirectionRef",17:"GPSImgDirection",18:"GPSMapDatum",19:"GPSDestLatitudeRef",20:"GPSDestLatitude",21:"GPSDestLongitudeRef",22:"GPSDestLongitude",23:"GPSDestBearingRef",24:"GPSDestBearing",25:"GPSDestDistanceRef",26:"GPSDestDistance",27:"GPSProcessingMethod",28:"GPSAreaInformation",29:"GPSDateStamp",30:"GPSDifferential",31:"GPSHPositioningError"},e.ExifMap.prototype.stringValues={ExposureProgram:{0:"Undefined",1:"Manual",2:"Normal program",3:"Aperture priority",4:"Shutter priority",5:"Creative program",6:"Action program",7:"Portrait mode",8:"Landscape mode"},MeteringMode:{0:"Unknown",1:"Average",2:"CenterWeightedAverage",3:"Spot",4:"MultiSpot",5:"Pattern",6:"Partial",255:"Other"},LightSource:{0:"Unknown",1:"Daylight",2:"Fluorescent",3:"Tungsten (incandescent light)",4:"Flash",9:"Fine weather",10:"Cloudy weather",11:"Shade",12:"Daylight fluorescent (D 5700 - 7100K)",13:"Day white fluorescent (N 4600 - 5400K)",14:"Cool white fluorescent (W 3900 - 4500K)",15:"White fluorescent (WW 3200 - 3700K)",17:"Standard light A",18:"Standard light B",19:"Standard light C",20:"D55",21:"D65",22:"D75",23:"D50",24:"ISO studio tungsten",255:"Other"},Flash:{0:"Flash did not fire",1:"Flash fired",5:"Strobe return light not detected",7:"Strobe return light detected",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"Flash fired, auto mode, return light detected, red-eye reduction mode"},SensingMethod:{1:"Undefined",2:"One-chip color area sensor",3:"Two-chip color area sensor",4:"Three-chip color area sensor",5:"Color sequential area sensor",7:"Trilinear sensor",8:"Color sequential linear sensor"},SceneCaptureType:{0:"Standard",1:"Landscape",2:"Portrait",3:"Night scene"},SceneType:{1:"Directly photographed"},CustomRendered:{0:"Normal process",1:"Custom process"},WhiteBalance:{0:"Auto white balance",1:"Manual white balance"},GainControl:{0:"None",1:"Low gain up",2:"High gain up",3:"Low gain down",4:"High gain down"},Contrast:{0:"Normal",1:"Soft",2:"Hard"},Saturation:{0:"Normal",1:"Low saturation",2:"High saturation"},Sharpness:{0:"Normal",1:"Soft",2:"Hard"},SubjectDistanceRange:{0:"Unknown",1:"Macro",2:"Close view",3:"Distant view"},FileSource:{3:"DSC"},ComponentsConfiguration:{0:"",1:"Y",2:"Cb",3:"Cr",4:"R",5:"G",6:"B"},Orientation:{1:"top-left",2:"top-right",3:"bottom-right",4:"bottom-left",5:"left-top",6:"right-top",7:"right-bottom",8:"left-bottom"}},e.ExifMap.prototype.getText=function(e){var t=this.get(e);switch(e){case"LightSource":case"Flash":case"MeteringMode":case"ExposureProgram":case"SensingMethod":case"SceneCaptureType":case"SceneType":case"CustomRendered":case"WhiteBalance":case"GainControl":case"Contrast":case"Saturation":case"Sharpness":case"SubjectDistanceRange":case"FileSource":case"Orientation":return this.stringValues[e][t];case"ExifVersion":case"FlashpixVersion":if(!t)return;return String.fromCharCode(t[0],t[1],t[2],t[3]);case"ComponentsConfiguration":if(!t)return;return this.stringValues[e][t[0]]+this.stringValues[e][t[1]]+this.stringValues[e][t[2]]+this.stringValues[e][t[3]];case"GPSVersionID":if(!t)return;return t[0]+"."+t[1]+"."+t[2]+"."+t[3]}return String(t)},function(e){var t,i=e.tags,a=e.map;for(t in i)Object.prototype.hasOwnProperty.call(i,t)&&(a[i[t]]=t)}(e.ExifMap.prototype),e.ExifMap.prototype.getAll=function(){var e,t,i={};for(e in this)Object.prototype.hasOwnProperty.call(this,e)&&(t=this.tags[e])&&(i[t]=this.getText(t));return i}}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-meta"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-meta")):e(window.loadImage)}(function(u){"use strict";u.IptcMap=function(){return this},u.IptcMap.prototype.map={ObjectName:5},u.IptcMap.prototype.get=function(e){return this[e]||this[this.map[e]]},u.parseIptcTags=function(e,t,i,a){function o(e,t,i){for(var a="",o=t;or.byteLength){console.log("Invalid meta data: Invalid segment size.");break}if((n=m.metaDataParsers.jpeg[t])&&!u.disableMetaDataParsers)for(a=0;ae.byteLength)){if(1===a)return f.getValue(e,s,o);for(l=[],c=0;ce.byteLength)console.log("Invalid Exif data: Invalid directory offset.");else{if(!((c=i+2+12*(l=e.getUint16(i,n)))+4>e.byteLength)){for(d=0;dc.byteLength)console.log("Invalid Exif data: Invalid segment size.");else if(0===c.getUint16(e+8)){switch(c.getUint16(m)){case 18761:u=!0;break;case 19789:u=!1;break;default:return void console.log("Invalid Exif data: Invalid byte alignment marker.")}42===c.getUint16(m+2,u)?(n=c.getUint32(m+4,u),d.exif=new h,i.disableExifOffsets||(d.exifOffsets=new h,d.exifTiffOffset=m,d.exifLittleEndian=u),(n=p(c,m,m+n,u,d.exif,d.exifOffsets,f,g))&&!i.disableExifThumbnail&&(n=p(c,m,m+n,u,d.exif,d.exifOffsets,f,g),d.exif[513]&&d.exif[514]&&(d.exif[513]=function(e,t,i){if(i&&!(t+i>e.byteLength))return new Blob([e.buffer.slice(t,t+i)],{type:"image/jpeg"});console.log("Invalid Exif data: Invalid thumbnail data.")}(c,m+d.exif[513],d.exif[514]))),Object.keys(d.exif.privateIFDs).forEach(function(e){var t,i,n,a,o,r,s,l;i=e,n=c,a=m,o=u,r=f,s=g,(l=(t=d).exif[i])&&(t.exif[i]=new h(i),t.exifOffsets&&(t.exifOffsets[i]=new h(i)),p(n,a,a+l,o,t.exif[i],t.exifOffsets&&t.exifOffsets[i],r&&r[i],s&&s[i]))})):console.log("Invalid Exif data: Missing TIFF marker.")}else console.log("Invalid Exif data: Missing byte alignment offset.")}},a.metaDataParsers.jpeg[65505].push(a.parseExifData),a.exifWriters={274:function(e,t,i){return new DataView(e,t.exifOffsets[274]+8,2).setUint16(0,i,t.exifLittleEndian),e}},a.writeExifData=function(e,t,i,n){a.exifWriters[t.exif.map[i]](e,t,n)},a.ExifMap=h}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-exif"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-exif")):e(window.loadImage)}(function(e){"use strict";var a=e.ExifMap.prototype;a.tags={256:"ImageWidth",257:"ImageHeight",258:"BitsPerSample",259:"Compression",262:"PhotometricInterpretation",274:"Orientation",277:"SamplesPerPixel",284:"PlanarConfiguration",530:"YCbCrSubSampling",531:"YCbCrPositioning",282:"XResolution",283:"YResolution",296:"ResolutionUnit",273:"StripOffsets",278:"RowsPerStrip",279:"StripByteCounts",513:"JPEGInterchangeFormat",514:"JPEGInterchangeFormatLength",301:"TransferFunction",318:"WhitePoint",319:"PrimaryChromaticities",529:"YCbCrCoefficients",532:"ReferenceBlackWhite",306:"DateTime",270:"ImageDescription",271:"Make",272:"Model",305:"Software",315:"Artist",33432:"Copyright",34665:{36864:"ExifVersion",40960:"FlashpixVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",42240:"Gamma",37121:"ComponentsConfiguration",37122:"CompressedBitsPerPixel",37500:"MakerNote",37510:"UserComment",40964:"RelatedSoundFile",36867:"DateTimeOriginal",36868:"DateTimeDigitized",37520:"SubSecTime",37521:"SubSecTimeOriginal",37522:"SubSecTimeDigitized",33434:"ExposureTime",33437:"FNumber",34850:"ExposureProgram",34852:"SpectralSensitivity",34855:"PhotographicSensitivity",34856:"OECF",34864:"SensitivityType",34865:"StandardOutputSensitivity",34866:"RecommendedExposureIndex",34867:"ISOSpeed",34868:"ISOSpeedLatitudeyyy",34869:"ISOSpeedLatitudezzz",37377:"ShutterSpeedValue",37378:"ApertureValue",37379:"BrightnessValue",37380:"ExposureBias",37381:"MaxApertureValue",37382:"SubjectDistance",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37396:"SubjectArea",37386:"FocalLength",41483:"FlashEnergy",41484:"SpatialFrequencyResponse",41486:"FocalPlaneXResolution",41487:"FocalPlaneYResolution",41488:"FocalPlaneResolutionUnit",41492:"SubjectLocation",41493:"ExposureIndex",41495:"SensingMethod",41728:"FileSource",41729:"SceneType",41730:"CFAPattern",41985:"CustomRendered",41986:"ExposureMode",41987:"WhiteBalance",41988:"DigitalZoomRatio",41989:"FocalLengthIn35mmFilm",41990:"SceneCaptureType",41991:"GainControl",41992:"Contrast",41993:"Saturation",41994:"Sharpness",41995:"DeviceSettingDescription",41996:"SubjectDistanceRange",42016:"ImageUniqueID",42032:"CameraOwnerName",42033:"BodySerialNumber",42034:"LensSpecification",42035:"LensMake",42036:"LensModel",42037:"LensSerialNumber"},34853:{0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude",5:"GPSAltitudeRef",6:"GPSAltitude",7:"GPSTimeStamp",8:"GPSSatellites",9:"GPSStatus",10:"GPSMeasureMode",11:"GPSDOP",12:"GPSSpeedRef",13:"GPSSpeed",14:"GPSTrackRef",15:"GPSTrack",16:"GPSImgDirectionRef",17:"GPSImgDirection",18:"GPSMapDatum",19:"GPSDestLatitudeRef",20:"GPSDestLatitude",21:"GPSDestLongitudeRef",22:"GPSDestLongitude",23:"GPSDestBearingRef",24:"GPSDestBearing",25:"GPSDestDistanceRef",26:"GPSDestDistance",27:"GPSProcessingMethod",28:"GPSAreaInformation",29:"GPSDateStamp",30:"GPSDifferential",31:"GPSHPositioningError"},40965:{1:"InteroperabilityIndex"}},a.stringValues={ExposureProgram:{0:"Undefined",1:"Manual",2:"Normal program",3:"Aperture priority",4:"Shutter priority",5:"Creative program",6:"Action program",7:"Portrait mode",8:"Landscape mode"},MeteringMode:{0:"Unknown",1:"Average",2:"CenterWeightedAverage",3:"Spot",4:"MultiSpot",5:"Pattern",6:"Partial",255:"Other"},LightSource:{0:"Unknown",1:"Daylight",2:"Fluorescent",3:"Tungsten (incandescent light)",4:"Flash",9:"Fine weather",10:"Cloudy weather",11:"Shade",12:"Daylight fluorescent (D 5700 - 7100K)",13:"Day white fluorescent (N 4600 - 5400K)",14:"Cool white fluorescent (W 3900 - 4500K)",15:"White fluorescent (WW 3200 - 3700K)",17:"Standard light A",18:"Standard light B",19:"Standard light C",20:"D55",21:"D65",22:"D75",23:"D50",24:"ISO studio tungsten",255:"Other"},Flash:{0:"Flash did not fire",1:"Flash fired",5:"Strobe return light not detected",7:"Strobe return light detected",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"Flash fired, auto mode, return light detected, red-eye reduction mode"},SensingMethod:{1:"Undefined",2:"One-chip color area sensor",3:"Two-chip color area sensor",4:"Three-chip color area sensor",5:"Color sequential area sensor",7:"Trilinear sensor",8:"Color sequential linear sensor"},SceneCaptureType:{0:"Standard",1:"Landscape",2:"Portrait",3:"Night scene"},SceneType:{1:"Directly photographed"},CustomRendered:{0:"Normal process",1:"Custom process"},WhiteBalance:{0:"Auto white balance",1:"Manual white balance"},GainControl:{0:"None",1:"Low gain up",2:"High gain up",3:"Low gain down",4:"High gain down"},Contrast:{0:"Normal",1:"Soft",2:"Hard"},Saturation:{0:"Normal",1:"Low saturation",2:"High saturation"},Sharpness:{0:"Normal",1:"Soft",2:"Hard"},SubjectDistanceRange:{0:"Unknown",1:"Macro",2:"Close view",3:"Distant view"},FileSource:{3:"DSC"},ComponentsConfiguration:{0:"",1:"Y",2:"Cb",3:"Cr",4:"R",5:"G",6:"B"},Orientation:{1:"top-left",2:"top-right",3:"bottom-right",4:"bottom-left",5:"left-top",6:"right-top",7:"right-bottom",8:"left-bottom"}},a.getText=function(e){var t=this.get(e);switch(e){case"LightSource":case"Flash":case"MeteringMode":case"ExposureProgram":case"SensingMethod":case"SceneCaptureType":case"SceneType":case"CustomRendered":case"WhiteBalance":case"GainControl":case"Contrast":case"Saturation":case"Sharpness":case"SubjectDistanceRange":case"FileSource":case"Orientation":return this.stringValues[e][t];case"ExifVersion":case"FlashpixVersion":if(!t)return;return String.fromCharCode(t[0],t[1],t[2],t[3]);case"ComponentsConfiguration":if(!t)return;return this.stringValues[e][t[0]]+this.stringValues[e][t[1]]+this.stringValues[e][t[2]]+this.stringValues[e][t[3]];case"GPSVersionID":if(!t)return;return t[0]+"."+t[1]+"."+t[2]+"."+t[3]}return String(t)},a.getAll=function(){var e,t,i,n={};for(e in this)Object.prototype.hasOwnProperty.call(this,e)&&((t=this[e])&&t.getAll?n[this.privateIFDs[e].name]=t.getAll():(i=this.tags[e])&&(n[i]=this.getText(i)));return n},a.getName=function(e){var t=this.tags[e];return"object"==typeof t?this.privateIFDs[e].name:t},function(){var e,t,i,n=a.tags;for(e in n)if(Object.prototype.hasOwnProperty.call(n,e))if(t=a.privateIFDs[e])for(e in i=n[e])Object.prototype.hasOwnProperty.call(i,e)&&(t.map[i[e]]=Number(e));else a.map[n[e]]=Number(e)}()}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-meta"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-meta")):e(window.loadImage)}(function(e){"use strict";function g(){}function m(e,t,i,n,a){return"binary"===t.types[e]?new Blob([i.buffer.slice(n,n+a)]):"Uint16"===t.types[e]?i.getUint16(n):function(e,t,i){for(var n="",a=t+i,o=t;o Date: Mon, 20 Apr 2020 12:36:13 +0600 Subject: [PATCH 043/201] Compatibility with jQuery 3.5.0 --- js/demo/demo.js | 6 +++--- js/vendor/jquery.Jcrop.js | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/js/demo/demo.js b/js/demo/demo.js index 6dc9fa3..b42cdcd 100644 --- a/js/demo/demo.js +++ b/js/demo/demo.js @@ -29,7 +29,7 @@ $(function () { * @param {object} tags Tags object */ function displayTagData(node, tags) { - var table = $('
    ') + var table = $('
    ') var row = $('') var cell = $('') var prop @@ -59,7 +59,7 @@ $(function () { */ function displayThumbnailImage(node, thumbnail, options) { if (thumbnail) { - var link = $('') + var link = $('') .attr('href', loadImage.createObjectURL(thumbnail)) .attr('download', 'thumbnail.jpg') .appendTo(node) @@ -105,7 +105,7 @@ $(function () { result.children().replaceWith($('Loading image file failed')) return } - var content = $('').append(img) + var content = $('').append(img) result.children().replaceWith(content) if (data) { if (img.getContext) { diff --git a/js/vendor/jquery.Jcrop.js b/js/vendor/jquery.Jcrop.js index 41f80e6..a879391 100755 --- a/js/vendor/jquery.Jcrop.js +++ b/js/vendor/jquery.Jcrop.js @@ -329,7 +329,7 @@ boundy = $img.height(), - $div = $('
    ').width(boundx).height(boundy).addClass(cssClass('holder')).css({ + $div = $('
    ').width(boundx).height(boundy).addClass(cssClass('holder')).css({ position: 'relative', backgroundColor: options.bgColor }).insertAfter($origimg).append($img); @@ -338,19 +338,19 @@ $div.addClass(options.addClass); } - var $img2 = $('
    '), + var $img2 = $('
    '), - $img_holder = $('
    ') + $img_holder = $('
    ') .width('100%').height('100%').css({ zIndex: 310, position: 'absolute', overflow: 'hidden' }), - $hdl_holder = $('
    ') + $hdl_holder = $('
    ') .width('100%').height('100%').css('zIndex', 320), - $sel = $('
    ') + $sel = $('
    ') .css({ position: 'absolute', zIndex: 600 @@ -737,7 +737,7 @@ // Shade Module {{{ var Shade = (function() { var enabled = false, - holder = $('
    ').css({ + holder = $('
    ').css({ position: 'absolute', zIndex: 240, opacity: 0 @@ -779,7 +779,7 @@ }); } function createShade() { - return $('
    ').css({ + return $('
    ').css({ position: 'absolute', backgroundColor: options.shadeColor||options.bgColor }).appendTo(holder); @@ -863,7 +863,7 @@ // Private Methods function insertBorder(type) //{{{ { - var jq = $('
    ').css({ + var jq = $('
    ').css({ position: 'absolute', opacity: options.borderOpacity }).addClass(cssClass(type)); @@ -873,7 +873,7 @@ //}}} function dragDiv(ord, zi) //{{{ { - var jq = $('
    ').mousedown(createDragger(ord)).css({ + var jq = $('
    ').mousedown(createDragger(ord)).css({ cursor: ord + '-resize', position: 'absolute', zIndex: zi @@ -1226,7 +1226,7 @@ width: '12px' }).addClass('jcrop-keymgr'), - $keywrap = $('
    ').css({ + $keywrap = $('
    ').css({ position: 'absolute', overflow: 'hidden' }).append($keymgr); From 804fd90a10177d7a9ccdbdfde2a663046cb02a8e Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Mon, 20 Apr 2020 22:31:56 +0900 Subject: [PATCH 044/201] Remove unnecessary whitespace. --- README.md | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index cc067d4..3c7a154 100644 --- a/README.md +++ b/README.md @@ -240,100 +240,103 @@ Defines the minimum height of the img/canvas element. The width of the sub-rectangle of the source image to draw into the destination canvas. - Defaults to the source image width and requires `canvas: true`. +Defaults to the source image width and requires `canvas: true`. ### sourceHeight The height of the sub-rectangle of the source image to draw into the destination canvas. - Defaults to the source image height and requires `canvas: true`. +Defaults to the source image height and requires `canvas: true`. ### top The top margin of the sub-rectangle of the source image. - Defaults to `0` and requires `canvas: true`. +Defaults to `0` and requires `canvas: true`. ### right The right margin of the sub-rectangle of the source image. - Defaults to `0` and requires `canvas: true`. +Defaults to `0` and requires `canvas: true`. ### bottom The bottom margin of the sub-rectangle of the source image. - Defaults to `0` and requires `canvas: true`. +Defaults to `0` and requires `canvas: true`. ### left The left margin of the sub-rectangle of the source image. - Defaults to `0` and requires `canvas: true`. +Defaults to `0` and requires `canvas: true`. ### contain Scales the image up/down to contain it in the max dimensions if set to `true`. - This emulates the CSS feature [background-image: contain](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Scaling_background_images#contain). +This emulates the CSS feature +[background-image: contain](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Scaling_background_images#contain). ### cover Scales the image up/down to cover the max dimensions with the image dimensions if set to `true`. - This emulates the CSS feature [background-image: cover](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Scaling_background_images#cover). +This emulates the CSS feature +[background-image: cover](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Scaling_background_images#cover). ### aspectRatio Crops the image to the given aspect ratio (e.g. `16/9`). - Setting the `aspectRatio` also enables the `crop` option. +Setting the `aspectRatio` also enables the `crop` option. ### pixelRatio Defines the ratio of the canvas pixels to the physical image pixels on the screen. - Should be set to `window.devicePixelRatio` unless the scaled image is not rendered -on screen. - Defaults to `1` and requires `canvas: true`. +Should be set to `window.devicePixelRatio` unless the scaled image is not +rendered on screen. +Defaults to `1` and requires `canvas: true`. ### downsamplingRatio Defines the ratio in which the image is downsampled. - By default, images are downsampled in one step. With a ratio of `0.5`, each step +By default, images are downsampled in one step. With a ratio of `0.5`, each step scales the image to half the size, before reaching the target dimensions. - Requires `canvas: true`. +Requires `canvas: true`. ### imageSmoothingEnabled If set to `false`, [disables image smoothing](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingEnabled). - Defaults to `true` and requires `canvas: true`. +Defaults to `true` and requires `canvas: true`. ### imageSmoothingQuality Sets the [quality of image smoothing](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingQuality). - Possible values: `'low'`, `'medium'`, `'high'` - Defaults to `'low'` and requires `canvas: true`. +Possible values: `'low'`, `'medium'`, `'high'` +Defaults to `'low'` and requires `canvas: true`. ### crop Crops the image to the maxWidth/maxHeight constraints if set to `true`. - Enabling the `crop` option also enables the `canvas` option. +Enabling the `crop` option also enables the `canvas` option. ### orientation Transform the canvas according to the specified Exif orientation, which can be an `integer` in the range of `1` to `8` or the boolean value `true`. - When set to `true`, it will set the orientation value based on the EXIF data of +When set to `true`, it will set the orientation value based on the EXIF data of the image, which will be parsed automatically if the exif library is available. Setting `orientation` to an integer in the range of `2` to `8` enables the `canvas` option. - Setting `orientation` to `true` enables the `canvas` and `meta` options, unless -the browser supports automatic image orientation (see [browser support for image-orientation](https://caniuse.com/#feat=css-image-orientation)). +Setting `orientation` to `true` enables the `canvas` and `meta` options, unless +the browser supports automatic image orientation (see +[browser support for image-orientation](https://caniuse.com/#feat=css-image-orientation)). ### meta Automatically parses the image meta data if set to `true`. - The meta data is passed to the callback as part of the second argument. - If the file is given as URL and the browser supports the +The meta data is passed to the callback as part of the second argument. +If the file is given as URL and the browser supports the [fetch API](https://developer.mozilla.org/en/docs/Web/API/Fetch_API), fetches the file as Blob to be able to parse the meta data. From 3f7b50eab933a339b1dac49b284581957b245c85 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Mon, 20 Apr 2020 22:43:51 +0900 Subject: [PATCH 045/201] Clarify meta option. --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3c7a154..8a1e09a 100644 --- a/README.md +++ b/README.md @@ -335,10 +335,13 @@ the browser supports automatic image orientation (see ### meta Automatically parses the image meta data if set to `true`. -The meta data is passed to the callback as part of the second argument. +If meta data has been found, the data object passed as second argument to the +callback function has additional properties (see +[meta data parsing](#meta-data-parsing)). If the file is given as URL and the browser supports the -[fetch API](https://developer.mozilla.org/en/docs/Web/API/Fetch_API), fetches -the file as Blob to be able to parse the meta data. +[fetch API](https://developer.mozilla.org/en/docs/Web/API/Fetch_API) or the XHR +[responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType) +`blob`, fetches the file as Blob to be able to parse the meta data. ### canvas From addca35c4769526606d303f44a5064557a1f420b Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Mon, 20 Apr 2020 22:51:22 +0900 Subject: [PATCH 046/201] Flash tag is not in the base exif map anymore. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a1e09a..0e334be 100644 --- a/README.md +++ b/README.md @@ -473,7 +473,7 @@ become available, as well as three additional methods: - `exif.getAll()` ```js -var flashText = data.exif.getText('Flash') // e.g.: 'Flash fired, auto mode', +var flashText = data.exif.getText('Orientation') // e.g. right-top for value 6 var name = data.exif.getName(0x0112) // Orientation From 2715acb296be9dbbd122fbf4131bb2958becb635 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Mon, 20 Apr 2020 22:56:47 +0900 Subject: [PATCH 047/201] Add headlines for the Exif/IPTC parser options. --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0e334be..48c2d33 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,10 @@ - [Meta data parsing](#meta-data-parsing) - [Image head](#image-head) - [Exif parser](#exif-parser) + - [Exif parser options](#exif-parser-options) - [Exif writer](#exif-writer) - [IPTC parser](#iptc-parser) + - [IPTC parser options](#iptc-parser-options) - [License](#license) - [Credits](#credits) @@ -481,8 +483,9 @@ var name = data.exif.getName(0x0112) // Orientation var allTags = data.exif.getAll() ``` -The Exif parser also adds additional options for the parseMetaData method, to -disable certain aspects of the parser: +#### Exif parser options + +The Exif parser adds additional options: - `disableExif`: Disables Exif parsing when `true`. - `disableExifThumbnail`: Disables parsing of Thumbnail data when `true`. @@ -599,8 +602,9 @@ var name = data.iptc.getName(5) // ObjectName var allTags = data.iptc.getAll() ``` -The IPTC parser also adds additional options for the parseMetaData method, to -disable certain aspects of the parser: +#### IPTC parser options + +The IPTC parser adds additional options: - `disableIptc`: Disables IPTC parsing when true. - `disableIptcOffsets`: Disables storing IPTC tag offsets when `true`. From b96a82149f6fb13befc1764caec141647b1324e7 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Mon, 20 Apr 2020 23:35:53 +0900 Subject: [PATCH 048/201] Add examples for parsing Exif Thumbnail and IFDs. --- README.md | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 48c2d33..865156c 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,10 @@ - [Meta data parsing](#meta-data-parsing) - [Image head](#image-head) - [Exif parser](#exif-parser) + - [Exif Thumbnail](#exif-thumbnail) + - [Exif IFD](#exif-ifd) + - [GPSInfo IFD](#gpsinfo-ifd) + - [Interoperability IFD](#interoperability-ifd) - [Exif parser options](#exif-parser-options) - [Exif writer](#exif-writer) - [IPTC parser](#iptc-parser) @@ -463,9 +467,9 @@ By default, only the following names are mapped: - `Orientation` - `Thumbnail` -- `Exif` -- `GPSInfo` -- `Interoperability` +- `Exif` (see [Exif IFD](#exif-ifd)) +- `GPSInfo` (see [GPSInfo IFD](#gpsinfo-ifd)) +- `Interoperability` (see [Interoperability IFD](#interoperability-ifd)) If you also include the Load Image Exif Map library, additional tag mappings become available, as well as three additional methods: @@ -483,6 +487,86 @@ var name = data.exif.getName(0x0112) // Orientation var allTags = data.exif.getAll() ``` +#### Exif Thumbnail + +Example code displaying a thumbnail image embedded into the Exif meta data: + +```js +loadImage( + fileOrBlobOrUrl, + function (img, data) { + var thumbBlob = data.exif && data.exif.get('Thumbnail') + if (thumbBlob) { + loadImage(thumbBlob, function (thumbImage) { + document.body.appendChild(thumbImage) + }) + } + }, + { meta: true } +) +``` + +#### Exif IFD + +Example code displaying data from the Exif IFD (Image File Directory) that +contains Exif specified TIFF tags: + +```js +loadImage( + fileOrBlobOrUrl, + function (img, data) { + var exifIFD = data.exif && data.exif.get('Exif') + if (exifIFD) { + // Map of all Exif IFD tags with their mapped names/text as keys/values: + console.log(exifIFD.getAll()) + // A specific Exif IFD tag value: + console.log(exifIFD.get('UserComment')) + } + }, + { meta: true } +) +``` + +#### GPSInfo IFD + +Example code displaying data from the Exif IFD (Image File Directory) that +contains [GPS](https://en.wikipedia.org/wiki/Global_Positioning_System) info: + +```js +loadImage( + fileOrBlobOrUrl, + function (img, data) { + var gpsInfo = data.exif && data.exif.get('GPSInfo') + if (gpsInfo) { + // Map of all GPSInfo tags with their mapped names/text as keys/values: + console.log(gpsInfo.getAll()) + // A specific GPSInfo tag value: + console.log(gpsInfo.get('GPSLatitude')) + } + }, + { meta: true } +) +``` + +#### Interoperability IFD + +Example code displaying data from the Exif IFD (Image File Directory) that +contains Interoperability data: + +```js +loadImage( + fileOrBlobOrUrl, + function (img, data) { + var interoperabilityData = data.exif && data.exif.get('Interoperability') + if (interoperabilityData) { + // The InteroperabilityIndex tag value: + console.log(interoperabilityData.get('InteroperabilityIndex')) + } + }, + { meta: true } +) +``` + #### Exif parser options The Exif parser adds additional options: From 6869b3b537e0e88f7e9cad04932aaca922708e05 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 21 Apr 2020 17:34:37 +0900 Subject: [PATCH 049/201] Remove unnecessary "Should" as test prefix. --- test/test.js | 66 ++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/test/test.js b/test/test.js index 35f9eab..cb1cd8d 100644 --- a/test/test.js +++ b/test/test.js @@ -682,7 +682,7 @@ }) describe('Orientation', function () { - it('Should keep the orientation', function (done) { + it('Keep the orientation', function (done) { expect( loadImage( blobGIF, @@ -696,7 +696,7 @@ ).to.be.ok }) - it('Should rotate left', function (done) { + it('Rotate left', function (done) { expect( loadImage( blobGIF, @@ -710,7 +710,7 @@ ).to.be.ok }) - it('Should rotate right', function (done) { + it('Rotate right', function (done) { expect( loadImage( blobGIF, @@ -724,7 +724,7 @@ ).to.be.ok }) - it('Should adjust constraints to new coordinates', function (done) { + it('Adjust constraints to new coordinates', function (done) { expect( loadImage( blobGIF, @@ -738,7 +738,7 @@ ).to.be.ok }) - it('Should adjust left and top to new coordinates', function (done) { + it('Adjust left and top to new coordinates', function (done) { expect( loadImage( blobGIF, @@ -752,7 +752,7 @@ ).to.be.ok }) - it('Should adjust right and bottom to new coordinates', function (done) { + it('Adjust right and bottom to new coordinates', function (done) { expect( loadImage( blobGIF, @@ -766,7 +766,7 @@ ).to.be.ok }) - it('Should adjust left and bottom to new coordinates', function (done) { + it('Adjust left and bottom to new coordinates', function (done) { expect( loadImage( blobGIF, @@ -780,7 +780,7 @@ ).to.be.ok }) - it('Should adjust right and top to new coordinates', function (done) { + it('Adjust right and top to new coordinates', function (done) { expect( loadImage( blobGIF, @@ -794,7 +794,7 @@ ).to.be.ok }) - it('Should rotate left with the given pixelRatio', function (done) { + it('Rotate left with the given pixelRatio', function (done) { expect( loadImage( blobGIF, @@ -810,7 +810,7 @@ ).to.be.ok }) - it('Should rotate right with the given pixelRatio', function (done) { + it('Rotate right with the given pixelRatio', function (done) { expect( loadImage( blobGIF, @@ -826,7 +826,7 @@ ).to.be.ok }) - it('Should ignore too small orientation value', function (done) { + it('Ignore too small orientation value', function (done) { expect( loadImage( blobGIF, @@ -840,7 +840,7 @@ ).to.be.ok }) - it('Should ignore too large orientation value', function (done) { + it('Ignore too large orientation value', function (done) { expect( loadImage( blobGIF, @@ -854,7 +854,7 @@ ).to.be.ok }) - it('Should rotate right based on the exif orientation value', function (done) { + it('Rotate right based on the exif orientation value', function (done) { expect( loadImage( blobJPEG, @@ -906,7 +906,7 @@ ).to.be.ok }) - it('Should scale image after exif based orientation', function (done) { + it('Scale image after exif based orientation', function (done) { expect( loadImage( blobJPEG, @@ -923,7 +923,7 @@ describe('from-image', function () { if (!loadImage.orientation) return - it('Should use automatic browser image orientation', function (done) { + it('Use automatic browser image orientation', function (done) { expect( loadImage( blobJPEG, @@ -1005,7 +1005,7 @@ }) describe('Metadata', function () { - it('Should parse Exif tags', function (done) { + it('Parse Exif tags', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.exif).to.be.ok expect(data.exif.get('Orientation')).to.equal(6) @@ -1013,7 +1013,7 @@ }) }) - it('Should not parse Exif tags if disabled', function (done) { + it('Do not parse Exif tags if disabled', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1024,7 +1024,7 @@ ) }) - it('Should parse Exif tag offsets', function (done) { + it('Parse Exif tag offsets', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.exifOffsets).to.be.ok expect(data.exifOffsets.get('Orientation')).to.equal(0x16) @@ -1034,7 +1034,7 @@ }) }) - it('Should not parse Exif tag offsets if disabled', function (done) { + it('Do not parse Exif tag offsets if disabled', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1045,7 +1045,7 @@ ) }) - it('Should only parse included Exif tags', function (done) { + it('Only parse included Exif tags', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1065,7 +1065,7 @@ ) }) - it('Should not parse excluded Exif tags', function (done) { + it('Do not parse excluded Exif tags', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1085,7 +1085,7 @@ ) }) - it('Should parse IPTC tags', function (done) { + it('Parse IPTC tags', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.iptc).to.be.ok expect(data.iptc.get('ObjectName')).to.equal('blueimp.net') @@ -1093,7 +1093,7 @@ }) }) - it('Should not parse IPTC tags if disabled', function (done) { + it('Do not parse IPTC tags if disabled', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1104,7 +1104,7 @@ ) }) - it('Should parse IPTC tag offsets', function (done) { + it('Parse IPTC tag offsets', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.iptcOffsets).to.be.ok expect(data.iptcOffsets.get('ObjectName')).to.equal(0x44) @@ -1112,7 +1112,7 @@ }) }) - it('Should not parse IPTC tag offsets if disabled', function (done) { + it('Do not parse IPTC tag offsets if disabled', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1123,7 +1123,7 @@ ) }) - it('Should only parse included IPTC tags', function (done) { + it('Only parse included IPTC tags', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1145,7 +1145,7 @@ ) }) - it('Should not parse excluded IPTC tags', function (done) { + it('Do not parse excluded IPTC tags', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1167,7 +1167,7 @@ ) }) - it('Should parse the complete image head', function (done) { + it('Parse the complete image head', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.imageHead).to.be.ok loadImage.parseMetaData( @@ -1181,7 +1181,7 @@ }) }) - it('Should not parse the complete image head if disabled', function (done) { + it('Do not parse the complete image head if disabled', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1192,7 +1192,7 @@ ) }) - it('Should parse meta data automatically', function (done) { + it('Parse meta data automatically', function (done) { expect( loadImage( blobJPEG, @@ -1210,7 +1210,7 @@ ).to.be.ok }) - it('Should write Exif Orientation tag and replace image head', function (done) { + it('Write Exif Orientation tag and replace image head', function (done) { loadImage( blobJPEG, function (img, data) { @@ -1253,7 +1253,7 @@ return } - it('Should fetch image URL as blob if meta option is true', function (done) { + it('Fetch image URL as blob if meta option is true', function (done) { expect( loadImage( // IE does not allow XMLHttpRequest access to data URLs, @@ -1273,7 +1273,7 @@ ).to.be.ok }) - it('Should load image URL as img if meta option is false', function (done) { + it('Load image URL as img if meta option is false', function (done) { expect( loadImage(imageUrlJPEG, function (img, data) { expect(data.imageHead).to.be.undefined From 4931b411b0d1df37850e0c480ee521a10e2e20a6 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 21 Apr 2020 23:16:45 +0900 Subject: [PATCH 050/201] Always pass a data arg to getTransformedOptions. --- js/load-image-scale.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/load-image-scale.js b/js/load-image-scale.js index 57ac273..dbebf50 100644 --- a/js/load-image-scale.js +++ b/js/load-image-scale.js @@ -45,7 +45,7 @@ // Returns transformed options, allows to override e.g. // maxWidth, maxHeight and crop options based on the aspectRatio. - // gets img, options passed as arguments: + // gets img, options, data passed as arguments: loadImage.getTransformedOptions = function (img, options) { var aspectRatio = options.aspectRatio var newOptions @@ -168,7 +168,7 @@ } if (useCanvas) { // eslint-disable-next-line no-param-reassign - options = loadImage.getTransformedOptions(img, options, data) + options = loadImage.getTransformedOptions(img, options, data || {}) sourceX = options.left || 0 sourceY = options.top || 0 if (options.sourceWidth) { From 379922b53b38a601738dfa8e79d3a396d494e82d Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 21 Apr 2020 23:23:47 +0900 Subject: [PATCH 051/201] Ensure pixelRatio scaling is idempotent. --- js/load-image-scale.js | 16 +++++++++++----- test/test.js | 12 ++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/js/load-image-scale.js b/js/load-image-scale.js index dbebf50..a662dde 100644 --- a/js/load-image-scale.js +++ b/js/load-image-scale.js @@ -225,11 +225,17 @@ if (useCanvas) { pixelRatio = options.pixelRatio if (pixelRatio > 1) { - canvas.style.width = destWidth + 'px' - canvas.style.height = destHeight + 'px' - destWidth *= pixelRatio - destHeight *= pixelRatio - canvas.getContext('2d').scale(pixelRatio, pixelRatio) + if (parseInt(img.style.width, 10) === width / pixelRatio) { + // Source image is already scaled according to device pixel ratio + canvas.style.width = destWidth / pixelRatio + 'px' + canvas.style.height = destHeight / pixelRatio + 'px' + } else { + canvas.style.width = destWidth + 'px' + canvas.style.height = destHeight + 'px' + destWidth *= pixelRatio + destHeight *= pixelRatio + canvas.getContext('2d').scale(pixelRatio, pixelRatio) + } } downsamplingRatio = options.downsamplingRatio if ( diff --git a/test/test.js b/test/test.js index cb1cd8d..1e688ae 100644 --- a/test/test.js +++ b/test/test.js @@ -300,6 +300,12 @@ expect(img.height).to.equal(160) expect(img.style.width).to.equal('120px') expect(img.style.height).to.equal('80px') + // Check if pixelRatio scaling is idempotent: + var img2 = loadImage.scale(img, { minWidth: 120, pixelRatio: 2 }) + expect(img2.width).to.equal(240) + expect(img2.height).to.equal(160) + expect(img2.style.width).to.equal('120px') + expect(img2.style.height).to.equal('80px') done() }, { minWidth: 120, canvas: true, pixelRatio: 2 } @@ -316,6 +322,12 @@ expect(img.height).to.equal(40) expect(img.style.width).to.equal('30px') expect(img.style.height).to.equal('20px') + // Check if pixelRatio scaling is idempotent: + var img2 = loadImage.scale(img, { minWidth: 30, pixelRatio: 2 }) + expect(img2.width).to.equal(60) + expect(img2.height).to.equal(40) + expect(img2.style.width).to.equal('30px') + expect(img2.style.height).to.equal('20px') done() }, { maxWidth: 30, canvas: true, pixelRatio: 2 } From 029ac424c3a9bb4c40951a1e12c73424c0808f00 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 21 Apr 2020 23:39:31 +0900 Subject: [PATCH 052/201] Document orientation values visually in source. --- js/load-image-orientation.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index 74a5be1..7527527 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -9,6 +9,20 @@ * https://opensource.org/licenses/MIT */ +/* + +Exif orientation values to correctly display the letter F: + + 1 2 3 4 5 6 7 8 + +██████ ██████ ██ ██ ██████████ ██ ██ ██████████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +████ ████ ████ ████ ██ ██████████ ██████████ ██ +██ ██ ██ ██ +██ ██ ██████ ██████ + +*/ + /* global define, module, require */ ;(function (factory) { From cda87fc468211987d808be08dc7ab06c059fa3e7 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 21 Apr 2020 23:41:32 +0900 Subject: [PATCH 053/201] Add missing degree character in source comments. --- js/load-image-orientation.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index 7527527..e48ebcd 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -119,7 +119,7 @@ Exif orientation values to correctly display the letter F: ctx.scale(1, -1) break case 5: - // vertical flip + 90 rotate right + // vertical flip + 90° rotate right ctx.rotate(0.5 * Math.PI) ctx.scale(1, -1) break @@ -129,7 +129,7 @@ Exif orientation values to correctly display the letter F: ctx.translate(0, -height) break case 7: - // horizontal flip + 90 rotate right + // horizontal flip + 90° rotate right ctx.rotate(0.5 * Math.PI) ctx.translate(width, -height) ctx.scale(-1, 1) @@ -185,7 +185,7 @@ Exif orientation values to correctly display the letter F: newOptions.bottom = options.top break case 5: - // vertical flip + 90 rotate right + // vertical flip + 90° rotate right newOptions.left = options.top newOptions.top = options.left newOptions.right = options.bottom @@ -199,7 +199,7 @@ Exif orientation values to correctly display the letter F: newOptions.bottom = options.left break case 7: - // horizontal flip + 90 rotate right + // horizontal flip + 90° rotate right newOptions.left = options.bottom newOptions.top = options.right newOptions.right = options.top From 61761388e0b9fff19acef3c4d5c1413c11b8c843 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 21 Apr 2020 23:45:39 +0900 Subject: [PATCH 054/201] Normalize original width+height dimensions. Switch reported original dimensions for browsers with automatic image orientation. --- js/load-image-orientation.js | 28 ++++++++++++++++++++++++++++ test/test.js | 14 ++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index e48ebcd..41ac1ee 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -43,6 +43,7 @@ Exif orientation values to correctly display the letter F: })(function (loadImage) { 'use strict' + var originalTransform = loadImage.transform var originalHasCanvasOption = loadImage.hasCanvasOption var originalHasMetaOption = loadImage.hasMetaOption var originalTransformCoordinates = loadImage.transformCoordinates @@ -66,6 +67,33 @@ Exif orientation values to correctly display the letter F: img.src = testImageURL })() + loadImage.transform = function (img, options, callback, file, data) { + originalTransform.call( + loadImage, + img, + options, + function (img, data) { + if (data) { + var exifOrientation = data.exif && data.exif.get('Orientation') + if ( + loadImage.orientation && + exifOrientation > 4 && + exifOrientation < 9 + ) { + // Automatic image orientation switched image dimensions + var originalWidth = data.originalWidth + var originalHeight = data.originalHeight + data.originalWidth = originalHeight + data.originalHeight = originalWidth + } + } + callback(img, data) + }, + file, + data + ) + } + // Determines if the target image should be a canvas element: loadImage.hasCanvasOption = function (options) { return ( diff --git a/test/test.js b/test/test.js index 1e688ae..84b4a4b 100644 --- a/test/test.js +++ b/test/test.js @@ -932,6 +932,20 @@ ).to.be.ok }) + it('Provide original image width+height from before orientation', function (done) { + expect( + loadImage( + blobJPEG, + function (img, data) { + expect(data.originalWidth).to.equal(3) + expect(data.originalHeight).to.equal(2) + done() + }, + { meta: true, minWidth: 20, minHeight: 30 } + ) + ).to.be.ok + }) + describe('from-image', function () { if (!loadImage.orientation) return From 2e72d13f9f4de50623d9b7e057d969e2121aa0ea Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 21 Apr 2020 23:46:48 +0900 Subject: [PATCH 055/201] Return early for invalid orientation values. --- js/load-image-orientation.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index 41ac1ee..71faf2f 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -111,19 +111,18 @@ Exif orientation values to correctly display the letter F: ) } - // Transform image orientation based on - // the given EXIF orientation option: + // Transform image orientation based on the given EXIF orientation option: loadImage.transformCoordinates = function (canvas, options) { originalTransformCoordinates.call(loadImage, canvas, options) + var orientation = options.orientation + if (!(orientation > 1 && orientation < 9)) { + return + } var ctx = canvas.getContext('2d') var width = canvas.width var height = canvas.height var styleWidth = canvas.style.width var styleHeight = canvas.style.height - var orientation = options.orientation - if (!(orientation > 1 && orientation < 9)) { - return - } if (orientation > 4) { canvas.width = height canvas.height = width From ae7013d4084a1b82a283be23c0543e92bd8ff2c2 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 21 Apr 2020 23:49:37 +0900 Subject: [PATCH 056/201] Move transformCoordinates declaration to the end. --- js/load-image-orientation.js | 116 +++++++++++++++++------------------ 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index 71faf2f..2f28171 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -111,64 +111,6 @@ Exif orientation values to correctly display the letter F: ) } - // Transform image orientation based on the given EXIF orientation option: - loadImage.transformCoordinates = function (canvas, options) { - originalTransformCoordinates.call(loadImage, canvas, options) - var orientation = options.orientation - if (!(orientation > 1 && orientation < 9)) { - return - } - var ctx = canvas.getContext('2d') - var width = canvas.width - var height = canvas.height - var styleWidth = canvas.style.width - var styleHeight = canvas.style.height - if (orientation > 4) { - canvas.width = height - canvas.height = width - canvas.style.width = styleHeight - canvas.style.height = styleWidth - } - switch (orientation) { - case 2: - // horizontal flip - ctx.translate(width, 0) - ctx.scale(-1, 1) - break - case 3: - // 180° rotate left - ctx.translate(width, height) - ctx.rotate(Math.PI) - break - case 4: - // vertical flip - ctx.translate(0, height) - ctx.scale(1, -1) - break - case 5: - // vertical flip + 90° rotate right - ctx.rotate(0.5 * Math.PI) - ctx.scale(1, -1) - break - case 6: - // 90° rotate right - ctx.rotate(0.5 * Math.PI) - ctx.translate(0, -height) - break - case 7: - // horizontal flip + 90° rotate right - ctx.rotate(0.5 * Math.PI) - ctx.translate(width, -height) - ctx.scale(-1, 1) - break - case 8: - // 90° rotate left - ctx.rotate(-0.5 * Math.PI) - ctx.translate(-width, 0) - break - } - } - // Transforms coordinate and dimension options // based on the given orientation option: loadImage.getTransformedOptions = function (img, opts, data) { @@ -250,4 +192,62 @@ Exif orientation values to correctly display the letter F: } return newOptions } + + // Transform image orientation based on the given EXIF orientation option: + loadImage.transformCoordinates = function (canvas, options) { + originalTransformCoordinates.call(loadImage, canvas, options) + var orientation = options.orientation + if (!(orientation > 1 && orientation < 9)) { + return + } + var ctx = canvas.getContext('2d') + var width = canvas.width + var height = canvas.height + var styleWidth = canvas.style.width + var styleHeight = canvas.style.height + if (orientation > 4) { + canvas.width = height + canvas.height = width + canvas.style.width = styleHeight + canvas.style.height = styleWidth + } + switch (orientation) { + case 2: + // horizontal flip + ctx.translate(width, 0) + ctx.scale(-1, 1) + break + case 3: + // 180° rotate left + ctx.translate(width, height) + ctx.rotate(Math.PI) + break + case 4: + // vertical flip + ctx.translate(0, height) + ctx.scale(1, -1) + break + case 5: + // vertical flip + 90° rotate right + ctx.rotate(0.5 * Math.PI) + ctx.scale(1, -1) + break + case 6: + // 90° rotate right + ctx.rotate(0.5 * Math.PI) + ctx.translate(0, -height) + break + case 7: + // horizontal flip + 90° rotate right + ctx.rotate(0.5 * Math.PI) + ctx.translate(width, -height) + ctx.scale(-1, 1) + break + case 8: + // 90° rotate left + ctx.rotate(-0.5 * Math.PI) + ctx.translate(-width, 0) + break + } + } }) From 83ace3efe41ffbf8221431f546365918311656aa Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Wed, 22 Apr 2020 00:07:26 +0900 Subject: [PATCH 057/201] Remove unnecessary double negation. --- js/load-image-orientation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index 2f28171..312f6ac 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -97,7 +97,7 @@ Exif orientation values to correctly display the letter F: // Determines if the target image should be a canvas element: loadImage.hasCanvasOption = function (options) { return ( - (!!options.orientation === true && !loadImage.orientation) || + (options.orientation === true && !loadImage.orientation) || (options.orientation > 1 && options.orientation < 9) || originalHasCanvasOption.call(loadImage, options) ) From 2abe1704e69886711b4b3b8bafe946822a57f7cc Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Wed, 22 Apr 2020 18:31:51 +0900 Subject: [PATCH 058/201] Pass data object to transformCoordinates function. --- js/load-image-scale.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/js/load-image-scale.js b/js/load-image-scale.js index a662dde..2f1fcc7 100644 --- a/js/load-image-scale.js +++ b/js/load-image-scale.js @@ -40,7 +40,7 @@ // Transform image coordinates, allows to override e.g. // the canvas orientation based on the orientation option, - // gets canvas, options passed as arguments: + // gets canvas, options and data passed as arguments: loadImage.transformCoordinates = function () {} // Returns transformed options, allows to override e.g. @@ -121,6 +121,8 @@ loadImage.scale = function (img, options, data) { // eslint-disable-next-line no-param-reassign options = options || {} + // eslint-disable-next-line no-param-reassign + data = data || {} var canvas = document.createElement('canvas') var useCanvas = img.getContext || @@ -168,7 +170,7 @@ } if (useCanvas) { // eslint-disable-next-line no-param-reassign - options = loadImage.getTransformedOptions(img, options, data || {}) + options = loadImage.getTransformedOptions(img, options, data) sourceX = options.left || 0 sourceY = options.top || 0 if (options.sourceWidth) { @@ -285,7 +287,7 @@ } canvas.width = destWidth canvas.height = destHeight - loadImage.transformCoordinates(canvas, options) + loadImage.transformCoordinates(canvas, options, data) return loadImage.renderImageToCanvas( canvas, img, From e52c67b9f77c18a9a7a6f0f22b04ea0a80ce63ae Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Wed, 22 Apr 2020 21:22:09 +0900 Subject: [PATCH 059/201] Rename functions for canvas and meta requirements. --- js/load-image-meta.js | 2 +- js/load-image-orientation.js | 12 ++++++------ js/load-image-scale.js | 10 +++------- js/load-image.js | 4 ++-- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/js/load-image-meta.js b/js/load-image-meta.js index ecdb077..63177d3 100644 --- a/js/load-image-meta.js +++ b/js/load-image-meta.js @@ -181,7 +181,7 @@ var originalTransform = loadImage.transform loadImage.transform = function (img, options, callback, file, data) { - if (loadImage.hasMetaOption(options)) { + if (loadImage.requiresMetaData(options)) { loadImage.parseMetaData( file, function (data) { diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index 312f6ac..ce0557f 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -44,8 +44,8 @@ Exif orientation values to correctly display the letter F: 'use strict' var originalTransform = loadImage.transform - var originalHasCanvasOption = loadImage.hasCanvasOption - var originalHasMetaOption = loadImage.hasMetaOption + var originalRequiresCanvas = loadImage.requiresCanvas + var originalRequiresMetaData = loadImage.requiresMetaData var originalTransformCoordinates = loadImage.transformCoordinates var originalGetTransformedOptions = loadImage.getTransformedOptions @@ -95,19 +95,19 @@ Exif orientation values to correctly display the letter F: } // Determines if the target image should be a canvas element: - loadImage.hasCanvasOption = function (options) { + loadImage.requiresCanvas = function (options) { return ( (options.orientation === true && !loadImage.orientation) || (options.orientation > 1 && options.orientation < 9) || - originalHasCanvasOption.call(loadImage, options) + originalRequiresCanvas.call(loadImage, options) ) } // Determines if meta data should be loaded automatically: - loadImage.hasMetaOption = function (options) { + loadImage.requiresMetaData = function (options) { return ( (options && options.orientation === true && !loadImage.orientation) || - originalHasMetaOption.call(loadImage, options) + originalRequiresMetaData.call(loadImage, options) ) } diff --git a/js/load-image-scale.js b/js/load-image-scale.js index 2f1fcc7..53fe5e6 100644 --- a/js/load-image-scale.js +++ b/js/load-image-scale.js @@ -109,15 +109,12 @@ } // Determines if the target image should be a canvas element: - loadImage.hasCanvasOption = function (options) { + loadImage.requiresCanvas = function (options) { return options.canvas || options.crop || !!options.aspectRatio } // Scales and/or crops the given image (img or canvas HTML element) - // using the given options. - // Returns a canvas object if the browser supports canvas - // and the hasCanvasOption method returns true or a canvas - // object is passed as image, else the scaled image: + // using the given options: loadImage.scale = function (img, options, data) { // eslint-disable-next-line no-param-reassign options = options || {} @@ -125,8 +122,7 @@ data = data || {} var canvas = document.createElement('canvas') var useCanvas = - img.getContext || - (loadImage.hasCanvasOption(options) && canvas.getContext) + img.getContext || (loadImage.requiresCanvas(options) && canvas.getContext) var width = img.naturalWidth || img.width var height = img.naturalHeight || img.height var destWidth = width diff --git a/js/load-image.js b/js/load-image.js index 50a36cd..865586d 100644 --- a/js/load-image.js +++ b/js/load-image.js @@ -54,7 +54,7 @@ return loadImage.onload(img, event, file, url, callback, options) } if (typeof file === 'string') { - if (loadImage.hasMetaOption(options)) { + if (loadImage.requiresMetaData(options)) { loadImage.fetchBlob(file, fetchBlobCallback, options) } else { fetchBlobCallback() @@ -102,7 +102,7 @@ // Determines if meta data should be loaded automatically. // Requires the load image meta extension to load meta data. - loadImage.hasMetaOption = function (options) { + loadImage.requiresMetaData = function (options) { return options && options.meta } From 0a0dc98c0103463de2e8911306c8726321c842e8 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Wed, 22 Apr 2020 21:43:28 +0900 Subject: [PATCH 060/201] Refactor canvas+meta requirement checks for reuse. --- js/load-image-orientation.js | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index ce0557f..6920d73 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -94,11 +94,31 @@ Exif orientation values to correctly display the letter F: ) } + /** + * Determines if the image requires orientation. + * + * @param {object} [options] Options object + * @param {boolean} [withMetaData] Is meta data required for orientation + * @returns {boolean} Returns true if the image requires orientation + */ + function requiresOrientation(options, withMetaData) { + var orientation = options && options.orientation + return ( + // Exif orientation for browsers without automatic image orientation: + (orientation === true && !loadImage.orientation) || + // Orientation reset for browsers with automatic image orientation: + (orientation === 1 && loadImage.orientation) || + // Orientation to defined value, requires meta data for orientation reset: + ((!withMetaData || loadImage.orientation) && + orientation > 1 && + orientation < 9) + ) + } + // Determines if the target image should be a canvas element: loadImage.requiresCanvas = function (options) { return ( - (options.orientation === true && !loadImage.orientation) || - (options.orientation > 1 && options.orientation < 9) || + requiresOrientation(options) || originalRequiresCanvas.call(loadImage, options) ) } @@ -106,7 +126,7 @@ Exif orientation values to correctly display the letter F: // Determines if meta data should be loaded automatically: loadImage.requiresMetaData = function (options) { return ( - (options && options.orientation === true && !loadImage.orientation) || + requiresOrientation(options, true) || originalRequiresMetaData.call(loadImage, options) ) } From a3eb4cda44a6b7d3327af93fe970151dea697f0c Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Wed, 22 Apr 2020 21:45:16 +0900 Subject: [PATCH 061/201] Move transform function below requirements checks. --- js/load-image-orientation.js | 54 ++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index 6920d73..edddb7c 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -67,33 +67,6 @@ Exif orientation values to correctly display the letter F: img.src = testImageURL })() - loadImage.transform = function (img, options, callback, file, data) { - originalTransform.call( - loadImage, - img, - options, - function (img, data) { - if (data) { - var exifOrientation = data.exif && data.exif.get('Orientation') - if ( - loadImage.orientation && - exifOrientation > 4 && - exifOrientation < 9 - ) { - // Automatic image orientation switched image dimensions - var originalWidth = data.originalWidth - var originalHeight = data.originalHeight - data.originalWidth = originalHeight - data.originalHeight = originalWidth - } - } - callback(img, data) - }, - file, - data - ) - } - /** * Determines if the image requires orientation. * @@ -131,6 +104,33 @@ Exif orientation values to correctly display the letter F: ) } + loadImage.transform = function (img, options, callback, file, data) { + originalTransform.call( + loadImage, + img, + options, + function (img, data) { + if (data) { + var exifOrientation = data.exif && data.exif.get('Orientation') + if ( + loadImage.orientation && + exifOrientation > 4 && + exifOrientation < 9 + ) { + // Automatic image orientation switched image dimensions + var originalWidth = data.originalWidth + var originalHeight = data.originalHeight + data.originalWidth = originalHeight + data.originalHeight = originalWidth + } + } + callback(img, data) + }, + file, + data + ) + } + // Transforms coordinate and dimension options // based on the given orientation option: loadImage.getTransformedOptions = function (img, opts, data) { From 212a3a3dcc138da248163795e2fa9221b3d4c614 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Wed, 22 Apr 2020 23:35:29 +0900 Subject: [PATCH 062/201] Arrange Exif orientation visualization vertically. --- js/load-image-orientation.js | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index edddb7c..f700df1 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -10,16 +10,31 @@ */ /* - Exif orientation values to correctly display the letter F: - 1 2 3 4 5 6 7 8 + 1 2 + ██████ ██████ + ██ ██ + ████ ████ + ██ ██ + ██ ██ + + 3 4 + ██ ██ + ██ ██ + ████ ████ + ██ ██ + ██████ ██████ + + 5 6 +██████████ ██ +██ ██ ██ ██ +██ ██████████ -██████ ██████ ██ ██ ██████████ ██ ██ ██████████ -██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -████ ████ ████ ████ ██ ██████████ ██████████ ██ -██ ██ ██ ██ -██ ██ ██████ ██████ + 7 8 + ██ ██████████ + ██ ██ ██ ██ +██████████ ██ */ From 7e5f90b8c623bcdb2088715af89686f2ccb877b2 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Wed, 22 Apr 2020 23:36:38 +0900 Subject: [PATCH 063/201] Update orientation requirements for canvas/meta. --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 865156c..75d87c7 100644 --- a/README.md +++ b/README.md @@ -332,11 +332,15 @@ an `integer` in the range of `1` to `8` or the boolean value `true`. When set to `true`, it will set the orientation value based on the EXIF data of the image, which will be parsed automatically if the exif library is available. -Setting `orientation` to an integer in the range of `2` to `8` enables the -`canvas` option. Setting `orientation` to `true` enables the `canvas` and `meta` options, unless the browser supports automatic image orientation (see -[browser support for image-orientation](https://caniuse.com/#feat=css-image-orientation)). +[browser support for image-orientation](https://caniuse.com/#feat=css-image-orientation)). +Setting `orientation` to `1` enables the `canvas` and `meta` options if the +browser does support automatic image orientation (to allow reset of the +orientation). +Setting `orientation` to an integer in the range of `2` to `8` always enables +the `canvas` option and also enables the `meta` option if the browser supports +automatic image orientation (again to allow reset). ### meta From 0f65d7d1241dc0f0463a531e612a5b56c9e856da Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Wed, 22 Apr 2020 23:38:06 +0900 Subject: [PATCH 064/201] Add Exif orientation visualization to the README. --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index 75d87c7..a13ac05 100644 --- a/README.md +++ b/README.md @@ -332,6 +332,34 @@ an `integer` in the range of `1` to `8` or the boolean value `true`. When set to `true`, it will set the orientation value based on the EXIF data of the image, which will be parsed automatically if the exif library is available. +Exif orientation values to correctly display the letter F: + +``` + 1 2 + ██████ ██████ + ██ ██ + ████ ████ + ██ ██ + ██ ██ + + 3 4 + ██ ██ + ██ ██ + ████ ████ + ██ ██ + ██████ ██████ + + 5 6 +██████████ ██ +██ ██ ██ ██ +██ ██████████ + + 7 8 + ██ ██████████ + ██ ██ ██ ██ +██████████ ██ +``` + Setting `orientation` to `true` enables the `canvas` and `meta` options, unless the browser supports automatic image orientation (see [browser support for image-orientation](https://caniuse.com/#feat=css-image-orientation)). From 14b599e924979e43f8f5d75e3afde4752aea5ac9 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Thu, 23 Apr 2020 00:32:05 +0900 Subject: [PATCH 065/201] Simplify original dimensions normalization. --- js/load-image-orientation.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index f700df1..30833de 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -126,12 +126,9 @@ Exif orientation values to correctly display the letter F: options, function (img, data) { if (data) { - var exifOrientation = data.exif && data.exif.get('Orientation') - if ( - loadImage.orientation && - exifOrientation > 4 && - exifOrientation < 9 - ) { + var autoOrientation = + loadImage.orientation && data.exif && data.exif.get('Orientation') + if (autoOrientation > 4 && autoOrientation < 9) { // Automatic image orientation switched image dimensions var originalWidth = data.originalWidth var originalHeight = data.originalHeight From f088760e7b29c88f75e622e97b2a937491a2fc60 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 26 Apr 2020 18:13:32 +0900 Subject: [PATCH 066/201] Normalize EXIF test names spelling. --- test/test.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/test.js b/test/test.js index 84b4a4b..33ed5f8 100644 --- a/test/test.js +++ b/test/test.js @@ -1031,7 +1031,7 @@ }) describe('Metadata', function () { - it('Parse Exif tags', function (done) { + it('Parse EXIF tags', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.exif).to.be.ok expect(data.exif.get('Orientation')).to.equal(6) @@ -1039,7 +1039,7 @@ }) }) - it('Do not parse Exif tags if disabled', function (done) { + it('Do not parse EXIF tags if disabled', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1050,7 +1050,7 @@ ) }) - it('Parse Exif tag offsets', function (done) { + it('Parse EXIF tag offsets', function (done) { loadImage.parseMetaData(blobJPEG, function (data) { expect(data.exifOffsets).to.be.ok expect(data.exifOffsets.get('Orientation')).to.equal(0x16) @@ -1060,7 +1060,7 @@ }) }) - it('Do not parse Exif tag offsets if disabled', function (done) { + it('Do not parse EXIF tag offsets if disabled', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1071,7 +1071,7 @@ ) }) - it('Only parse included Exif tags', function (done) { + it('Only parse included EXIF tags', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1091,7 +1091,7 @@ ) }) - it('Do not parse excluded Exif tags', function (done) { + it('Do not parse excluded EXIF tags', function (done) { loadImage.parseMetaData( blobJPEG, function (data) { @@ -1236,7 +1236,7 @@ ).to.be.ok }) - it('Write Exif Orientation tag and replace image head', function (done) { + it('Write EXIF Orientation tag and replace image head', function (done) { loadImage( blobJPEG, function (img, data) { @@ -1245,7 +1245,7 @@ expect(data.exif.get('Orientation')).to.equal(6) expect(data.iptc).to.be.ok expect(data.iptc.get('ObjectName')).to.equal('blueimp.net') - // Reset Exif Orientation data: + // Reset EXIF Orientation data: loadImage.writeExifData(data.imageHead, data, 'Orientation', 1) img.toBlob(function (blob) { loadImage.replaceHead(blob, data.imageHead, function (newBlob) { From 001fe7fcf345d1fb7e5a8faa9545a7eb09da5c94 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 26 Apr 2020 18:15:07 +0900 Subject: [PATCH 067/201] Test functions via instanceOf method. --- test/test.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/test.js b/test/test.js index 33ed5f8..64899a2 100644 --- a/test/test.js +++ b/test/test.js @@ -91,8 +91,8 @@ it('Return an object with onload and onerror methods', function () { var img = loadImage(blobGIF, function () {}) expect(img).to.be.an.instanceOf(Object) - expect(img.onload).to.be.a('function') - expect(img.onerror).to.be.a('function') + expect(img.onload).to.be.an.instanceOf(Function) + expect(img.onerror).to.be.an.instanceOf(Function) }) it('Load image url', function (done) { @@ -984,7 +984,7 @@ loadImage( blobGIF, function (img) { - expect(img.getContext).to.be.ok + expect(img.getContext).to.be.an.instanceOf(Function) expect(img.nodeName.toLowerCase()).to.equal('canvas') done() }, @@ -998,7 +998,7 @@ loadImage( blobGIF, function (img) { - expect(img.getContext).to.be.ok + expect(img.getContext).to.be.an.instanceOf(Function) expect(img.nodeName.toLowerCase()).to.equal('canvas') expect(img.width).to.equal(30) expect(img.height).to.equal(20) @@ -1018,7 +1018,7 @@ img = loadImage.scale(img, { maxWidth: 30 }) - expect(img.getContext).to.be.ok + expect(img.getContext).to.be.an.instanceOf(Function) expect(img.nodeName.toLowerCase()).to.equal('canvas') expect(img.width).to.equal(30) expect(img.height).to.equal(20) From 996dbb1bcfc60238961619be7a1889d8d409e383 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 26 Apr 2020 18:18:04 +0900 Subject: [PATCH 068/201] Remove unnecessary destX/destY arguments. --- js/load-image-scale.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/js/load-image-scale.js b/js/load-image-scale.js index 53fe5e6..4f6ab50 100644 --- a/js/load-image-scale.js +++ b/js/load-image-scale.js @@ -82,8 +82,6 @@ sourceY, sourceWidth, sourceHeight, - destX, - destY, destWidth, destHeight, options @@ -100,8 +98,8 @@ sourceY, sourceWidth, sourceHeight, - destX, - destY, + 0, + 0, destWidth, destHeight ) @@ -252,8 +250,6 @@ sourceY, sourceWidth, sourceHeight, - 0, - 0, canvas.width, canvas.height, options @@ -273,8 +269,6 @@ 0, sourceWidth, sourceHeight, - 0, - 0, sourceWidth, sourceHeight, options @@ -291,8 +285,6 @@ sourceY, sourceWidth, sourceHeight, - 0, - 0, destWidth, destHeight, options From 8776ebe52bbe9509ba4407a0ce873bda51639680 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 26 Apr 2020 18:22:33 +0900 Subject: [PATCH 069/201] Limit pixel ratio handling to scaling library. --- js/load-image-orientation.js | 4 ---- js/load-image-scale.js | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/js/load-image-orientation.js b/js/load-image-orientation.js index 30833de..d5e215e 100644 --- a/js/load-image-orientation.js +++ b/js/load-image-orientation.js @@ -235,13 +235,9 @@ Exif orientation values to correctly display the letter F: var ctx = canvas.getContext('2d') var width = canvas.width var height = canvas.height - var styleWidth = canvas.style.width - var styleHeight = canvas.style.height if (orientation > 4) { canvas.width = height canvas.height = width - canvas.style.width = styleHeight - canvas.style.height = styleWidth } switch (orientation) { case 2: diff --git a/js/load-image-scale.js b/js/load-image-scale.js index 4f6ab50..e398b13 100644 --- a/js/load-image-scale.js +++ b/js/load-image-scale.js @@ -220,18 +220,14 @@ } if (useCanvas) { pixelRatio = options.pixelRatio - if (pixelRatio > 1) { - if (parseInt(img.style.width, 10) === width / pixelRatio) { - // Source image is already scaled according to device pixel ratio - canvas.style.width = destWidth / pixelRatio + 'px' - canvas.style.height = destHeight / pixelRatio + 'px' - } else { - canvas.style.width = destWidth + 'px' - canvas.style.height = destHeight + 'px' - destWidth *= pixelRatio - destHeight *= pixelRatio - canvas.getContext('2d').scale(pixelRatio, pixelRatio) - } + if ( + pixelRatio > 1 && + // Check if image has not yet device pixel ratio applied: + parseInt(img.style.width, 10) !== width / pixelRatio + ) { + destWidth *= pixelRatio + destHeight *= pixelRatio + canvas.getContext('2d').scale(pixelRatio, pixelRatio) } downsamplingRatio = options.downsamplingRatio if ( @@ -278,6 +274,10 @@ canvas.width = destWidth canvas.height = destHeight loadImage.transformCoordinates(canvas, options, data) + if (pixelRatio > 1) { + canvas.style.width = canvas.width / pixelRatio + 'px' + canvas.style.height = canvas.height / pixelRatio + 'px' + } return loadImage.renderImageToCanvas( canvas, img, From 4c79652b5357fdf7fd5ce0b3f45c386e4e732719 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Sun, 26 Apr 2020 22:24:44 +0900 Subject: [PATCH 070/201] Fix IE10 ArrayBuffer.slice workaround. To use imageHead as DataView argument (e.g. for writing EXIF data), it needs to be a buffer. --- js/load-image-meta.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/js/load-image-meta.js b/js/load-image-meta.js index 63177d3..21c9961 100644 --- a/js/load-image-meta.js +++ b/js/load-image-meta.js @@ -96,6 +96,8 @@ var markerLength var parsers var i + var arr1 + var arr2 // Check for the JPEG marker (0xffd8): if (dataView.getUint16(0) === 0xffd8) { while (offset < maxOffset) { @@ -144,9 +146,12 @@ if (buffer.slice) { data.imageHead = buffer.slice(0, headLength) } else { - // Workaround for IE10, which does not yet - // support ArrayBuffer.slice: - data.imageHead = new Uint8Array(buffer).subarray(0, headLength) + // Workaround for IE10, which does not support + // ArrayBuffer.slice: + arr1 = new Uint8Array(buffer, 0, headLength) + arr2 = new Uint8Array(headLength) + arr2.set(arr1) + data.imageHead = arr2.buffer } } } else { From 681143cfb196bfeade745252fcc67fa04bb87d80 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 28 Apr 2020 19:40:14 +0900 Subject: [PATCH 071/201] Demo: take pixelRatio into account when cropping. Use contain:true instead of specifying both minWidth and maxWidth. Remove unnecessary downsamplingRatio option for cropping. --- js/demo/demo.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/js/demo/demo.js b/js/demo/demo.js index b42cdcd..fe1984c 100644 --- a/js/demo/demo.js +++ b/js/demo/demo.js @@ -250,10 +250,9 @@ $(function () { top: coordinates.y * pixelRatio, sourceWidth: coordinates.w * pixelRatio, sourceHeight: coordinates.h * pixelRatio, - minWidth: result.width(), - maxWidth: result.width(), + maxWidth: result.width() * pixelRatio, + contain: true, pixelRatio: pixelRatio, - downsamplingRatio: 0.5 }) ) coordinates = null From b86c22f62000513963980180454bb62901fba592 Mon Sep 17 00:00:00 2001 From: Sebastian Tschan Date: Tue, 28 Apr 2020 19:41:03 +0900 Subject: [PATCH 072/201] Demo: add orientation selector. --- index.html | 18 ++++++++++++++++++ js/demo/demo.js | 14 +++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index bc619ec..7192a00 100644 --- a/index.html +++ b/index.html @@ -80,6 +80,24 @@

    Select an image file

    Or drag & drop an image file onto this webpage.

    +

    + + +

    Result

    Select an image file

    +

    + + +

    Result

    Result

    API.

    -