@xiuchang-midscene/shared 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/es/baseDB.mjs +109 -0
- package/dist/es/baseDB.mjs.bak +109 -0
- package/dist/es/build/copy-static.mjs +31 -0
- package/dist/es/build/copy-static.mjs.bak +31 -0
- package/dist/es/build/rspack-config.mjs +4 -0
- package/dist/es/build/rspack-config.mjs.bak +4 -0
- package/dist/es/cli/cli-runner.mjs +140 -0
- package/dist/es/cli/cli-runner.mjs.bak +140 -0
- package/dist/es/cli/index.mjs +2 -0
- package/dist/es/cli/index.mjs.bak +2 -0
- package/dist/es/common.mjs +37 -0
- package/dist/es/common.mjs.bak +37 -0
- package/dist/es/constants/example-code.mjs +223 -0
- package/dist/es/constants/example-code.mjs.bak +223 -0
- package/dist/es/constants/index.mjs +23 -0
- package/dist/es/constants/index.mjs.bak +23 -0
- package/dist/es/env/basic.mjs +6 -0
- package/dist/es/env/basic.mjs.bak +6 -0
- package/dist/es/env/constants.mjs +70 -0
- package/dist/es/env/constants.mjs.bak +70 -0
- package/dist/es/env/global-config-manager.mjs +94 -0
- package/dist/es/env/global-config-manager.mjs.bak +94 -0
- package/dist/es/env/helper.mjs +43 -0
- package/dist/es/env/helper.mjs.bak +43 -0
- package/dist/es/env/index.mjs +5 -0
- package/dist/es/env/index.mjs.bak +5 -0
- package/dist/es/env/init-debug.mjs +18 -0
- package/dist/es/env/init-debug.mjs.bak +18 -0
- package/dist/es/env/model-config-manager.mjs +79 -0
- package/dist/es/env/model-config-manager.mjs.bak +79 -0
- package/dist/es/env/parse-model-config.mjs +132 -0
- package/dist/es/env/parse-model-config.mjs.bak +132 -0
- package/dist/es/env/types.mjs +220 -0
- package/dist/es/env/types.mjs.bak +220 -0
- package/dist/es/env/utils.mjs +26 -0
- package/dist/es/env/utils.mjs.bak +26 -0
- package/dist/es/extractor/constants.mjs +2 -0
- package/dist/es/extractor/constants.mjs.bak +2 -0
- package/dist/es/extractor/debug.mjs +6 -0
- package/dist/es/extractor/debug.mjs.bak +6 -0
- package/dist/es/extractor/dom-util.mjs +92 -0
- package/dist/es/extractor/dom-util.mjs.bak +92 -0
- package/dist/es/extractor/index.mjs +5 -0
- package/dist/es/extractor/index.mjs.bak +5 -0
- package/dist/es/extractor/locator.mjs +250 -0
- package/dist/es/extractor/locator.mjs.bak +250 -0
- package/dist/es/extractor/tree.mjs +78 -0
- package/dist/es/extractor/tree.mjs.bak +78 -0
- package/dist/es/extractor/util.mjs +245 -0
- package/dist/es/extractor/util.mjs.bak +245 -0
- package/dist/es/extractor/web-extractor.mjs +303 -0
- package/dist/es/extractor/web-extractor.mjs.bak +303 -0
- package/dist/es/img/box-select.mjs +824 -0
- package/dist/es/img/box-select.mjs.bak +824 -0
- package/dist/es/img/canvas-fallback.mjs +238 -0
- package/dist/es/img/canvas-fallback.mjs.bak +238 -0
- package/dist/es/img/get-photon.mjs +45 -0
- package/dist/es/img/get-photon.mjs.bak +45 -0
- package/dist/es/img/get-sharp.mjs +11 -0
- package/dist/es/img/get-sharp.mjs.bak +11 -0
- package/dist/es/img/index.mjs +4 -0
- package/dist/es/img/index.mjs.bak +4 -0
- package/dist/es/img/info.mjs +29 -0
- package/dist/es/img/info.mjs.bak +29 -0
- package/dist/es/img/transform.mjs +295 -0
- package/dist/es/img/transform.mjs.bak +295 -0
- package/dist/es/index.mjs +4 -0
- package/dist/es/index.mjs.bak +4 -0
- package/dist/es/logger.mjs +64 -0
- package/dist/es/logger.mjs.bak +64 -0
- package/dist/es/mcp/base-server.mjs +281 -0
- package/dist/es/mcp/base-server.mjs.bak +281 -0
- package/dist/es/mcp/base-tools.mjs +91 -0
- package/dist/es/mcp/base-tools.mjs.bak +91 -0
- package/dist/es/mcp/chrome-path.mjs +35 -0
- package/dist/es/mcp/chrome-path.mjs.bak +35 -0
- package/dist/es/mcp/index.mjs +7 -0
- package/dist/es/mcp/index.mjs.bak +7 -0
- package/dist/es/mcp/inject-report-html-plugin.mjs +53 -0
- package/dist/es/mcp/inject-report-html-plugin.mjs.bak +53 -0
- package/dist/es/mcp/launcher-helper.mjs +52 -0
- package/dist/es/mcp/launcher-helper.mjs.bak +52 -0
- package/dist/es/mcp/tool-generator.mjs +297 -0
- package/dist/es/mcp/tool-generator.mjs.bak +297 -0
- package/dist/es/mcp/types.mjs +3 -0
- package/dist/es/mcp/types.mjs.bak +3 -0
- package/dist/es/node/fs.mjs +44 -0
- package/dist/es/node/fs.mjs.bak +44 -0
- package/dist/es/node/index.mjs +2 -0
- package/dist/es/node/index.mjs.bak +2 -0
- package/dist/es/node/port.mjs +24 -0
- package/dist/es/node/port.mjs.bak +24 -0
- package/dist/es/oss/demo.mjs +30 -0
- package/dist/es/oss/demo.mjs.bak +30 -0
- package/dist/es/oss/index.mjs +90 -0
- package/dist/es/oss/index.mjs.bak +90 -0
- package/dist/es/polyfills/async-hooks.mjs +2 -0
- package/dist/es/polyfills/async-hooks.mjs.bak +2 -0
- package/dist/es/polyfills/index.mjs +1 -0
- package/dist/es/polyfills/index.mjs.bak +1 -0
- package/dist/es/types/index.mjs +3 -0
- package/dist/es/types/index.mjs.bak +3 -0
- package/dist/es/us-keyboard-layout.mjs +1414 -0
- package/dist/es/us-keyboard-layout.mjs.LICENSE.txt +5 -0
- package/dist/es/us-keyboard-layout.mjs.bak +1414 -0
- package/dist/es/utils.mjs +72 -0
- package/dist/es/utils.mjs.bak +72 -0
- package/dist/es/zod-schema-utils.mjs +54 -0
- package/dist/es/zod-schema-utils.mjs.bak +54 -0
- package/dist/lib/baseDB.js +149 -0
- package/dist/lib/baseDB.js.bak +149 -0
- package/dist/lib/build/copy-static.js +79 -0
- package/dist/lib/build/copy-static.js.bak +79 -0
- package/dist/lib/build/rspack-config.js +38 -0
- package/dist/lib/build/rspack-config.js.bak +38 -0
- package/dist/lib/cli/cli-runner.js +196 -0
- package/dist/lib/cli/cli-runner.js.bak +196 -0
- package/dist/lib/cli/index.js +48 -0
- package/dist/lib/cli/index.js.bak +48 -0
- package/dist/lib/common.js +93 -0
- package/dist/lib/common.js.bak +93 -0
- package/dist/lib/constants/example-code.js +260 -0
- package/dist/lib/constants/example-code.js.bak +260 -0
- package/dist/lib/constants/index.js +96 -0
- package/dist/lib/constants/index.js.bak +96 -0
- package/dist/lib/env/basic.js +40 -0
- package/dist/lib/env/basic.js.bak +40 -0
- package/dist/lib/env/constants.js +113 -0
- package/dist/lib/env/constants.js.bak +113 -0
- package/dist/lib/env/global-config-manager.js +128 -0
- package/dist/lib/env/global-config-manager.js.bak +128 -0
- package/dist/lib/env/helper.js +80 -0
- package/dist/lib/env/helper.js.bak +80 -0
- package/dist/lib/env/index.js +90 -0
- package/dist/lib/env/index.js.bak +90 -0
- package/dist/lib/env/init-debug.js +52 -0
- package/dist/lib/env/init-debug.js.bak +52 -0
- package/dist/lib/env/model-config-manager.js +113 -0
- package/dist/lib/env/model-config-manager.js.bak +113 -0
- package/dist/lib/env/parse-model-config.js +178 -0
- package/dist/lib/env/parse-model-config.js.bak +178 -0
- package/dist/lib/env/types.js +554 -0
- package/dist/lib/env/types.js.bak +554 -0
- package/dist/lib/env/utils.js +72 -0
- package/dist/lib/env/utils.js.bak +72 -0
- package/dist/lib/extractor/constants.js +42 -0
- package/dist/lib/extractor/constants.js.bak +42 -0
- package/dist/lib/extractor/debug.js +12 -0
- package/dist/lib/extractor/debug.js.bak +12 -0
- package/dist/lib/extractor/dom-util.js +153 -0
- package/dist/lib/extractor/dom-util.js.bak +153 -0
- package/dist/lib/extractor/index.js +81 -0
- package/dist/lib/extractor/index.js.bak +81 -0
- package/dist/lib/extractor/locator.js +296 -0
- package/dist/lib/extractor/locator.js.bak +296 -0
- package/dist/lib/extractor/tree.js +124 -0
- package/dist/lib/extractor/tree.js.bak +124 -0
- package/dist/lib/extractor/util.js +336 -0
- package/dist/lib/extractor/util.js.bak +336 -0
- package/dist/lib/extractor/web-extractor.js +349 -0
- package/dist/lib/extractor/web-extractor.js.bak +349 -0
- package/dist/lib/img/box-select.js +875 -0
- package/dist/lib/img/box-select.js.bak +875 -0
- package/dist/lib/img/canvas-fallback.js +305 -0
- package/dist/lib/img/canvas-fallback.js.bak +305 -0
- package/dist/lib/img/get-photon.js +82 -0
- package/dist/lib/img/get-photon.js.bak +82 -0
- package/dist/lib/img/get-sharp.js +45 -0
- package/dist/lib/img/get-sharp.js.bak +45 -0
- package/dist/lib/img/index.js +95 -0
- package/dist/lib/img/index.js.bak +95 -0
- package/dist/lib/img/info.js +83 -0
- package/dist/lib/img/info.js.bak +83 -0
- package/dist/lib/img/transform.js +387 -0
- package/dist/lib/img/transform.js.bak +387 -0
- package/dist/lib/index.js +47 -0
- package/dist/lib/index.js.bak +47 -0
- package/dist/lib/logger.js +114 -0
- package/dist/lib/logger.js.bak +114 -0
- package/dist/lib/mcp/base-server.js +331 -0
- package/dist/lib/mcp/base-server.js.bak +331 -0
- package/dist/lib/mcp/base-tools.js +125 -0
- package/dist/lib/mcp/base-tools.js.bak +125 -0
- package/dist/lib/mcp/chrome-path.js +72 -0
- package/dist/lib/mcp/chrome-path.js.bak +72 -0
- package/dist/lib/mcp/index.js +100 -0
- package/dist/lib/mcp/index.js.bak +100 -0
- package/dist/lib/mcp/inject-report-html-plugin.js +98 -0
- package/dist/lib/mcp/inject-report-html-plugin.js.bak +98 -0
- package/dist/lib/mcp/launcher-helper.js +86 -0
- package/dist/lib/mcp/launcher-helper.js.bak +86 -0
- package/dist/lib/mcp/tool-generator.js +334 -0
- package/dist/lib/mcp/tool-generator.js.bak +334 -0
- package/dist/lib/mcp/types.js +40 -0
- package/dist/lib/mcp/types.js.bak +40 -0
- package/dist/lib/node/fs.js +97 -0
- package/dist/lib/node/fs.js.bak +97 -0
- package/dist/lib/node/index.js +65 -0
- package/dist/lib/node/index.js.bak +65 -0
- package/dist/lib/node/port.js +61 -0
- package/dist/lib/node/port.js.bak +61 -0
- package/dist/lib/oss/demo.js +36 -0
- package/dist/lib/oss/demo.js.bak +36 -0
- package/dist/lib/oss/index.js +138 -0
- package/dist/lib/oss/index.js.bak +138 -0
- package/dist/lib/polyfills/async-hooks.js +36 -0
- package/dist/lib/polyfills/async-hooks.js.bak +36 -0
- package/dist/lib/polyfills/index.js +58 -0
- package/dist/lib/polyfills/index.js.bak +58 -0
- package/dist/lib/types/index.js +37 -0
- package/dist/lib/types/index.js.bak +37 -0
- package/dist/lib/us-keyboard-layout.js +1457 -0
- package/dist/lib/us-keyboard-layout.js.LICENSE.txt +5 -0
- package/dist/lib/us-keyboard-layout.js.bak +1457 -0
- package/dist/lib/utils.js +148 -0
- package/dist/lib/utils.js.bak +148 -0
- package/dist/lib/zod-schema-utils.js +97 -0
- package/dist/lib/zod-schema-utils.js.bak +97 -0
- package/dist/types/baseDB.d.ts +25 -0
- package/dist/types/baseDB.d.ts.bak +25 -0
- package/dist/types/build/copy-static.d.ts +31 -0
- package/dist/types/build/copy-static.d.ts.bak +31 -0
- package/dist/types/build/rspack-config.d.ts +8 -0
- package/dist/types/build/rspack-config.d.ts.bak +8 -0
- package/dist/types/cli/cli-runner.d.ts +14 -0
- package/dist/types/cli/cli-runner.d.ts.bak +14 -0
- package/dist/types/cli/index.d.ts +2 -0
- package/dist/types/cli/index.d.ts.bak +2 -0
- package/dist/types/common.d.ts +12 -0
- package/dist/types/common.d.ts.bak +12 -0
- package/dist/types/constants/example-code.d.ts +2 -0
- package/dist/types/constants/example-code.d.ts.bak +2 -0
- package/dist/types/constants/index.d.ts +21 -0
- package/dist/types/constants/index.d.ts.bak +21 -0
- package/dist/types/env/basic.d.ts +6 -0
- package/dist/types/env/basic.d.ts.bak +6 -0
- package/dist/types/env/constants.d.ts +40 -0
- package/dist/types/env/constants.d.ts.bak +40 -0
- package/dist/types/env/global-config-manager.d.ts +32 -0
- package/dist/types/env/global-config-manager.d.ts.bak +32 -0
- package/dist/types/env/helper.d.ts +4 -0
- package/dist/types/env/helper.d.ts.bak +4 -0
- package/dist/types/env/index.d.ts +4 -0
- package/dist/types/env/index.d.ts.bak +4 -0
- package/dist/types/env/init-debug.d.ts +1 -0
- package/dist/types/env/init-debug.d.ts.bak +1 -0
- package/dist/types/env/model-config-manager.d.ts +25 -0
- package/dist/types/env/model-config-manager.d.ts.bak +25 -0
- package/dist/types/env/parse-model-config.d.ts +31 -0
- package/dist/types/env/parse-model-config.d.ts.bak +31 -0
- package/dist/types/env/types.d.ts +318 -0
- package/dist/types/env/types.d.ts.bak +318 -0
- package/dist/types/env/utils.d.ts +38 -0
- package/dist/types/env/utils.d.ts.bak +38 -0
- package/dist/types/extractor/constants.d.ts +1 -0
- package/dist/types/extractor/constants.d.ts.bak +1 -0
- package/dist/types/extractor/debug.d.ts +1 -0
- package/dist/types/extractor/debug.d.ts.bak +1 -0
- package/dist/types/extractor/dom-util.d.ts +56 -0
- package/dist/types/extractor/dom-util.d.ts.bak +56 -0
- package/dist/types/extractor/index.d.ts +32 -0
- package/dist/types/extractor/index.d.ts.bak +32 -0
- package/dist/types/extractor/locator.d.ts +9 -0
- package/dist/types/extractor/locator.d.ts.bak +9 -0
- package/dist/types/extractor/tree.d.ts +6 -0
- package/dist/types/extractor/tree.d.ts.bak +6 -0
- package/dist/types/extractor/util.d.ts +47 -0
- package/dist/types/extractor/util.d.ts.bak +47 -0
- package/dist/types/extractor/web-extractor.d.ts +19 -0
- package/dist/types/extractor/web-extractor.d.ts.bak +19 -0
- package/dist/types/img/box-select.d.ts +26 -0
- package/dist/types/img/box-select.d.ts.bak +26 -0
- package/dist/types/img/canvas-fallback.d.ts +105 -0
- package/dist/types/img/canvas-fallback.d.ts.bak +105 -0
- package/dist/types/img/get-photon.d.ts +19 -0
- package/dist/types/img/get-photon.d.ts.bak +19 -0
- package/dist/types/img/get-sharp.d.ts +3 -0
- package/dist/types/img/get-sharp.d.ts.bak +3 -0
- package/dist/types/img/index.d.ts +3 -0
- package/dist/types/img/index.d.ts.bak +3 -0
- package/dist/types/img/info.d.ts +29 -0
- package/dist/types/img/info.d.ts.bak +29 -0
- package/dist/types/img/transform.d.ts +107 -0
- package/dist/types/img/transform.d.ts.bak +107 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.bak +4 -0
- package/dist/types/logger.d.ts +5 -0
- package/dist/types/logger.d.ts.bak +5 -0
- package/dist/types/mcp/base-server.d.ts +93 -0
- package/dist/types/mcp/base-server.d.ts.bak +93 -0
- package/dist/types/mcp/base-tools.d.ts +79 -0
- package/dist/types/mcp/base-tools.d.ts.bak +79 -0
- package/dist/types/mcp/chrome-path.d.ts +2 -0
- package/dist/types/mcp/chrome-path.d.ts.bak +2 -0
- package/dist/types/mcp/index.d.ts +7 -0
- package/dist/types/mcp/index.d.ts.bak +7 -0
- package/dist/types/mcp/inject-report-html-plugin.d.ts +18 -0
- package/dist/types/mcp/inject-report-html-plugin.d.ts.bak +18 -0
- package/dist/types/mcp/launcher-helper.d.ts +94 -0
- package/dist/types/mcp/launcher-helper.d.ts.bak +94 -0
- package/dist/types/mcp/tool-generator.d.ts +10 -0
- package/dist/types/mcp/tool-generator.d.ts.bak +10 -0
- package/dist/types/mcp/types.d.ts +103 -0
- package/dist/types/mcp/types.d.ts.bak +103 -0
- package/dist/types/node/fs.d.ts +15 -0
- package/dist/types/node/fs.d.ts.bak +15 -0
- package/dist/types/node/index.d.ts +2 -0
- package/dist/types/node/index.d.ts.bak +2 -0
- package/dist/types/node/port.d.ts +8 -0
- package/dist/types/node/port.d.ts.bak +8 -0
- package/dist/types/oss/demo.d.ts +1 -0
- package/dist/types/oss/demo.d.ts.bak +1 -0
- package/dist/types/oss/index.d.ts +34 -0
- package/dist/types/oss/index.d.ts.bak +34 -0
- package/dist/types/polyfills/async-hooks.d.ts +6 -0
- package/dist/types/polyfills/async-hooks.d.ts.bak +6 -0
- package/dist/types/polyfills/index.d.ts +4 -0
- package/dist/types/polyfills/index.d.ts.bak +4 -0
- package/dist/types/types/index.d.ts +34 -0
- package/dist/types/types/index.d.ts.bak +34 -0
- package/dist/types/us-keyboard-layout.d.ts +32 -0
- package/dist/types/us-keyboard-layout.d.ts.bak +32 -0
- package/dist/types/utils.d.ts +34 -0
- package/dist/types/utils.d.ts.bak +34 -0
- package/dist/types/zod-schema-utils.d.ts +23 -0
- package/dist/types/zod-schema-utils.d.ts.bak +23 -0
- package/package.json +132 -0
- package/src/baseDB.ts +158 -0
- package/src/build/copy-static.ts +68 -0
- package/src/build/rspack-config.ts +12 -0
- package/src/cli/cli-runner.ts +224 -0
- package/src/cli/index.ts +8 -0
- package/src/common.ts +67 -0
- package/src/constants/example-code.ts +223 -0
- package/src/constants/index.ts +29 -0
- package/src/env/basic.ts +12 -0
- package/src/env/constants.ts +234 -0
- package/src/env/global-config-manager.ts +191 -0
- package/src/env/helper.ts +58 -0
- package/src/env/index.ts +4 -0
- package/src/env/init-debug.ts +34 -0
- package/src/env/model-config-manager.ts +149 -0
- package/src/env/parse-model-config.ts +294 -0
- package/src/env/types.ts +547 -0
- package/src/env/utils.ts +89 -0
- package/src/extractor/constants.ts +5 -0
- package/src/extractor/debug.ts +10 -0
- package/src/extractor/dom-util.ts +226 -0
- package/src/extractor/index.ts +48 -0
- package/src/extractor/locator.ts +469 -0
- package/src/extractor/tree.ts +179 -0
- package/src/extractor/util.ts +482 -0
- package/src/extractor/web-extractor.ts +481 -0
- package/src/img/box-select.ts +588 -0
- package/src/img/canvas-fallback.ts +393 -0
- package/src/img/get-photon.ts +108 -0
- package/src/img/get-sharp.ts +18 -0
- package/src/img/index.ts +26 -0
- package/src/img/info.ts +75 -0
- package/src/img/transform.ts +594 -0
- package/src/index.ts +8 -0
- package/src/logger.ts +96 -0
- package/src/mcp/base-server.ts +502 -0
- package/src/mcp/base-tools.ts +185 -0
- package/src/mcp/chrome-path.ts +48 -0
- package/src/mcp/index.ts +7 -0
- package/src/mcp/inject-report-html-plugin.ts +119 -0
- package/src/mcp/launcher-helper.ts +200 -0
- package/src/mcp/tool-generator.ts +429 -0
- package/src/mcp/types.ts +112 -0
- package/src/node/fs.ts +84 -0
- package/src/node/index.ts +2 -0
- package/src/node/port.ts +37 -0
- package/src/oss/demo.ts +61 -0
- package/src/oss/index.ts +187 -0
- package/src/polyfills/async-hooks.ts +6 -0
- package/src/polyfills/index.ts +4 -0
- package/src/types/index.ts +52 -0
- package/src/us-keyboard-layout.ts +723 -0
- package/src/utils.ts +149 -0
- package/src/zod-schema-utils.ts +133 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas-based fallback for image processing when Photon WASM fails to load.
|
|
3
|
+
* Provides a compatible API with Photon for browser environments.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { getDebug } from '../logger';
|
|
7
|
+
|
|
8
|
+
const debug = getDebug('img:canvas-fallback');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Canvas-based image class that mimics PhotonImage API
|
|
12
|
+
*/
|
|
13
|
+
export class CanvasImage {
|
|
14
|
+
private canvas: HTMLCanvasElement;
|
|
15
|
+
private ctx: CanvasRenderingContext2D;
|
|
16
|
+
private _width: number;
|
|
17
|
+
private _height: number;
|
|
18
|
+
|
|
19
|
+
constructor(canvas: HTMLCanvasElement) {
|
|
20
|
+
this.canvas = canvas;
|
|
21
|
+
const ctx = canvas.getContext('2d');
|
|
22
|
+
if (!ctx) {
|
|
23
|
+
throw new Error('Failed to get 2d context');
|
|
24
|
+
}
|
|
25
|
+
this.ctx = ctx;
|
|
26
|
+
this._width = canvas.width;
|
|
27
|
+
this._height = canvas.height;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get_width(): number {
|
|
31
|
+
return this._width;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get_height(): number {
|
|
35
|
+
return this._height;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get_raw_pixels(): Uint8Array {
|
|
39
|
+
const imageData = this.ctx.getImageData(0, 0, this._width, this._height);
|
|
40
|
+
return new Uint8Array(imageData.data.buffer);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get_bytes_jpeg(quality: number): Uint8Array {
|
|
44
|
+
const dataUrl = this.canvas.toDataURL('image/jpeg', quality / 100);
|
|
45
|
+
const base64 = dataUrl.split(',')[1];
|
|
46
|
+
const binary = atob(base64);
|
|
47
|
+
const bytes = new Uint8Array(binary.length);
|
|
48
|
+
for (let i = 0; i < binary.length; i++) {
|
|
49
|
+
bytes[i] = binary.charCodeAt(i);
|
|
50
|
+
}
|
|
51
|
+
return bytes;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
free(): void {
|
|
55
|
+
// No-op for Canvas, garbage collector will handle it
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Internal method to get canvas for composition
|
|
59
|
+
_getCanvas(): HTMLCanvasElement {
|
|
60
|
+
return this.canvas;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
_getContext(): CanvasRenderingContext2D {
|
|
64
|
+
return this.ctx;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Create a CanvasImage from a base64 string
|
|
69
|
+
*/
|
|
70
|
+
static async new_from_base64(base64Body: string): Promise<CanvasImage> {
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
const img = new Image();
|
|
73
|
+
img.onload = () => {
|
|
74
|
+
const canvas = document.createElement('canvas');
|
|
75
|
+
canvas.width = img.width;
|
|
76
|
+
canvas.height = img.height;
|
|
77
|
+
const ctx = canvas.getContext('2d');
|
|
78
|
+
if (!ctx) {
|
|
79
|
+
reject(new Error('Failed to get 2d context'));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
ctx.drawImage(img, 0, 0);
|
|
83
|
+
resolve(new CanvasImage(canvas));
|
|
84
|
+
};
|
|
85
|
+
img.onerror = () => {
|
|
86
|
+
reject(new Error('Failed to load image'));
|
|
87
|
+
};
|
|
88
|
+
// Handle both with and without data URL prefix
|
|
89
|
+
if (base64Body.startsWith('data:')) {
|
|
90
|
+
img.src = base64Body;
|
|
91
|
+
} else {
|
|
92
|
+
img.src = `data:image/png;base64,${base64Body}`;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Create a CanvasImage from a byte array (async version)
|
|
99
|
+
*/
|
|
100
|
+
static async new_from_byteslice(bytes: Uint8Array): Promise<CanvasImage> {
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
const blob = new Blob([bytes], { type: 'image/png' });
|
|
103
|
+
const url = URL.createObjectURL(blob);
|
|
104
|
+
const img = new Image();
|
|
105
|
+
|
|
106
|
+
img.onload = () => {
|
|
107
|
+
const canvas = document.createElement('canvas');
|
|
108
|
+
canvas.width = img.width;
|
|
109
|
+
canvas.height = img.height;
|
|
110
|
+
const ctx = canvas.getContext('2d');
|
|
111
|
+
if (!ctx) {
|
|
112
|
+
URL.revokeObjectURL(url);
|
|
113
|
+
reject(new Error('Failed to get 2d context'));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
ctx.drawImage(img, 0, 0);
|
|
117
|
+
URL.revokeObjectURL(url);
|
|
118
|
+
resolve(new CanvasImage(canvas));
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
img.onerror = () => {
|
|
122
|
+
URL.revokeObjectURL(url);
|
|
123
|
+
reject(new Error('Failed to load image from bytes'));
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
img.src = url;
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Sampling filter enum (compatible with Photon)
|
|
133
|
+
*/
|
|
134
|
+
export const CanvasSamplingFilter = {
|
|
135
|
+
Nearest: 'nearest',
|
|
136
|
+
Triangle: 'triangle',
|
|
137
|
+
CatmullRom: 'catmullrom',
|
|
138
|
+
Gaussian: 'gaussian',
|
|
139
|
+
Lanczos3: 'lanczos3',
|
|
140
|
+
} as const;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* RGBA color class (compatible with Photon)
|
|
144
|
+
*/
|
|
145
|
+
export class CanvasRgba {
|
|
146
|
+
r: number;
|
|
147
|
+
g: number;
|
|
148
|
+
b: number;
|
|
149
|
+
a: number;
|
|
150
|
+
|
|
151
|
+
constructor(r: number, g: number, b: number, a: number) {
|
|
152
|
+
this.r = r;
|
|
153
|
+
this.g = g;
|
|
154
|
+
this.b = b;
|
|
155
|
+
this.a = a;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Resize an image
|
|
161
|
+
*/
|
|
162
|
+
export function canvasResize(
|
|
163
|
+
image: CanvasImage,
|
|
164
|
+
newWidth: number,
|
|
165
|
+
newHeight: number,
|
|
166
|
+
_filter: string,
|
|
167
|
+
): CanvasImage {
|
|
168
|
+
const canvas = document.createElement('canvas');
|
|
169
|
+
canvas.width = newWidth;
|
|
170
|
+
canvas.height = newHeight;
|
|
171
|
+
const ctx = canvas.getContext('2d');
|
|
172
|
+
if (!ctx) {
|
|
173
|
+
throw new Error('Failed to get 2d context');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Enable image smoothing for better quality
|
|
177
|
+
ctx.imageSmoothingEnabled = true;
|
|
178
|
+
ctx.imageSmoothingQuality = 'high';
|
|
179
|
+
|
|
180
|
+
ctx.drawImage(image._getCanvas(), 0, 0, newWidth, newHeight);
|
|
181
|
+
return new CanvasImage(canvas);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Crop an image
|
|
186
|
+
*/
|
|
187
|
+
export function canvasCrop(
|
|
188
|
+
image: CanvasImage,
|
|
189
|
+
x1: number,
|
|
190
|
+
y1: number,
|
|
191
|
+
x2: number,
|
|
192
|
+
y2: number,
|
|
193
|
+
): CanvasImage {
|
|
194
|
+
const width = x2 - x1;
|
|
195
|
+
const height = y2 - y1;
|
|
196
|
+
const canvas = document.createElement('canvas');
|
|
197
|
+
canvas.width = width;
|
|
198
|
+
canvas.height = height;
|
|
199
|
+
const ctx = canvas.getContext('2d');
|
|
200
|
+
if (!ctx) {
|
|
201
|
+
throw new Error('Failed to get 2d context');
|
|
202
|
+
}
|
|
203
|
+
ctx.drawImage(image._getCanvas(), x1, y1, width, height, 0, 0, width, height);
|
|
204
|
+
return new CanvasImage(canvas);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Add padding to the right of an image
|
|
209
|
+
*/
|
|
210
|
+
export function canvasPaddingRight(
|
|
211
|
+
image: CanvasImage,
|
|
212
|
+
padding: number,
|
|
213
|
+
color: CanvasRgba,
|
|
214
|
+
): CanvasImage {
|
|
215
|
+
const newWidth = image.get_width() + padding;
|
|
216
|
+
const height = image.get_height();
|
|
217
|
+
const canvas = document.createElement('canvas');
|
|
218
|
+
canvas.width = newWidth;
|
|
219
|
+
canvas.height = height;
|
|
220
|
+
const ctx = canvas.getContext('2d');
|
|
221
|
+
if (!ctx) {
|
|
222
|
+
throw new Error('Failed to get 2d context');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Fill with color
|
|
226
|
+
ctx.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a / 255})`;
|
|
227
|
+
ctx.fillRect(0, 0, newWidth, height);
|
|
228
|
+
|
|
229
|
+
// Draw original image
|
|
230
|
+
ctx.drawImage(image._getCanvas(), 0, 0);
|
|
231
|
+
return new CanvasImage(canvas);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Add padding to the bottom of an image
|
|
236
|
+
*/
|
|
237
|
+
export function canvasPaddingBottom(
|
|
238
|
+
image: CanvasImage,
|
|
239
|
+
padding: number,
|
|
240
|
+
color: CanvasRgba,
|
|
241
|
+
): CanvasImage {
|
|
242
|
+
const width = image.get_width();
|
|
243
|
+
const newHeight = image.get_height() + padding;
|
|
244
|
+
const canvas = document.createElement('canvas');
|
|
245
|
+
canvas.width = width;
|
|
246
|
+
canvas.height = newHeight;
|
|
247
|
+
const ctx = canvas.getContext('2d');
|
|
248
|
+
if (!ctx) {
|
|
249
|
+
throw new Error('Failed to get 2d context');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Fill with color
|
|
253
|
+
ctx.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a / 255})`;
|
|
254
|
+
ctx.fillRect(0, 0, width, newHeight);
|
|
255
|
+
|
|
256
|
+
// Draw original image
|
|
257
|
+
ctx.drawImage(image._getCanvas(), 0, 0);
|
|
258
|
+
return new CanvasImage(canvas);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Add uniform padding to an image
|
|
263
|
+
*/
|
|
264
|
+
export function canvasPaddingUniform(
|
|
265
|
+
image: CanvasImage,
|
|
266
|
+
padding: number,
|
|
267
|
+
color: CanvasRgba,
|
|
268
|
+
): CanvasImage {
|
|
269
|
+
const newWidth = image.get_width() + padding * 2;
|
|
270
|
+
const newHeight = image.get_height() + padding * 2;
|
|
271
|
+
const canvas = document.createElement('canvas');
|
|
272
|
+
canvas.width = newWidth;
|
|
273
|
+
canvas.height = newHeight;
|
|
274
|
+
const ctx = canvas.getContext('2d');
|
|
275
|
+
if (!ctx) {
|
|
276
|
+
throw new Error('Failed to get 2d context');
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Fill with color
|
|
280
|
+
ctx.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a / 255})`;
|
|
281
|
+
ctx.fillRect(0, 0, newWidth, newHeight);
|
|
282
|
+
|
|
283
|
+
// Draw original image centered
|
|
284
|
+
ctx.drawImage(image._getCanvas(), padding, padding);
|
|
285
|
+
return new CanvasImage(canvas);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Add padding to the left of an image
|
|
290
|
+
*/
|
|
291
|
+
export function canvasPaddingLeft(
|
|
292
|
+
image: CanvasImage,
|
|
293
|
+
padding: number,
|
|
294
|
+
color: CanvasRgba,
|
|
295
|
+
): CanvasImage {
|
|
296
|
+
const newWidth = image.get_width() + padding;
|
|
297
|
+
const height = image.get_height();
|
|
298
|
+
const canvas = document.createElement('canvas');
|
|
299
|
+
canvas.width = newWidth;
|
|
300
|
+
canvas.height = height;
|
|
301
|
+
const ctx = canvas.getContext('2d');
|
|
302
|
+
if (!ctx) {
|
|
303
|
+
throw new Error('Failed to get 2d context');
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Fill with color
|
|
307
|
+
ctx.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a / 255})`;
|
|
308
|
+
ctx.fillRect(0, 0, newWidth, height);
|
|
309
|
+
|
|
310
|
+
// Draw original image offset by padding
|
|
311
|
+
ctx.drawImage(image._getCanvas(), padding, 0);
|
|
312
|
+
return new CanvasImage(canvas);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Add padding to the top of an image
|
|
317
|
+
*/
|
|
318
|
+
export function canvasPaddingTop(
|
|
319
|
+
image: CanvasImage,
|
|
320
|
+
padding: number,
|
|
321
|
+
color: CanvasRgba,
|
|
322
|
+
): CanvasImage {
|
|
323
|
+
const width = image.get_width();
|
|
324
|
+
const newHeight = image.get_height() + padding;
|
|
325
|
+
const canvas = document.createElement('canvas');
|
|
326
|
+
canvas.width = width;
|
|
327
|
+
canvas.height = newHeight;
|
|
328
|
+
const ctx = canvas.getContext('2d');
|
|
329
|
+
if (!ctx) {
|
|
330
|
+
throw new Error('Failed to get 2d context');
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Fill with color
|
|
334
|
+
ctx.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a / 255})`;
|
|
335
|
+
ctx.fillRect(0, 0, width, newHeight);
|
|
336
|
+
|
|
337
|
+
// Draw original image offset by padding
|
|
338
|
+
ctx.drawImage(image._getCanvas(), 0, padding);
|
|
339
|
+
return new CanvasImage(canvas);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Watermark an image (overlay one image on another)
|
|
344
|
+
*/
|
|
345
|
+
export function canvasWatermark(
|
|
346
|
+
base: CanvasImage,
|
|
347
|
+
overlay: CanvasImage,
|
|
348
|
+
x: number,
|
|
349
|
+
y: number,
|
|
350
|
+
): CanvasImage {
|
|
351
|
+
const canvas = document.createElement('canvas');
|
|
352
|
+
canvas.width = base.get_width();
|
|
353
|
+
canvas.height = base.get_height();
|
|
354
|
+
const ctx = canvas.getContext('2d');
|
|
355
|
+
if (!ctx) {
|
|
356
|
+
throw new Error('Failed to get 2d context');
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Draw base image
|
|
360
|
+
ctx.drawImage(base._getCanvas(), 0, 0);
|
|
361
|
+
|
|
362
|
+
// Draw overlay at position
|
|
363
|
+
ctx.drawImage(overlay._getCanvas(), x, y);
|
|
364
|
+
return new CanvasImage(canvas);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Create and return the canvas fallback module with Photon-compatible API
|
|
369
|
+
*/
|
|
370
|
+
export function createCanvasFallbackModule() {
|
|
371
|
+
debug('Creating Canvas fallback module');
|
|
372
|
+
console.log(
|
|
373
|
+
'[midscene:img] Using Canvas fallback (Photon WASM not available)',
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
return {
|
|
377
|
+
PhotonImage: CanvasImage,
|
|
378
|
+
SamplingFilter: CanvasSamplingFilter,
|
|
379
|
+
resize: canvasResize,
|
|
380
|
+
crop: canvasCrop,
|
|
381
|
+
open_image: () => {
|
|
382
|
+
throw new Error('open_image not supported in Canvas fallback');
|
|
383
|
+
},
|
|
384
|
+
base64_to_image: CanvasImage.new_from_base64,
|
|
385
|
+
padding_uniform: canvasPaddingUniform,
|
|
386
|
+
padding_left: canvasPaddingLeft,
|
|
387
|
+
padding_right: canvasPaddingRight,
|
|
388
|
+
padding_top: canvasPaddingTop,
|
|
389
|
+
padding_bottom: canvasPaddingBottom,
|
|
390
|
+
watermark: canvasWatermark,
|
|
391
|
+
Rgba: CanvasRgba,
|
|
392
|
+
};
|
|
393
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { getDebug } from '../logger';
|
|
2
|
+
import { ifInBrowser, ifInNode, ifInWorker } from '../utils';
|
|
3
|
+
|
|
4
|
+
const debug = getDebug('img');
|
|
5
|
+
|
|
6
|
+
let photonModule: any = null;
|
|
7
|
+
let isInitialized = false;
|
|
8
|
+
let usingCanvasFallback = false;
|
|
9
|
+
|
|
10
|
+
export default async function getPhoton(): Promise<{
|
|
11
|
+
PhotonImage: typeof import('@silvia-odwyer/photon-node').PhotonImage;
|
|
12
|
+
SamplingFilter: typeof import('@silvia-odwyer/photon-node').SamplingFilter;
|
|
13
|
+
resize: typeof import('@silvia-odwyer/photon-node').resize;
|
|
14
|
+
crop: typeof import('@silvia-odwyer/photon-node').crop;
|
|
15
|
+
open_image: typeof import('@silvia-odwyer/photon-node').open_image;
|
|
16
|
+
base64_to_image: typeof import('@silvia-odwyer/photon-node').base64_to_image;
|
|
17
|
+
padding_uniform: typeof import('@silvia-odwyer/photon-node').padding_uniform;
|
|
18
|
+
padding_left: typeof import('@silvia-odwyer/photon-node').padding_left;
|
|
19
|
+
padding_right: typeof import('@silvia-odwyer/photon-node').padding_right;
|
|
20
|
+
padding_top: typeof import('@silvia-odwyer/photon-node').padding_top;
|
|
21
|
+
padding_bottom: typeof import('@silvia-odwyer/photon-node').padding_bottom;
|
|
22
|
+
watermark: typeof import('@silvia-odwyer/photon-node').watermark;
|
|
23
|
+
Rgba: typeof import('@silvia-odwyer/photon-node').Rgba;
|
|
24
|
+
}> {
|
|
25
|
+
if (photonModule && isInitialized) {
|
|
26
|
+
return photonModule;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const env = ifInBrowser
|
|
30
|
+
? 'browser'
|
|
31
|
+
: ifInWorker
|
|
32
|
+
? 'worker'
|
|
33
|
+
: ifInNode
|
|
34
|
+
? 'node'
|
|
35
|
+
: 'unknown';
|
|
36
|
+
debug(`Loading photon module in ${env} environment`);
|
|
37
|
+
|
|
38
|
+
// Try to load Photon first
|
|
39
|
+
try {
|
|
40
|
+
if (ifInBrowser || ifInWorker) {
|
|
41
|
+
// Regular browser environment: use @silvia-odwyer/photon
|
|
42
|
+
const photon = await import('@silvia-odwyer/photon');
|
|
43
|
+
if (typeof photon.default === 'function') {
|
|
44
|
+
// for browser environment, ensure WASM module is correctly initialized
|
|
45
|
+
await photon.default();
|
|
46
|
+
}
|
|
47
|
+
debug('Photon loaded: @silvia-odwyer/photon (browser/worker)');
|
|
48
|
+
photonModule = photon;
|
|
49
|
+
} else if (ifInNode) {
|
|
50
|
+
// Node.js environment: use @silvia-odwyer/photon-node
|
|
51
|
+
photonModule = await import('@silvia-odwyer/photon-node');
|
|
52
|
+
debug('Photon loaded: @silvia-odwyer/photon-node (node)');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// verify that the critical functions exist (only for Photon, not Canvas fallback)
|
|
56
|
+
if (!photonModule?.PhotonImage) {
|
|
57
|
+
throw new Error('PhotonImage is not available');
|
|
58
|
+
}
|
|
59
|
+
// new_from_byteslice may be sync (Photon) or async (Canvas), both are acceptable
|
|
60
|
+
if (
|
|
61
|
+
!photonModule.PhotonImage.new_from_byteslice &&
|
|
62
|
+
!photonModule.PhotonImage.new_from_base64
|
|
63
|
+
) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
'PhotonImage.new_from_byteslice or new_from_base64 is not available',
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
isInitialized = true;
|
|
70
|
+
return photonModule;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
debug(
|
|
73
|
+
`Photon load failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
// In browser environment, fall back to Canvas API
|
|
77
|
+
if (ifInBrowser) {
|
|
78
|
+
console.warn(
|
|
79
|
+
`[midscene:img] Photon WASM failed to load, falling back to Canvas API. Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const { createCanvasFallbackModule } = await import(
|
|
84
|
+
'./canvas-fallback'
|
|
85
|
+
);
|
|
86
|
+
photonModule = createCanvasFallbackModule();
|
|
87
|
+
usingCanvasFallback = true;
|
|
88
|
+
isInitialized = true;
|
|
89
|
+
return photonModule;
|
|
90
|
+
} catch (fallbackError) {
|
|
91
|
+
debug(
|
|
92
|
+
`Canvas fallback also failed: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
throw new Error(
|
|
98
|
+
`Failed to load photon module: ${error instanceof Error ? error.message : String(error)}`,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Check if we're using the Canvas fallback instead of Photon
|
|
105
|
+
*/
|
|
106
|
+
export function isUsingCanvasFallback(): boolean {
|
|
107
|
+
return usingCanvasFallback;
|
|
108
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ifInNode } from '../utils';
|
|
2
|
+
type TSharpModule = typeof import('sharp');
|
|
3
|
+
|
|
4
|
+
export default async function getSharp(): Promise<TSharpModule> {
|
|
5
|
+
if (!ifInNode) {
|
|
6
|
+
throw new Error('Sharp is only available in Node.js environment');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
const sharp = await import('sharp');
|
|
12
|
+
return sharp.default;
|
|
13
|
+
} catch (error) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
`Failed to load sharp module: ${error instanceof Error ? error.message : String(error)}`,
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
}
|
package/src/img/index.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export {
|
|
2
|
+
imageInfoOfBase64,
|
|
3
|
+
isValidPNGImageBuffer,
|
|
4
|
+
isValidJPEGImageBuffer,
|
|
5
|
+
isValidImageBuffer,
|
|
6
|
+
} from './info';
|
|
7
|
+
export {
|
|
8
|
+
resizeAndConvertImgBuffer,
|
|
9
|
+
resizeImgBase64,
|
|
10
|
+
convertToJpegBase64,
|
|
11
|
+
zoomForGPT4o,
|
|
12
|
+
saveBase64Image,
|
|
13
|
+
paddingToMatchBlockByBase64,
|
|
14
|
+
cropByRect,
|
|
15
|
+
scaleImage,
|
|
16
|
+
localImg2Base64,
|
|
17
|
+
httpImg2Base64,
|
|
18
|
+
preProcessImageUrl,
|
|
19
|
+
parseBase64,
|
|
20
|
+
createImgBase64ByFormat,
|
|
21
|
+
} from './transform';
|
|
22
|
+
export {
|
|
23
|
+
processImageElementInfo,
|
|
24
|
+
compositeElementInfoImg,
|
|
25
|
+
annotateRects,
|
|
26
|
+
} from './box-select';
|
package/src/img/info.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import type { Size } from '../types';
|
|
3
|
+
import getPhoton from './get-photon';
|
|
4
|
+
|
|
5
|
+
export interface ImageInfo extends Size {}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Retrieves the dimensions of an image from a base64-encoded string
|
|
9
|
+
*
|
|
10
|
+
* @param imageBase64 - The base64-encoded image data
|
|
11
|
+
* @returns A Promise that resolves to an object containing the width and height of the image
|
|
12
|
+
* @throws Error if the image data is invalid
|
|
13
|
+
*/
|
|
14
|
+
export async function imageInfoOfBase64(
|
|
15
|
+
imageBase64: string,
|
|
16
|
+
): Promise<ImageInfo> {
|
|
17
|
+
const { PhotonImage } = await getPhoton();
|
|
18
|
+
const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, '');
|
|
19
|
+
// Support both sync (Photon) and async (Canvas fallback) versions
|
|
20
|
+
const result = PhotonImage.new_from_base64(base64Data);
|
|
21
|
+
const image = result instanceof Promise ? await result : result;
|
|
22
|
+
const width = image.get_width();
|
|
23
|
+
const height = image.get_height();
|
|
24
|
+
image.free();
|
|
25
|
+
assert(width && height, 'Invalid image: cannot get width or height');
|
|
26
|
+
return { width, height };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Check if the Buffer is a valid PNG image
|
|
31
|
+
* @param buffer The Buffer to check
|
|
32
|
+
* @returns true if the Buffer is a valid PNG image, otherwise false
|
|
33
|
+
*/
|
|
34
|
+
export function isValidPNGImageBuffer(buffer: Buffer): boolean {
|
|
35
|
+
if (!buffer || buffer.length < 8) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Check PNG signature (8 bytes): 89 50 4E 47 0D 0A 1A 0A
|
|
40
|
+
// This is more robust than just checking the first 4 bytes
|
|
41
|
+
const isPNG =
|
|
42
|
+
buffer[0] === 0x89 &&
|
|
43
|
+
buffer[1] === 0x50 &&
|
|
44
|
+
buffer[2] === 0x4e &&
|
|
45
|
+
buffer[3] === 0x47 &&
|
|
46
|
+
buffer[4] === 0x0d &&
|
|
47
|
+
buffer[5] === 0x0a &&
|
|
48
|
+
buffer[6] === 0x1a &&
|
|
49
|
+
buffer[7] === 0x0a;
|
|
50
|
+
|
|
51
|
+
return isPNG;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Check if the Buffer is a valid JPEG image
|
|
56
|
+
* @param buffer The Buffer to check
|
|
57
|
+
* @returns true if the Buffer is a valid JPEG image, otherwise false
|
|
58
|
+
*/
|
|
59
|
+
export function isValidJPEGImageBuffer(buffer: Buffer): boolean {
|
|
60
|
+
if (!buffer || buffer.length < 3) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Check JPEG signature (3 bytes): FF D8 FF
|
|
65
|
+
return buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Check if the Buffer is a valid image (PNG or JPEG)
|
|
70
|
+
* @param buffer The Buffer to check
|
|
71
|
+
* @returns true if the Buffer is a valid PNG or JPEG image, otherwise false
|
|
72
|
+
*/
|
|
73
|
+
export function isValidImageBuffer(buffer: Buffer): boolean {
|
|
74
|
+
return isValidPNGImageBuffer(buffer) || isValidJPEGImageBuffer(buffer);
|
|
75
|
+
}
|