diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 4ec7c35..6179760 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,10 +4,8 @@
-
+
-
-
@@ -24,7 +22,7 @@
@@ -43,122 +41,136 @@
"state": "OPEN"
}
}
- {
+ "prStates": [
{
- "id": {
- "id": "PR_kwDOMJIfts51PkS9",
- "number": 22
+ "id": {
+ "id": "PR_kwDOMJIfts51PkS9",
+ "number": 22
},
- "lastSeen": 1741207144695
+ "lastSeen": 1741207144695
},
{
- "id": {
- "id": "PR_kwDOMJIfts6NiNYl",
- "number": 32
+ "id": {
+ "id": "PR_kwDOMJIfts6NiNYl",
+ "number": 32
},
- "lastSeen": 1741209723869
+ "lastSeen": 1741209723869
},
{
- "id": {
- "id": "PR_kwDOMJIfts6Nheyd",
- "number": 31
+ "id": {
+ "id": "PR_kwDOMJIfts6Nheyd",
+ "number": 31
},
- "lastSeen": 1741213371410
+ "lastSeen": 1741213371410
},
{
- "id": {
- "id": "PR_kwDOMJIfts6NmRBs",
- "number": 33
+ "id": {
+ "id": "PR_kwDOMJIfts6NmRBs",
+ "number": 33
},
- "lastSeen": 1741282429036
+ "lastSeen": 1741282429036
},
{
- "id": {
- "id": "PR_kwDOMJIfts5zyFTs",
- "number": 15
+ "id": {
+ "id": "PR_kwDOMJIfts5zyFTs",
+ "number": 15
},
- "lastSeen": 1741535540953
+ "lastSeen": 1741535540953
},
{
- "id": {
- "id": "PR_kwDOMJIfts6QQB3c",
- "number": 59
+ "id": {
+ "id": "PR_kwDOMJIfts6QQB3c",
+ "number": 59
},
- "lastSeen": 1743018960900
+ "lastSeen": 1743018960900
},
{
- "id": {
- "id": "PR_kwDOMJIfts6QMPEg",
- "number": 58
+ "id": {
+ "id": "PR_kwDOMJIfts6QMPEg",
+ "number": 58
},
- "lastSeen": 1743019452983
+ "lastSeen": 1743019452983
},
{
- "id": {
- "id": "PR_kwDOMJIfts6QZvRI",
- "number": 61
+ "id": {
+ "id": "PR_kwDOMJIfts6QZvRI",
+ "number": 61
},
- "lastSeen": 1743103196866
+ "lastSeen": 1743103196866
},
{
- "id": {
- "id": "PR_kwDOMJIfts6QqPrQ",
- "number": 73
+ "id": {
+ "id": "PR_kwDOMJIfts6QqPrQ",
+ "number": 73
},
- "lastSeen": 1743265865001
+ "lastSeen": 1743265865001
},
{
- "id": {
- "id": "PR_kwDOMJIfts6Qp5nI",
- "number": 72
+ "id": {
+ "id": "PR_kwDOMJIfts6Qp5nI",
+ "number": 72
},
- "lastSeen": 1743338472110
+ "lastSeen": 1743338472110
},
{
- "id": {
- "id": "PR_kwDOMJIfts6QsjlS",
- "number": 76
+ "id": {
+ "id": "PR_kwDOMJIfts6QsjlS",
+ "number": 76
},
- "lastSeen": 1743352150953
+ "lastSeen": 1743352150953
},
{
- "id": {
- "id": "PR_kwDOMJIfts6Q0JBe",
- "number": 82
+ "id": {
+ "id": "PR_kwDOMJIfts6Q0JBe",
+ "number": 82
},
- "lastSeen": 1743470267269
+ "lastSeen": 1743470267269
},
{
- "id": {
- "id": "PR_kwDOMJIfts6UE9-x",
- "number": 102
+ "id": {
+ "id": "PR_kwDOMJIfts6UE9-x",
+ "number": 102
},
- "lastSeen": 1747171977348
+ "lastSeen": 1747171977348
},
{
- "id": {
- "id": "PR_kwDOMJIfts6XPua_",
- "number": 117
+ "id": {
+ "id": "PR_kwDOMJIfts6XPua_",
+ "number": 117
},
- "lastSeen": 1747929835864
+ "lastSeen": 1747929835864
},
{
- "id": {
- "id": "PR_kwDOMJIfts6XY-mZ",
- "number": 119
+ "id": {
+ "id": "PR_kwDOMJIfts6XY-mZ",
+ "number": 119
},
- "lastSeen": 1748028108508
+ "lastSeen": 1748028108508
},
{
- "id": {
- "id": "PR_kwDOMJIfts6Xdz4n",
- "number": 120
+ "id": {
+ "id": "PR_kwDOMJIfts6Xdz4n",
+ "number": 120
},
- "lastSeen": 1748282672214
+ "lastSeen": 1748282672214
+ },
+ {
+ "id": {
+ "id": "PR_kwDOMJIfts6X_zxl",
+ "number": 131
+ },
+ "lastSeen": 1748881279494
+ },
+ {
+ "id": {
+ "id": "PR_kwDOMJIfts6XsHfL",
+ "number": 128
+ },
+ "lastSeen": 1748881318360
}
]
-}]]>
+}
{
"selectedUrlAndAccountId": {
"url": "https://github.com/iib0011/omni-tools.git",
@@ -187,56 +199,56 @@
- {
+ "keyToString": {
+ "ASKED_ADD_EXTERNAL_FILES": "true",
+ "ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
+ "Docker.Dockerfile build.executor": "Run",
+ "Docker.Dockerfile.executor": "Run",
+ "Playwright.Create transparent PNG.should make png color transparent.executor": "Run",
+ "Playwright.JoinText Component.executor": "Run",
+ "Playwright.JoinText Component.should merge text pieces with specified join character.executor": "Run",
+ "RunOnceActivity.OpenProjectViewOnStart": "true",
+ "RunOnceActivity.ShowReadmeOnStart": "true",
+ "RunOnceActivity.git.unshallow": "true",
+ "Vitest.compute function (1).executor": "Run",
+ "Vitest.compute function.executor": "Run",
+ "Vitest.mergeText.executor": "Run",
+ "Vitest.mergeText.should merge lines and preserve blank lines when deleteBlankLines is false.executor": "Run",
+ "Vitest.mergeText.should merge lines, preserve blank lines and trailing spaces when both deleteBlankLines and deleteTrailingSpaces are false.executor": "Run",
+ "Vitest.parsePageRanges.executor": "Run",
+ "Vitest.removeDuplicateLines function.executor": "Run",
+ "Vitest.removeDuplicateLines function.newlines option.executor": "Run",
+ "Vitest.removeDuplicateLines function.newlines option.should filter newlines when newlines is set to filter.executor": "Run",
+ "Vitest.replaceText function (regexp mode).should return the original text when passed an invalid regexp.executor": "Run",
+ "Vitest.replaceText function.executor": "Run",
+ "Vitest.timeBetweenDates.executor": "Run",
+ "git-widget-placeholder": "#131 on fork/ARRY7686/main",
+ "ignore.virus.scanning.warn.message": "true",
+ "kotlin-language-version-configured": "true",
+ "last_opened_file_path": "C:/Users/Ibrahima/IdeaProjects/omni-tools/src",
+ "node.js.detected.package.eslint": "true",
+ "node.js.detected.package.tslint": "true",
+ "node.js.selected.package.eslint": "(autodetect)",
+ "node.js.selected.package.tslint": "(autodetect)",
+ "nodejs_package_manager_path": "npm",
+ "npm.build.executor": "Run",
+ "npm.dev.executor": "Run",
+ "npm.lint.executor": "Run",
+ "npm.prebuild.executor": "Run",
+ "npm.script:create:tool.executor": "Run",
+ "npm.test.executor": "Run",
+ "npm.test:e2e.executor": "Run",
+ "npm.test:e2e:run.executor": "Run",
+ "prettierjs.PrettierConfiguration.Package": "C:\\Users\\Ibrahima\\IdeaProjects\\omni-tools\\node_modules\\prettier",
+ "project.structure.last.edited": "Problems",
+ "project.structure.proportion": "0.0",
+ "project.structure.side.proportion": "0.2",
+ "settings.editor.selected.configurable": "refactai_advanced_settings",
+ "ts.external.directory.path": "C:\\Users\\Ibrahima\\IdeaProjects\\omni-tools\\node_modules\\typescript\\lib",
+ "vue.rearranger.settings.migration": "true"
}
-}]]>
+}
@@ -889,7 +902,6 @@
-
@@ -914,7 +926,8 @@
-
+
+
diff --git a/package-lock.json b/package-lock.json
index 4241de4..9f5b3c2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -30,6 +30,7 @@
"formik": "^2.4.6",
"jimp": "^0.22.12",
"js-quantities": "^1.8.0",
+ "jszip": "^3.10.1",
"lint-staged": "^15.4.3",
"lodash": "^4.17.21",
"mime": "^4.0.6",
@@ -38,6 +39,7 @@
"notistack": "^3.0.1",
"omggif": "^1.0.10",
"pdf-lib": "^1.17.1",
+ "pdfjs-dist": "^5.2.133",
"playwright": "^1.45.0",
"rc-slider": "^11.1.8",
"react": "^18.3.1",
@@ -2323,6 +2325,188 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
},
+ "node_modules/@napi-rs/canvas": {
+ "version": "0.1.70",
+ "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.70.tgz",
+ "integrity": "sha512-nD6NGa4JbNYSZYsTnLGrqe9Kn/lCkA4ybXt8sx5ojDqZjr2i0TWAHxx/vhgfjX+i3hCdKWufxYwi7CfXqtITSA==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">= 10"
+ },
+ "optionalDependencies": {
+ "@napi-rs/canvas-android-arm64": "0.1.70",
+ "@napi-rs/canvas-darwin-arm64": "0.1.70",
+ "@napi-rs/canvas-darwin-x64": "0.1.70",
+ "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.70",
+ "@napi-rs/canvas-linux-arm64-gnu": "0.1.70",
+ "@napi-rs/canvas-linux-arm64-musl": "0.1.70",
+ "@napi-rs/canvas-linux-riscv64-gnu": "0.1.70",
+ "@napi-rs/canvas-linux-x64-gnu": "0.1.70",
+ "@napi-rs/canvas-linux-x64-musl": "0.1.70",
+ "@napi-rs/canvas-win32-x64-msvc": "0.1.70"
+ }
+ },
+ "node_modules/@napi-rs/canvas-android-arm64": {
+ "version": "0.1.70",
+ "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.70.tgz",
+ "integrity": "sha512-I/YOuQ0wbkVYxVaYtCgN42WKTYxNqFA0gTcTrHIGG1jfpDSyZWII/uHcjOo4nzd19io6Y4+/BqP8E5hJgf9OmQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/canvas-darwin-arm64": {
+ "version": "0.1.70",
+ "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.70.tgz",
+ "integrity": "sha512-4pPGyXetHIHkw2TOJHujt3mkCP8LdDu8+CT15ld9Id39c752RcI0amDHSuMLMQfAjvusA9B5kKxazwjMGjEJpQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/canvas-darwin-x64": {
+ "version": "0.1.70",
+ "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.70.tgz",
+ "integrity": "sha512-+2N6Os9LbkmDMHL+raknrUcLQhsXzc5CSXRbXws9C3pv/mjHRVszQ9dhFUUe9FjfPhCJznO6USVdwOtu7pOrzQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": {
+ "version": "0.1.70",
+ "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.70.tgz",
+ "integrity": "sha512-QjscX9OaKq/990sVhSMj581xuqLgiaPVMjjYvWaCmAJRkNQ004QfoSMEm3FoTqM4DRoquP8jvuEXScVJsc1rqQ==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/canvas-linux-arm64-gnu": {
+ "version": "0.1.70",
+ "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.70.tgz",
+ "integrity": "sha512-LNakMOwwqwiHIwMpnMAbFRczQMQ7TkkMyATqFCOtUJNlE6LPP/QiUj/mlFrNbUn/hctqShJ60gWEb52ZTALbVw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/canvas-linux-arm64-musl": {
+ "version": "0.1.70",
+ "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.70.tgz",
+ "integrity": "sha512-wBTOllEYNfJCHOdZj9v8gLzZ4oY3oyPX8MSRvaxPm/s7RfEXxCyZ8OhJ5xAyicsDdbE5YBZqdmaaeP5+xKxvtg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/canvas-linux-riscv64-gnu": {
+ "version": "0.1.70",
+ "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.70.tgz",
+ "integrity": "sha512-GVUUPC8TuuFqHip0rxHkUqArQnlzmlXmTEBuXAWdgCv85zTCFH8nOHk/YCF5yo0Z2eOm8nOi90aWs0leJ4OE5Q==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/canvas-linux-x64-gnu": {
+ "version": "0.1.70",
+ "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.70.tgz",
+ "integrity": "sha512-/kvUa2lZRwGNyfznSn5t1ShWJnr/m5acSlhTV3eXECafObjl0VBuA1HJw0QrilLpb4Fe0VLywkpD1NsMoVDROQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/canvas-linux-x64-musl": {
+ "version": "0.1.70",
+ "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.70.tgz",
+ "integrity": "sha512-aqlv8MLpycoMKRmds7JWCfVwNf1fiZxaU7JwJs9/ExjTD8lX2KjsO7CTeAj5Cl4aEuzxUWbJPUUE2Qu9cZ1vfg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/canvas-win32-x64-msvc": {
+ "version": "0.1.70",
+ "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.70.tgz",
+ "integrity": "sha512-Q9QU3WIpwBTVHk4cPfBjGHGU4U0llQYRXgJtFtYqqGNEOKVN4OT6PQ+ve63xwIPODMpZ0HHyj/KLGc9CWc3EtQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -4587,6 +4771,12 @@
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
},
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "license": "MIT"
+ },
"node_modules/cosmiconfig": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
@@ -6388,6 +6578,12 @@
"integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==",
"license": "MIT"
},
+ "node_modules/immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
+ "license": "MIT"
+ },
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -7119,6 +7315,54 @@
"node": ">=4.0"
}
},
+ "node_modules/jszip": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
+ "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
+ "license": "(MIT OR GPL-3.0-or-later)",
+ "dependencies": {
+ "lie": "~3.3.0",
+ "pako": "~1.0.2",
+ "readable-stream": "~2.3.6",
+ "setimmediate": "^1.0.5"
+ }
+ },
+ "node_modules/jszip/node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "license": "MIT"
+ },
+ "node_modules/jszip/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "license": "MIT",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/jszip/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "license": "MIT"
+ },
+ "node_modules/jszip/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -7150,6 +7394,15 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/lie": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+ "license": "MIT",
+ "dependencies": {
+ "immediate": "~3.0.5"
+ }
+ },
"node_modules/lilconfig": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
@@ -8386,6 +8639,18 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"license": "0BSD"
},
+ "node_modules/pdfjs-dist": {
+ "version": "5.2.133",
+ "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.2.133.tgz",
+ "integrity": "sha512-abE6ZWDxztt+gGFzfm4bX2ggfxUk9wsDEoFzIJm9LozaY3JdXR7jyLK4Bjs+XLXplCduuWS1wGhPC4tgTn/kzg==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=20.16.0 || >=22.3.0"
+ },
+ "optionalDependencies": {
+ "@napi-rs/canvas": "^0.1.67"
+ }
+ },
"node_modules/peek-readable": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz",
@@ -8778,10 +9043,17 @@
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+ "license": "MIT",
"engines": {
"node": ">= 0.6.0"
}
},
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "license": "MIT"
+ },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -9426,6 +9698,12 @@
"node": ">= 0.4"
}
},
+ "node_modules/setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
+ "license": "MIT"
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
diff --git a/package.json b/package.json
index 1bebbe8..7e43cbe 100644
--- a/package.json
+++ b/package.json
@@ -47,6 +47,7 @@
"formik": "^2.4.6",
"jimp": "^0.22.12",
"js-quantities": "^1.8.0",
+ "jszip": "^3.10.1",
"lint-staged": "^15.4.3",
"lodash": "^4.17.21",
"mime": "^4.0.6",
@@ -55,6 +56,7 @@
"notistack": "^3.0.1",
"omggif": "^1.0.10",
"pdf-lib": "^1.17.1",
+ "pdfjs-dist": "^5.2.133",
"playwright": "^1.45.0",
"rc-slider": "^11.1.8",
"react": "^18.3.1",
diff --git a/src/components/ToolContent.tsx b/src/components/ToolContent.tsx
index 703128e..9e261ae 100644
--- a/src/components/ToolContent.tsx
+++ b/src/components/ToolContent.tsx
@@ -38,25 +38,25 @@ const FormikListenerComponent = ({
return null; // This component doesn't render anything
};
-interface ToolContentProps extends ToolComponentProps {
+interface ToolContentProps extends ToolComponentProps {
inputComponent?: ReactNode;
resultComponent?: ReactNode;
renderCustomInput?: (
- values: T,
+ values: Options,
setFieldValue: (fieldName: string, value: any) => void
) => ReactNode;
- initialValues: T;
- getGroups: GetGroupsType | null;
- compute: (optionsValues: T, input: I) => void;
+ initialValues: Options;
+ getGroups: GetGroupsType | null;
+ compute: (optionsValues: Options, input: Input) => void;
toolInfo?: {
title: string;
description?: string;
};
- input?: I;
- exampleCards?: CardExampleType[];
- setInput?: React.Dispatch>;
+ input?: Input;
+ exampleCards?: CardExampleType[];
+ setInput?: React.Dispatch>;
validationSchema?: any;
- onValuesChange?: (values: T) => void;
+ onValuesChange?: (values: Options) => void;
verticalGroups?: boolean;
}
diff --git a/src/pages/tools/pdf/index.ts b/src/pages/tools/pdf/index.ts
index 0e2627b..c5f294f 100644
--- a/src/pages/tools/pdf/index.ts
+++ b/src/pages/tools/pdf/index.ts
@@ -4,11 +4,13 @@ import { meta as mergePdf } from './merge-pdf/meta';
import { DefinedTool } from '@tools/defineTool';
import { tool as compressPdfTool } from './compress-pdf/meta';
import { tool as protectPdfTool } from './protect-pdf/meta';
+import { meta as pdfToEpub } from './pdf-to-epub/meta';
export const pdfTools: DefinedTool[] = [
splitPdfMeta,
pdfRotatePdf,
compressPdfTool,
protectPdfTool,
- mergePdf
+ mergePdf,
+ pdfToEpub
];
diff --git a/src/pages/tools/pdf/pdf-to-epub/index.tsx b/src/pages/tools/pdf/pdf-to-epub/index.tsx
new file mode 100644
index 0000000..952a716
--- /dev/null
+++ b/src/pages/tools/pdf/pdf-to-epub/index.tsx
@@ -0,0 +1,58 @@
+import { useState, useEffect } from 'react';
+import ToolFileResult from '@components/result/ToolFileResult';
+import ToolContent from '@components/ToolContent';
+import { ToolComponentProps } from '@tools/defineTool';
+import ToolPdfInput from '@components/input/ToolPdfInput';
+import { convertPdfToEpub } from './service';
+
+export default function PdfToEpub({ title }: ToolComponentProps) {
+ const [input, setInput] = useState(null);
+ const [result, setResult] = useState(null);
+ const [isProcessing, setIsProcessing] = useState(false);
+
+ const compute = async (options: {}, input: File | null) => {
+ if (!input) return;
+ try {
+ setIsProcessing(true);
+ setResult(null);
+ const epub = await convertPdfToEpub(input);
+ setResult(epub);
+ } catch (error) {
+ console.error('Failed to convert PDF to EPUB:', error);
+ } finally {
+ setIsProcessing(false);
+ }
+ };
+
+ return (
+ setInput(file)}
+ accept={['application/pdf']}
+ title={'Input PDF'}
+ />
+ }
+ getGroups={null}
+ resultComponent={
+
+ }
+ toolInfo={{
+ title: 'How to Use PDF to EPUB?',
+ description: `Upload a PDF file and this tool will convert it into an EPUB format, suitable for most e-reader devices.`
+ }}
+ />
+ );
+}
diff --git a/src/pages/tools/pdf/pdf-to-epub/meta.ts b/src/pages/tools/pdf/pdf-to-epub/meta.ts
new file mode 100644
index 0000000..7f24758
--- /dev/null
+++ b/src/pages/tools/pdf/pdf-to-epub/meta.ts
@@ -0,0 +1,13 @@
+import { defineTool } from '@tools/defineTool';
+import { lazy } from 'react';
+
+export const meta = defineTool('pdf', {
+ name: 'PDF to EPUB',
+ shortDescription: 'Convert PDF files to EPUB format',
+ description:
+ 'Transform PDF documents into EPUB files for better e-reader compatibility.',
+ icon: 'material-symbols:import-contacts',
+ component: lazy(() => import('./index')),
+ keywords: ['pdf', 'epub', 'convert', 'ebook'],
+ path: 'pdf-to-epub'
+});
diff --git a/src/pages/tools/pdf/pdf-to-epub/service.ts b/src/pages/tools/pdf/pdf-to-epub/service.ts
new file mode 100644
index 0000000..5e0207a
--- /dev/null
+++ b/src/pages/tools/pdf/pdf-to-epub/service.ts
@@ -0,0 +1,144 @@
+import * as pdfjsLib from 'pdfjs-dist';
+import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.min?url';
+import JSZip from 'jszip';
+
+// Set worker source for PDF.js
+pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;
+
+function formatTextToParagraphs(raw: string): string {
+ return raw
+ .split(/\n{2,}|\r{2,}/g) // Split on double line breaks
+ .map((p) => p.trim())
+ .filter((p) => p.length > 0)
+ .map((p) => `${p.replace(/\n/g, ' ')}
`)
+ .join('\n');
+}
+
+export async function convertPdfToEpub(pdfFile: File): Promise {
+ const arrayBuffer = await pdfFile.arrayBuffer();
+
+ const loadingTask = pdfjsLib.getDocument({ data: arrayBuffer });
+ const pdfDoc = await loadingTask.promise;
+ const numPages = pdfDoc.numPages;
+
+ // Extracting text
+ const pages: string[] = [];
+ for (let i = 1; i <= numPages; i++) {
+ const page = await pdfDoc.getPage(i);
+ const textContent = await page.getTextContent();
+
+ const pageText = textContent.items.map((item: any) => item.str).join('\n'); // Preserve line breaks better
+
+ pages.push(pageText);
+ }
+
+ const zip = new JSZip();
+
+ zip.file('mimetype', 'application/epub+zip', { compression: 'STORE' });
+
+ const metaInf = zip.folder('META-INF');
+ metaInf!.file(
+ 'container.xml',
+ `
+
+
+
+
+`
+ );
+
+ const oebps = zip.folder('OEBPS');
+ const bookTitle = pdfFile.name.replace(/\.pdf$/i, '');
+
+ const contentOpf = `
+
+
+ ${bookTitle}
+ Converted by omni-tools
+ ${Date.now()}
+ en
+
+
+
+ ${pages
+ .map(
+ (_, index) =>
+ ` `
+ )
+ .join('\n ')}
+
+
+ ${pages
+ .map((_, index) => ``)
+ .join('\n ')}
+
+`;
+
+ oebps!.file('content.opf', contentOpf);
+
+ const tocNcx = `
+
+
+
+
+
+
+
+
+ ${bookTitle}
+
+
+ ${pages
+ .map(
+ (_, index) =>
+ `
+
+ Page ${index + 1}
+
+
+ `
+ )
+ .join('\n ')}
+
+`;
+
+ oebps!.file('toc.ncx', tocNcx);
+
+ pages.forEach((pageText, index) => {
+ const formattedBody = formatTextToParagraphs(pageText);
+
+ const chapterXhtml = `
+
+
+
+ Page ${index + 1}
+
+
+
+
+ Page ${index + 1}
+ ${formattedBody}
+
+`;
+
+ oebps!.file(`chapter${index + 1}.xhtml`, chapterXhtml);
+ });
+
+ const epubBuffer = await zip.generateAsync({ type: 'arraybuffer' });
+
+ return new File([epubBuffer], pdfFile.name.replace(/\.pdf$/i, '.epub'), {
+ type: 'application/epub+zip'
+ });
+}