├── .devcontainer ├── Dockerfile ├── devcontainer.json ├── docker-compose.yml ├── imgproxy-truncated.env ├── imgproxy-unsigned.env ├── imgproxy.env ├── init.sh ├── minio-dump │ └── test-bucket │ │ ├── test-image.png │ │ └── test-image.svg ├── minio.env ├── test-image.png └── workspace.env ├── .eslintignore ├── .eslintrc.json ├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── build.yml │ ├── dependabot-auto-merge.yml │ └── publish-npm-package.yml ├── .gitignore ├── .ncurc.json ├── .nvmrc ├── .prettierrc ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── docs ├── .nojekyll ├── assets │ ├── highlight.css │ ├── icons.js │ ├── icons.svg │ ├── main.js │ ├── navigation.js │ ├── search.js │ └── style.css ├── classes │ └── ParamBuilder.html ├── enums │ ├── GradientDirection.html │ ├── GravityType.html │ ├── ResizeType.html │ ├── ResizingAlgorithm.html │ ├── UnsharpeningMode.html │ └── WatermarkPosition.html ├── functions │ ├── chain.html │ └── default.html ├── index.html ├── modules.html └── types │ ├── AdjustOptions.html │ ├── BackgroundAlphaOptions.html │ ├── BackgroundOptions.html │ ├── BlurDetectionOptions.html │ ├── BlurOptions.html │ ├── BrightnessOptions.html │ ├── BuildOptions.html │ ├── CacheBusterOptions.html │ ├── ContrastOptions.html │ ├── CropOptions.html │ ├── DPIOptions.html │ ├── DprOptions.html │ ├── DrawDetectionOptions.html │ ├── DuotoneOptions.html │ ├── ExpiresOptions.html │ ├── ExtendAspectRatioOptions.html │ ├── ExtendOptions.html │ ├── FallbackImageUrlOptions.html │ ├── FileNameOptions.html │ ├── FormatOptions.html │ ├── FormatQualityOptions.html │ ├── GifOptions.html │ ├── GradientOptions.html │ ├── GravityOptions.html │ ├── HashsumOptions.html │ ├── JpegOptions.html │ ├── MaxBytesOptions.html │ ├── MinHeightOptions.html │ ├── MinWidthOptions.html │ ├── MonochromeOptions.html │ ├── PaddingOptions.html │ ├── PageOptions.html │ ├── PixelateOptions.html │ ├── PngOptions.html │ ├── PresetOptions.html │ ├── QualityOptions.html │ ├── ResizeOptions.html │ ├── ResizingAlgorithmOptions.html │ ├── RotationOptions.html │ ├── SaturationOptions.html │ ├── SharpenOptions.html │ ├── SkipProcessingOptions.html │ ├── StyleOptions.html │ ├── TrimOptions.html │ ├── UnsharpeningOptions.html │ ├── VideoThumbnailKeyframesOptions.html │ ├── VideoThumbnailSecondOptions.html │ ├── VideoThumbnailTileOptions.html │ ├── WatermarkOptions.html │ ├── WatermarkShadowOptions.html │ ├── WatermarkSizeOptions.html │ ├── WatermarkTextOptions.html │ ├── WatermarkUrlOptions.html │ └── ZoomOptions.html ├── jest.config.ts ├── jest.globals.ts ├── jest.setup.ts ├── package-lock.json ├── package.json ├── rollup.config.js ├── scripts ├── micro-benchmark.cjs ├── minio-dump.sh ├── minio-restore.sh └── populate-readme.cjs ├── src ├── common.ts ├── crypto │ ├── codec.ts │ ├── common.ts │ ├── hmac.ts │ └── sha256.ts ├── enums │ ├── gradient-direction.enum.ts │ ├── gravity-type.enum.ts │ ├── hashsum-type.enum.ts │ ├── resize-type.enum.ts │ ├── resizing-algorithm.enum.ts │ ├── unsharpening-mode.enum.ts │ └── watermark-position.enum.ts ├── index.ts ├── param-builder.ts ├── transformers │ ├── adjust.ts │ ├── auto-rotate.ts │ ├── background-alpha.ts │ ├── background.ts │ ├── blur-detections.ts │ ├── blur.ts │ ├── brightness.ts │ ├── cache-buster.ts │ ├── contrast.ts │ ├── crop.ts │ ├── disable-animation.ts │ ├── dpi.ts │ ├── dpr.ts │ ├── draw-detections.ts │ ├── duotone.ts │ ├── enforce-thumbnail.ts │ ├── enlarge.ts │ ├── expires.ts │ ├── extend-aspect-ratio.ts │ ├── extend.ts │ ├── fallback-image-url.ts │ ├── filename.ts │ ├── format-quality.ts │ ├── format.ts │ ├── gif-options.ts │ ├── gradient.ts │ ├── gravity.ts │ ├── hashsum.ts │ ├── jpeg-options.ts │ ├── keep-copypright.ts │ ├── max-bytes.ts │ ├── min-height.ts │ ├── min-width.ts │ ├── monochrome.ts │ ├── pad.ts │ ├── page.ts │ ├── pixelate.ts │ ├── png-options.ts │ ├── preset.ts │ ├── quality.ts │ ├── raw.ts │ ├── resize.ts │ ├── resizing-algorithm.ts │ ├── return-attachment.ts │ ├── rotate.ts │ ├── saturation.ts │ ├── sharpen.ts │ ├── skip-processing.ts │ ├── strip-color-profile.ts │ ├── strip-metadata.ts │ ├── style.ts │ ├── trim.ts │ ├── unsharpen.ts │ ├── video-thumbnail-keyframes.ts │ ├── video-thumbnail-second.ts │ ├── video-thumbnail-tile.ts │ ├── watermark-shadow.ts │ ├── watermark-size.ts │ ├── watermark-text.ts │ ├── watermark-url.ts │ ├── watermark.ts │ └── zoom.ts └── utils.ts ├── test ├── .gitkeep ├── chain.test.ts ├── clone.test.ts ├── crypto │ ├── base64.test.ts │ ├── hmac.test.ts │ └── sha256.test.ts ├── override.test.ts ├── signature.test.ts ├── transformers.test.ts └── unset.test.ts ├── tsconfig.build.json ├── tsconfig.json └── typedoc.json /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # Update the VARIANT arg in docker-compose.yml to pick a Node version: 10, 12, 14 2 | ARG VARIANT=18 3 | FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT} 4 | 5 | # See https://github.com/microsoft/vscode-dev-containers/tree/master/containers/docker-from-docker for more documentation 6 | # On how to use docker from within docker 7 | 8 | # Install Docker CE CLI 9 | RUN apt-get update \ 10 | && apt-get install -y apt-transport-https ca-certificates curl gnupg2 lsb-release \ 11 | && curl -fsSL https://download.docker.com/linux/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/gpg | apt-key add - 2>/dev/null \ 12 | && echo "deb [arch=amd64] https://download.docker.com/linux/$(lsb_release -is | tr '[:upper:]' '[:lower:]') $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list \ 13 | && apt-get update \ 14 | && apt-get install -y docker-ce-cli 15 | 16 | # Install Docker Compose 17 | RUN LATEST_COMPOSE_VERSION=$(curl -sSL "https://api.github.com/repos/docker/compose/releases/latest" | grep -o -P '(?<="tag_name": ").+(?=")') \ 18 | && curl -sSL "https://github.com/docker/compose/releases/download/${LATEST_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose \ 19 | && chmod +x /usr/local/bin/docker-compose 20 | 21 | # Update args in docker-compose.yaml to set the UID/GID of the "node" user. 22 | ARG USER_UID=1000 23 | ARG USER_GID=$USER_UID 24 | RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then groupmod --gid $USER_GID node && usermod --uid $USER_UID --gid $USER_GID node; fi 25 | 26 | # Add the node user to the docker group to access 27 | # the daemon without sudo 28 | RUN groupadd docker 29 | RUN usermod -a -G docker node 30 | 31 | # Add minio CLI 32 | # See https://min.io/download#/linux 33 | RUN wget https://dl.min.io/client/mc/release/linux-amd64/mc \ 34 | && mv mc /usr/local/bin/minio-cli \ 35 | && chmod +x /usr/local/bin/minio-cli 36 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "imgproxy-js", 3 | "dockerComposeFile": "docker-compose.yml", 4 | "service": "application", 5 | "workspaceFolder": "/workspace", 6 | "customizations": { 7 | "vscode": { 8 | "settings": { 9 | "terminal.integrated.defaultProfile.linux": "bash" 10 | }, 11 | "extensions": [ 12 | "dbaeumer.vscode-eslint", 13 | "esbenp.prettier-vscode", 14 | "mikestead.dotenv", 15 | "ms-azuretools.vscode-docker", 16 | "ms-vsliveshare.vsliveshare", 17 | "wayou.vscode-todo-highlight", 18 | "streetsidesoftware.code-spell-checker" 19 | ] 20 | } 21 | }, 22 | "forwardPorts": [4000, 5000, 9000, 9001], 23 | "postCreateCommand": "bash -i .devcontainer/init.sh", 24 | "remoteUser": "node", 25 | "portsAttributes": { 26 | "4000": { 27 | "label": "Imgproxy Server" 28 | }, 29 | "5000": { 30 | "label": "Imgproxy Server (Unsigned)" 31 | }, 32 | "9000": { 33 | "label": "Minio Server" 34 | }, 35 | "9001": { 36 | "label": "Minio Console" 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /.devcontainer/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | networks: 4 | imgproxy-url-builder-network: 5 | name: imgproxy-url-builder-network 6 | driver: bridge 7 | 8 | volumes: 9 | imgproxy-url-builder-minio__data: 10 | driver: local 11 | 12 | services: 13 | application: 14 | container_name: imgproxy-url-builder 15 | build: 16 | context: . 17 | dockerfile: Dockerfile 18 | args: 19 | VARIANT: 20 20 | USER_UID: 1000 21 | USER_GID: 1000 22 | networks: 23 | - imgproxy-url-builder-network 24 | volumes: 25 | - ..:/workspace:cached 26 | - /var/run/docker.sock:/var/run/docker.sock 27 | command: sleep infinity 28 | user: node 29 | env_file: 30 | - ./workspace.env 31 | ports: 32 | - 4000:4000 33 | - 4001:4001 34 | - 4002:4002 35 | - 9000:9000 36 | - 9001:9001 37 | 38 | # Minio 39 | imgproxy-url-builder-minio: 40 | container_name: imgproxy-url-builder-minio 41 | image: minio/minio:RELEASE.2021-10-23T03-28-24Z 42 | network_mode: service:application 43 | volumes: 44 | - type: volume 45 | source: imgproxy-url-builder-minio__data 46 | target: /data 47 | volume: 48 | nocopy: false 49 | command: server /data --console-address :9001 50 | env_file: 51 | - ./minio.env 52 | 53 | # Imgproxy 54 | imgproxy-url-builder-imgproxy: 55 | container_name: imgproxy-url-builder-imgproxy 56 | image: darthsim/imgproxy:v3.13.2 57 | network_mode: service:application 58 | env_file: 59 | - ./imgproxy.env 60 | 61 | imgproxy-url-builder-imgproxy-unsigned: 62 | container_name: imgproxy-url-builder-imgproxy-unsigned 63 | image: darthsim/imgproxy:v3.13.2 64 | network_mode: service:application 65 | env_file: 66 | - ./imgproxy-unsigned.env 67 | 68 | imgproxy-url-builder-imgproxy-ttruncated: 69 | container_name: imgproxy-url-builder-imgproxy-truncated 70 | image: darthsim/imgproxy:v3.13.2 71 | network_mode: service:application 72 | env_file: 73 | - ./imgproxy-truncated.env 74 | -------------------------------------------------------------------------------- /.devcontainer/imgproxy-truncated.env: -------------------------------------------------------------------------------- 1 | IMGPROXY_BIND=0.0.0.0:4002 2 | IMGPROXY_ALLOWED_SOURCES=s3:// 3 | IMGPROXY_USE_S3=true 4 | IMGPROXY_S3_ENDPOINT=http://localhost:9000 5 | IMGPROXY_KEY=91bdcda48ce22cd7d8d3a0eda930b3db1762bc1cba5dc13542e723b68fe55d6f9d18199cbe35191a45faf22593405cad0fe76ffec67d24f8aee861ac8fe44d96 6 | IMGPROXY_SALT=72456c286761260f320391fe500fcec53755958dabd288867a6db072e1bc1dbd84b15079838a83a715edc1ecad50c3ce91dd8fdef6f981816fa274f91d8ecf06 7 | AWS_ACCESS_KEY_ID=minio_user 8 | AWS_SECRET_ACCESS_KEY=minio_password 9 | IMGPROXY_SIGNATURE_SIZE=13 -------------------------------------------------------------------------------- /.devcontainer/imgproxy-unsigned.env: -------------------------------------------------------------------------------- 1 | IMGPROXY_BIND=0.0.0.0:4001 2 | IMGPROXY_ALLOWED_SOURCES=s3:// 3 | IMGPROXY_USE_S3=true 4 | IMGPROXY_S3_ENDPOINT=http://localhost:9000 5 | AWS_ACCESS_KEY_ID=minio_user 6 | AWS_SECRET_ACCESS_KEY=minio_password -------------------------------------------------------------------------------- /.devcontainer/imgproxy.env: -------------------------------------------------------------------------------- 1 | IMGPROXY_BIND=0.0.0.0:4000 2 | IMGPROXY_ALLOWED_SOURCES=s3:// 3 | IMGPROXY_USE_S3=true 4 | IMGPROXY_S3_ENDPOINT=http://localhost:9000 5 | IMGPROXY_KEY=91bdcda48ce22cd7d8d3a0eda930b3db1762bc1cba5dc13542e723b68fe55d6f9d18199cbe35191a45faf22593405cad0fe76ffec67d24f8aee861ac8fe44d96 6 | IMGPROXY_SALT=72456c286761260f320391fe500fcec53755958dabd288867a6db072e1bc1dbd84b15079838a83a715edc1ecad50c3ce91dd8fdef6f981816fa274f91d8ecf06 7 | AWS_ACCESS_KEY_ID=minio_user 8 | AWS_SECRET_ACCESS_KEY=minio_password -------------------------------------------------------------------------------- /.devcontainer/init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Init minio 4 | minio-cli alias set myminio/ http://localhost:9000 minio_user minio_password 5 | 6 | # Init project 7 | nvm install 8 | nvm use 9 | nvm alias default $(node --version) 10 | nvm install-latest-npm 11 | npm i 12 | -------------------------------------------------------------------------------- /.devcontainer/minio-dump/test-bucket/test-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitPatty/imgproxy-url-builder/0d6c9dd0c09d75c274a8ffb8949bfb64422fc266/.devcontainer/minio-dump/test-bucket/test-image.png -------------------------------------------------------------------------------- /.devcontainer/minio-dump/test-bucket/test-image.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 43 | 45 | 46 | 48 | image/svg+xml 49 | 51 | 52 | 53 | 54 | 55 | 60 | 67 | 72 | 78 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /.devcontainer/minio.env: -------------------------------------------------------------------------------- 1 | MINIO_ACCESS_KEY=minio_user 2 | MINIO_SECRET_KEY=minio_password -------------------------------------------------------------------------------- /.devcontainer/test-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitPatty/imgproxy-url-builder/0d6c9dd0c09d75c274a8ffb8949bfb64422fc266/.devcontainer/test-image.png -------------------------------------------------------------------------------- /.devcontainer/workspace.env: -------------------------------------------------------------------------------- 1 | IMGPROXY_URL=http://localhost:4000 -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage/** 2 | dist/** 3 | scripts/** 4 | **/*.sh 5 | rollup.config.js 6 | populate-readme.cjs -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "node": true, 5 | "es6": true 6 | }, 7 | "ignorePatterns": ["coverage/**", "dist/**", "scripts/**", "**/*.sh"], 8 | "extends": [ 9 | "eslint:recommended", 10 | "plugin:@typescript-eslint/eslint-recommended", 11 | "plugin:@typescript-eslint/recommended", 12 | "plugin:jest/recommended", 13 | "plugin:prettier/recommended" 14 | ], 15 | "parser": "@typescript-eslint/parser", 16 | "parserOptions": { 17 | "project": "./tsconfig.json", 18 | "tsconfigRootDir": "./" 19 | }, 20 | "plugins": ["@typescript-eslint", "jest", "prettier"], 21 | "rules": { 22 | "@typescript-eslint/explicit-function-return-type": [ 23 | "error", 24 | { 25 | "allowExpressions": true, 26 | "allowConciseArrowFunctionExpressionsStartingWithVoid": true 27 | } 28 | ], 29 | "@typescript-eslint/no-floating-promises": ["error"], 30 | "@typescript-eslint/no-shadow": ["error"], 31 | "@typescript-eslint/explicit-member-accessibility": ["error"], 32 | "no-console": ["error"], 33 | "no-return-await": ["error"], 34 | "padding-line-between-statements": [ 35 | "error", 36 | { 37 | "blankLine": "always", 38 | "prev": "*", 39 | "next": "function" 40 | } 41 | ], 42 | "prettier/prettier": [ 43 | "error", 44 | {}, 45 | { 46 | "usePrettierrc": true 47 | } 48 | ], 49 | "require-await": ["error"] 50 | }, 51 | "overrides": [ 52 | { 53 | "files": ["test/**/*.js"], 54 | "rules": { 55 | "@typescript-eslint/explicit-function-return-type": "off" 56 | } 57 | } 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.css text eol=lf 2 | *.env text eol=lf 3 | *.js text eol=lf 4 | *.json text eol=lf 5 | *.lock text eol=lf 6 | *.md text eol=lf 7 | *.sh text eol=lf 8 | *.svg text eol=lf 9 | *.ts text eol=lf 10 | *.tsx text eol=lf 11 | *.yml text eol=lf 12 | 13 | # Dockerfiles 14 | *.Dockerfile text eol=lf 15 | Dockerfile text eol=lf 16 | 17 | # dotfiles 18 | .git* text eol=lf 19 | .npmignore text eol=lf 20 | .nvmrc text eol=lf 21 | .prettierrc text eol=lf 22 | 23 | # Binaries 24 | *.ico binary 25 | *.jpg binary 26 | *.png binary 27 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: npm 5 | directory: '/' 6 | schedule: 7 | interval: monthly 8 | open-pull-requests-limit: 5 9 | reviewers: 10 | - bitpatty 11 | labels: 12 | - dependencies 13 | groups: 14 | production-dependencies: 15 | dependency-type: 'production' 16 | development-dependencies: 17 | dependency-type: 'development' 18 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: push 4 | 5 | jobs: 6 | build: 7 | if: github.repository_owner == 'bitpatty' 8 | name: Build Project 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - uses: actions/setup-node@v3 13 | with: 14 | node-version: '22.10.0' 15 | - run: npm install 16 | - run: npm run build 17 | - run: npm run test 18 | - name: Coveralls 19 | uses: coverallsapp/github-action@v1 20 | -------------------------------------------------------------------------------- /.github/workflows/dependabot-auto-merge.yml: -------------------------------------------------------------------------------- 1 | name: auto-merge 2 | 3 | on: 4 | pull_request: 5 | 6 | jobs: 7 | auto-merge: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | - uses: ahmadnassri/action-dependabot-auto-merge@v2 12 | with: 13 | target: minor 14 | github-token: ${{ secrets.BOT_TOKEN }} 15 | -------------------------------------------------------------------------------- /.github/workflows/publish-npm-package.yml: -------------------------------------------------------------------------------- 1 | name: Publish npm package 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | publish-github: 9 | if: github.repository_owner == 'bitpatty' 10 | name: Publish NPM package (GitHub Registry) 11 | runs-on: ubuntu-latest 12 | environment: github-registry 13 | permissions: 14 | contents: read 15 | packages: write 16 | steps: 17 | - uses: actions/checkout@v3 18 | - uses: actions/setup-node@v3 19 | with: 20 | node-version: '22.10.0' 21 | registry-url: 'https://npm.pkg.github.com' 22 | scope: '@bitpatty' 23 | - run: npm install 24 | - run: npm run build 25 | - run: echo "registry=https://npm.pkg.github.com/@bitpatty" >> .npmrc 26 | - run: npm publish 27 | env: 28 | NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 29 | 30 | publish-npmjs: 31 | if: github.repository_owner == 'bitpatty' 32 | name: Publish NPM package (npmjs.org) 33 | runs-on: ubuntu-latest 34 | environment: npm-registry 35 | steps: 36 | - uses: actions/checkout@v3 37 | - uses: actions/setup-node@v3 38 | with: 39 | node-version: '22.10.0' 40 | registry-url: 'https://registry.npmjs.org' 41 | - run: npm install 42 | - run: npm run build 43 | - run: npm publish --access=public 44 | env: 45 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | /index.js 4 | coverage -------------------------------------------------------------------------------- /.ncurc.json: -------------------------------------------------------------------------------- 1 | { 2 | "reject": [] 3 | } 4 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v22.10.0 -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "printWidth": 80 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[html]": { 3 | "editor.defaultFormatter": "esbenp.prettier-vscode" 4 | }, 5 | "[javascript]": { 6 | "editor.defaultFormatter": "esbenp.prettier-vscode" 7 | }, 8 | "[javascriptreact]": { 9 | "editor.defaultFormatter": "esbenp.prettier-vscode" 10 | }, 11 | "[typescript]": { 12 | "editor.defaultFormatter": "esbenp.prettier-vscode" 13 | }, 14 | "[typescriptreact]": { 15 | "editor.defaultFormatter": "esbenp.prettier-vscode" 16 | }, 17 | "[json]": { 18 | "editor.quickSuggestions": { 19 | "strings": true 20 | }, 21 | "editor.suggest.insertMode": "replace", 22 | "editor.defaultFormatter": "esbenp.prettier-vscode" 23 | }, 24 | "files.autoSave": "off", 25 | "breadcrumbs.symbolSortOrder": "type", 26 | "coverage-gutters.coverageReportFileName": "coverage/**/index.html", 27 | "coverage-gutters.showLineCoverage": true, 28 | "editor.codeLens": true, 29 | "editor.detectIndentation": true, 30 | "editor.formatOnSave": true, 31 | "editor.minimap.maxColumn": 150, 32 | "editor.tabSize": 2, 33 | "explorer.confirmDragAndDrop": false, 34 | "files.associations": { 35 | "*.erb": "html", 36 | "*.html.erb": "html" 37 | }, 38 | "git.confirmSync": false, 39 | "git.enableSmartCommit": true, 40 | "html.format.wrapLineLength": 150, 41 | "javascript.updateImportsOnFileMove.enabled": "always", 42 | "search.exclude": { 43 | "**/*.eot": true, 44 | "**/*.png": true, 45 | "**/*.svg": true, 46 | "**/*.ttf": true, 47 | "**/*.woff": true, 48 | "**/*.woff2": true, 49 | "**/.git": true, 50 | "**/bower_components": true, 51 | "**/dist/": true, 52 | "**/node_modules": true, 53 | "**/tmp": true, 54 | "**/docs/": true 55 | }, 56 | "todohighlight.keywords": ["@TODO"], 57 | "typescript.preferences.importModuleSpecifier": "relative", 58 | "typescript.referencesCodeLens.enabled": true, 59 | "typescript.referencesCodeLens.showOnAllFunctions": true, 60 | "typescript.reportStyleChecksAsWarnings": true, 61 | "typescript.updateImportsOnFileMove.enabled": "always", 62 | "workbench.editor.enablePreview": false, 63 | "workbench.editor.enablePreviewFromQuickOpen": false, 64 | "cSpell.enabled": true, 65 | "cSpell.words": ["imgproxy", "rotr"], 66 | "cSpell.ignorePaths": [ 67 | ".devcontainer", 68 | ".github", 69 | "docs", 70 | "package-lock.json", 71 | "node_modules", 72 | "vscode-extension", 73 | ".git/objects", 74 | ".vscode", 75 | ".vscode-insiders" 76 | ] 77 | } 78 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Matteias Collet and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /docs/assets/highlight.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --light-hl-0: #795E26; 3 | --dark-hl-0: #DCDCAA; 4 | --light-hl-1: #000000; 5 | --dark-hl-1: #D4D4D4; 6 | --light-hl-2: #A31515; 7 | --dark-hl-2: #CE9178; 8 | --light-hl-3: #0000FF; 9 | --dark-hl-3: #569CD6; 10 | --light-hl-4: #AF00DB; 11 | --dark-hl-4: #C586C0; 12 | --light-hl-5: #001080; 13 | --dark-hl-5: #9CDCFE; 14 | --light-hl-6: #008000; 15 | --dark-hl-6: #6A9955; 16 | --light-hl-7: #098658; 17 | --dark-hl-7: #B5CEA8; 18 | --light-hl-8: #0070C1; 19 | --dark-hl-8: #4FC1FF; 20 | --light-code-background: #FFFFFF; 21 | --dark-code-background: #1E1E1E; 22 | } 23 | 24 | @media (prefers-color-scheme: light) { :root { 25 | --hl-0: var(--light-hl-0); 26 | --hl-1: var(--light-hl-1); 27 | --hl-2: var(--light-hl-2); 28 | --hl-3: var(--light-hl-3); 29 | --hl-4: var(--light-hl-4); 30 | --hl-5: var(--light-hl-5); 31 | --hl-6: var(--light-hl-6); 32 | --hl-7: var(--light-hl-7); 33 | --hl-8: var(--light-hl-8); 34 | --code-background: var(--light-code-background); 35 | } } 36 | 37 | @media (prefers-color-scheme: dark) { :root { 38 | --hl-0: var(--dark-hl-0); 39 | --hl-1: var(--dark-hl-1); 40 | --hl-2: var(--dark-hl-2); 41 | --hl-3: var(--dark-hl-3); 42 | --hl-4: var(--dark-hl-4); 43 | --hl-5: var(--dark-hl-5); 44 | --hl-6: var(--dark-hl-6); 45 | --hl-7: var(--dark-hl-7); 46 | --hl-8: var(--dark-hl-8); 47 | --code-background: var(--dark-code-background); 48 | } } 49 | 50 | :root[data-theme='light'] { 51 | --hl-0: var(--light-hl-0); 52 | --hl-1: var(--light-hl-1); 53 | --hl-2: var(--light-hl-2); 54 | --hl-3: var(--light-hl-3); 55 | --hl-4: var(--light-hl-4); 56 | --hl-5: var(--light-hl-5); 57 | --hl-6: var(--light-hl-6); 58 | --hl-7: var(--light-hl-7); 59 | --hl-8: var(--light-hl-8); 60 | --code-background: var(--light-code-background); 61 | } 62 | 63 | :root[data-theme='dark'] { 64 | --hl-0: var(--dark-hl-0); 65 | --hl-1: var(--dark-hl-1); 66 | --hl-2: var(--dark-hl-2); 67 | --hl-3: var(--dark-hl-3); 68 | --hl-4: var(--dark-hl-4); 69 | --hl-5: var(--dark-hl-5); 70 | --hl-6: var(--dark-hl-6); 71 | --hl-7: var(--dark-hl-7); 72 | --hl-8: var(--dark-hl-8); 73 | --code-background: var(--dark-code-background); 74 | } 75 | 76 | .hl-0 { color: var(--hl-0); } 77 | .hl-1 { color: var(--hl-1); } 78 | .hl-2 { color: var(--hl-2); } 79 | .hl-3 { color: var(--hl-3); } 80 | .hl-4 { color: var(--hl-4); } 81 | .hl-5 { color: var(--hl-5); } 82 | .hl-6 { color: var(--hl-6); } 83 | .hl-7 { color: var(--hl-7); } 84 | .hl-8 { color: var(--hl-8); } 85 | pre, code { background: var(--code-background); } 86 | -------------------------------------------------------------------------------- /docs/assets/navigation.js: -------------------------------------------------------------------------------- 1 | window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAA5XYXW/TMBQG4P+S64myic/dtRS2gQZl65gE4uIsOU1MHTuyna0Z4r+jfUDsxCfHu35fP2lqO43743fmcOeyw+zIQCFQuaUwmDuhVbaXNeCq7DBD1dZ2Nio8q1wts71sK1SRHb75s+db18J1667BiPIvosefoRW3GBveJ8xoocq5LLURrqqjiF+grQtlKzANKqHKU12MPs8wp6VLcGhqMNuVtiL2/Y4KtLUCA/WiFbJA0zO5BGvRzvw0NPYPfGVe/Gqt+9LcXcv2jOsatLMgDJWD529f77888KQF5NvS6FYVc9lUQJDxVrrNsqmibM0S3cMiptBIJ8Wd4FIVI8rKKbSWsoYFVrxbChTmZZzzDvIKF611SN3muMGaWjkD5CocxKxmdENJfcQpy9UJgfQJazTUd9QnrGHghlunsQ7rttpphZQYpJz1ftcIg9RSDVPecqiKuW0wd2fghCbVeC/Nn0QTpQ8g5RXk25MaSrwwkjCJGqsLiZ+hpiZoELOaNjVQ+ysI06SvLUjhukkw7HDukdgQWp+wxuPLCQWFcYJ2Td9jmHLWMdjKtjVhhSlnfWywJCAv4pRT2C06R27aQcxqQh3j3S8SxQ3yBO9SFK6iOT9mNa10XhlN7qZRgRNXUBRCUdMQprxVUp/Li1hF7FCCI6UwZjX63tLvy6BFakEEISdNP22e9px5ODsQVBAmSf4BYgqN9FhfO5j40R/EnHYOrjVT3qjAig9nHooLUtbaimZldI7W0tsqWmJl10lquv2Mc9ZGUBPsRZzinxQJLVLh1G+iQL2u2vpKgZCfsNsYqMlH+3T7adc6x1yTb1MT1addZS3IKSSL3BX+H7QJeJgne+cVFPqGU4NWuk0/umKdZHeNO+pBHesku/RbcaTCqd+1pnagF3FKXoHw/nXZtOr+1GRn90E4+tULb2CBG2iliw19jEaDf/4FX4DUo1kTAAA=" -------------------------------------------------------------------------------- /docs/types/BlurOptions.html: -------------------------------------------------------------------------------- 1 | BlurOptions | @bitpatty/imgproxy-url-builder
BlurOptions: number

The blur radius

2 |
3 | -------------------------------------------------------------------------------- /docs/types/BrightnessOptions.html: -------------------------------------------------------------------------------- 1 | BrightnessOptions | @bitpatty/imgproxy-url-builder
BrightnessOptions: number

The brightness, an integer ranging from -255 to 255.

2 |
3 | -------------------------------------------------------------------------------- /docs/types/CacheBusterOptions.html: -------------------------------------------------------------------------------- 1 | CacheBusterOptions | @bitpatty/imgproxy-url-builder
CacheBusterOptions: string

The cache buster

2 |
3 | -------------------------------------------------------------------------------- /docs/types/ContrastOptions.html: -------------------------------------------------------------------------------- 1 | ContrastOptions | @bitpatty/imgproxy-url-builder
ContrastOptions: number

The percentage (positive floating number from 0-1)

2 |
3 | -------------------------------------------------------------------------------- /docs/types/DPIOptions.html: -------------------------------------------------------------------------------- 1 | DPIOptions | @bitpatty/imgproxy-url-builder
DPIOptions: number

The DPI value

2 |
3 | -------------------------------------------------------------------------------- /docs/types/DprOptions.html: -------------------------------------------------------------------------------- 1 | DprOptions | @bitpatty/imgproxy-url-builder
DprOptions: number

The DPR factor (must be greater than 0)

2 |
3 | -------------------------------------------------------------------------------- /docs/types/FileNameOptions.html: -------------------------------------------------------------------------------- 1 | FileNameOptions | @bitpatty/imgproxy-url-builder
FileNameOptions: string

The file name

2 |
3 | -------------------------------------------------------------------------------- /docs/types/MaxBytesOptions.html: -------------------------------------------------------------------------------- 1 | MaxBytesOptions | @bitpatty/imgproxy-url-builder
MaxBytesOptions: number

The number of bytes

2 |
3 | -------------------------------------------------------------------------------- /docs/types/MinHeightOptions.html: -------------------------------------------------------------------------------- 1 | MinHeightOptions | @bitpatty/imgproxy-url-builder
MinHeightOptions: number

The min height of the resulting image

2 |
3 | -------------------------------------------------------------------------------- /docs/types/MinWidthOptions.html: -------------------------------------------------------------------------------- 1 | MinWidthOptions | @bitpatty/imgproxy-url-builder
MinWidthOptions: number

The min width of the resulting image

2 |
3 | -------------------------------------------------------------------------------- /docs/types/PageOptions.html: -------------------------------------------------------------------------------- 1 | PageOptions | @bitpatty/imgproxy-url-builder
PageOptions: number

The page number (starting from 0)

2 |
3 | -------------------------------------------------------------------------------- /docs/types/PixelateOptions.html: -------------------------------------------------------------------------------- 1 | PixelateOptions | @bitpatty/imgproxy-url-builder
PixelateOptions: number

The size of a pixel

2 |
3 | -------------------------------------------------------------------------------- /docs/types/QualityOptions.html: -------------------------------------------------------------------------------- 1 | QualityOptions | @bitpatty/imgproxy-url-builder
QualityOptions: number

The quality in percentage (floating point number from 0.0 to 1.0)

2 |
3 | -------------------------------------------------------------------------------- /docs/types/SharpenOptions.html: -------------------------------------------------------------------------------- 1 | SharpenOptions | @bitpatty/imgproxy-url-builder
SharpenOptions: number

The size of the sharpen mask (floating point number)

2 |
3 | -------------------------------------------------------------------------------- /docs/types/WatermarkTextOptions.html: -------------------------------------------------------------------------------- 1 | WatermarkTextOptions | @bitpatty/imgproxy-url-builder
WatermarkTextOptions: string

The watermark text

2 |
3 | -------------------------------------------------------------------------------- /docs/types/WatermarkUrlOptions.html: -------------------------------------------------------------------------------- 1 | WatermarkUrlOptions | @bitpatty/imgproxy-url-builder
WatermarkUrlOptions: string

The watermark URL

2 |
3 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { JestConfigWithTsJest } from 'ts-jest'; 2 | 3 | export default (): JestConfigWithTsJest => { 4 | return { 5 | preset: 'ts-jest', 6 | testEnvironment: 'node', 7 | coverageReporters: ['lcov', 'html', 'json'], 8 | setupFilesAfterEnv: ['./jest.setup.ts'], 9 | verbose: true, 10 | testMatch: ['**/*.test.ts'], 11 | extensionsToTreatAsEsm: ['.ts'], 12 | moduleNameMapper: { 13 | '^(\\.{1,2}/.*)\\.js$': '$1', 14 | }, 15 | transform: { 16 | '^.+\\.tsx?$': [ 17 | 'ts-jest', 18 | { 19 | tsconfig: 'tsconfig.json', 20 | useESM: true, 21 | }, 22 | ], 23 | }, 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /jest.globals.ts: -------------------------------------------------------------------------------- 1 | const jestGlobals = { 2 | buildOptions: { 3 | signature: { 4 | key: '91bdcda48ce22cd7d8d3a0eda930b3db1762bc1cba5dc13542e723b68fe55d6f9d18199cbe35191a45faf22593405cad0fe76ffec67d24f8aee861ac8fe44d96', 5 | salt: '72456c286761260f320391fe500fcec53755958dabd288867a6db072e1bc1dbd84b15079838a83a715edc1ecad50c3ce91dd8fdef6f981816fa274f91d8ecf06', 6 | }, 7 | baseUrl: 'http://localhost:4000', 8 | path: 's3://test-bucket/test-image.png', 9 | }, 10 | }; 11 | 12 | export default jestGlobals; 13 | -------------------------------------------------------------------------------- /jest.setup.ts: -------------------------------------------------------------------------------- 1 | import { ParamBuilder } from './src/index.js'; 2 | 3 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 4 | // @ts-ignore 5 | declare global { 6 | // eslint-disable-next-line @typescript-eslint/no-namespace 7 | namespace jest { 8 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 9 | interface Matchers { 10 | toIncludeModifier(str: string): jest.CustomMatcherResult; 11 | toIncludeModifierIdentifier( 12 | keyof: keyof ParamBuilder, 13 | ): jest.CustomMatcherResult; 14 | } 15 | } 16 | } 17 | 18 | expect.extend({ 19 | toIncludeModifier( 20 | received: ParamBuilder, 21 | expected: string, 22 | ): jest.CustomMatcherResult { 23 | const values = Array.from(received.modifiers.values()); 24 | const hasValue = values.includes(expected); 25 | 26 | return { 27 | pass: hasValue, 28 | message: () => 29 | hasValue 30 | ? '' 31 | : `Could not find modifier "${expected}" in ${JSON.stringify( 32 | values, 33 | )} `, 34 | }; 35 | }, 36 | 37 | toIncludeModifierIdentifier( 38 | received: ParamBuilder, 39 | expected: keyof ParamBuilder, 40 | ): jest.CustomMatcherResult { 41 | const values = Array.from(received.modifiers.keys()); 42 | const hasValue = values.includes(expected); 43 | 44 | return { 45 | pass: hasValue, 46 | message: () => 47 | hasValue 48 | ? '' 49 | : `Could not find modifier identifier "${expected}" in ${JSON.stringify( 50 | values, 51 | )} `, 52 | }; 53 | }, 54 | }); 55 | 56 | export default undefined; 57 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bitpatty/imgproxy-url-builder", 3 | "version": "2.0.0-rc1", 4 | "description": "A TypeScript helper library for building imgproxy URLs", 5 | "author": "Matteias Collet ", 6 | "contributors": [ 7 | { 8 | "name": "Coo van Leeuwen", 9 | "url": "https://github.com/c00" 10 | }, 11 | { 12 | "name": "Ushakov Fedor", 13 | "url": "https://github.com/ushakovfserg" 14 | } 15 | ], 16 | "type": "module", 17 | "main": "dist/cjs/index.js", 18 | "module": "dist/esm/index.js", 19 | "types": "dist/types/index.d.ts", 20 | "exports": { 21 | ".": { 22 | "import": "./dist/esm/index.js", 23 | "require": "./dist/cjs/index.js", 24 | "types": "./dist/types/index.d.ts" 25 | } 26 | }, 27 | "scripts": { 28 | "prebuild": "rm -rf dist", 29 | "build": "rollup -c", 30 | "test": "jest --verbose --coverage", 31 | "docs": "typedoc && node scripts/populate-readme.cjs", 32 | "deps:force-upgrade": "npm-check-updates -u && rm -rf node_modules && rm -f package-lock.json && npm i" 33 | }, 34 | "keywords": [ 35 | "imgproxy", 36 | "imgproxyjs", 37 | "browser", 38 | "node" 39 | ], 40 | "repository": { 41 | "type": "git", 42 | "url": "https://github.com/BitPatty/imgproxy-url-builder.git" 43 | }, 44 | "license": "MIT", 45 | "bugs": { 46 | "url": "https://github.com/BitPatty/imgproxy-url-builder/issues" 47 | }, 48 | "files": [ 49 | "dist" 50 | ], 51 | "homepage": "https://github.com/BitPatty/imgproxy-url-builder#readme", 52 | "devDependencies": { 53 | "@types/jest": "29.5.14", 54 | "@types/node": "22.15.3", 55 | "@typescript-eslint/eslint-plugin": "8.31.1", 56 | "@typescript-eslint/parser": "8.31.1", 57 | "crypto-js": "4.2.0", 58 | "eslint": "9.25.1", 59 | "eslint-config-prettier": "10.1.2", 60 | "eslint-plugin-jest": "28.11.0", 61 | "eslint-plugin-prettier": "5.2.6", 62 | "npm-check-updates": "18.0.1", 63 | "prettier": "3.5.3", 64 | "rollup": "4.40.1", 65 | "rollup-plugin-typescript2": "0.36.0", 66 | "ts-jest": "29.3.2", 67 | "ts-node": "10.9.2", 68 | "tslib": "2.8.1", 69 | "typedoc": "0.28.3", 70 | "typescript": "5.8.3" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import pkg from './package.json' with { type: 'json' }; 2 | 3 | import fs from 'fs'; 4 | import path, { dirname } from 'path'; 5 | import { fileURLToPath } from 'url'; 6 | 7 | import typescript from 'rollup-plugin-typescript2'; 8 | 9 | const __dirname = dirname(fileURLToPath(import.meta.url)); 10 | 11 | const createPackageJson = { 12 | writeBundle: (opts) => { 13 | if (!['es', 'cjs'].includes(opts.format) || opts.file === pkg.types) return; 14 | const dirName = path.join(__dirname, path.dirname(opts.file)); 15 | const output = JSON.stringify({ 16 | type: opts.format === 'es' ? 'module' : 'commonjs', 17 | }); 18 | fs.writeFileSync(path.join(dirName, 'package.json'), output); 19 | }, 20 | }; 21 | 22 | export default { 23 | input: 'src/index.ts', 24 | output: [ 25 | { 26 | file: pkg.main, 27 | format: 'cjs', 28 | exports: 'named', 29 | sourcemap: true, 30 | strict: true, 31 | compact: false, 32 | }, 33 | { 34 | file: pkg.module, 35 | format: 'es', 36 | exports: 'named', 37 | sourcemap: true, 38 | strict: true, 39 | compact: false, 40 | }, 41 | ], 42 | plugins: [ 43 | typescript({ 44 | tsconfig: 'tsconfig.build.json', 45 | useTsconfigDeclarationDir: true, 46 | tsconfigOverride: { 47 | compilerOptions: { 48 | declaration: true, 49 | declarationDir: dirname(pkg.types), 50 | }, 51 | }, 52 | }), 53 | createPackageJson, 54 | ], 55 | external: [], 56 | }; 57 | -------------------------------------------------------------------------------- /scripts/micro-benchmark.cjs: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto'); 2 | const { performance } = require('perf_hooks'); 3 | const CryptoJS = require('crypto-js'); 4 | const { hmac } = require('../dist/cjs'); 5 | 6 | // Configuration for the benchmark 7 | const message = 'Benchmarking HMAC performance'; 8 | const key = 'supersecretkey'; 9 | const initialIterations = 1000; 10 | const maxIterations = 100000; 11 | const incrementFactor = 10; 12 | 13 | // Node.js native HMAC implementation 14 | function nativeHmac(key, message) { 15 | return crypto.createHmac('sha256', key).update(message).digest('hex'); 16 | } 17 | 18 | // CryptoJS HMAC implementation 19 | function cryptoJsHmac(key, message) { 20 | return CryptoJS.HmacSHA256(message, key).toString(CryptoJS.enc.Hex); 21 | } 22 | 23 | // Benchmark function to measure execution time 24 | function benchmark(label, func, iterations) { 25 | const start = performance.now(); 26 | for (let i = 0; i < iterations; i++) { 27 | func(); 28 | } 29 | const end = performance.now(); 30 | console.log( 31 | `${label} took ${(end - start).toFixed(2)} ms for ${iterations} iterations`, 32 | ); 33 | } 34 | 35 | // Ensure the key and message are in Uint8Array format for the 36 | // custom HMAC function 37 | const keyBytes = new Uint8Array(Buffer.from(key, 'utf-8')); 38 | const messageBytes = new Uint8Array(Buffer.from(message, 'utf-8')); 39 | 40 | console.log('Starting HMAC performance comparison:'); 41 | for ( 42 | let iterations = initialIterations; 43 | iterations <= maxIterations; 44 | iterations *= incrementFactor 45 | ) { 46 | console.log(`\nRunning ${iterations} iterations:`); 47 | 48 | benchmark('Node Native HMAC', () => nativeHmac(key, message), iterations); 49 | benchmark('CryptoJS HMAC', () => cryptoJsHmac(key, message), iterations); 50 | benchmark( 51 | 'Custom HMAC Implementation', 52 | () => hmac(keyBytes, messageBytes), 53 | iterations, 54 | ); 55 | } 56 | -------------------------------------------------------------------------------- /scripts/minio-dump.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | SCRIPT_PATH=$(dirname "$0") 4 | echo "Dumping minio files" 5 | cd $SCRIPT_PATH/.. 6 | minio-cli cp --recursive myminio ./.devcontainer/minio-dump -------------------------------------------------------------------------------- /scripts/minio-restore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | SCRIPT_PATH=$(dirname "$0") 4 | echo "Restoring minio files" 5 | cd $SCRIPT_PATH/../.devcontainer/minio-dump 6 | minio-cli mb --ignore-existing myminio/test-bucket 7 | minio-cli rm --recursive --force myminio/test-bucket || true 8 | minio-cli cp --recursive . myminio -------------------------------------------------------------------------------- /scripts/populate-readme.cjs: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const pbLines = fs 5 | .readFileSync(path.join(__dirname, '..', 'src', 'param-builder.ts')) 6 | .toString() 7 | .split('\n'); 8 | 9 | const readmeLines = fs 10 | .readFileSync(path.join(__dirname, '..', 'README.md')) 11 | .toString() 12 | .split('\n'); 13 | 14 | const comments = []; 15 | let currentComment = null; 16 | 17 | for (let i = 0; i < pbLines.length; i++) { 18 | if (currentComment && pbLines[i].includes('*/')) { 19 | comments.push(currentComment); 20 | currentComment = null; 21 | continue; 22 | } 23 | 24 | if (currentComment == null && pbLines[i].includes('/*')) { 25 | currentComment = pbLines[i]; 26 | continue; 27 | } 28 | 29 | if (currentComment != null) { 30 | currentComment += `\n${pbLines[i]}`; 31 | } 32 | } 33 | 34 | const commentsWithExamples = comments.filter((c) => c.includes('@example')); 35 | 36 | const transformers = []; 37 | 38 | for (let i = 0; i < commentsWithExamples.length; i++) { 39 | const textLines = commentsWithExamples[i] 40 | .split('\n') 41 | .map((l) => l.trim().replace(/^[/*]+ {0,1}/, '')); 42 | 43 | let mode = 'description'; 44 | let description = ''; 45 | let example = ''; 46 | let url = ''; 47 | let functionName = ''; 48 | 49 | for (let j = 0; j < textLines.length; j++) { 50 | if ( 51 | textLines[j].trim().startsWith('See https://github.com/imgproxy/imgproxy') 52 | ) { 53 | mode = 'link'; 54 | } else if (textLines[j].startsWith('@example')) { 55 | mode = 'example'; 56 | } else if (mode !== 'description') { 57 | continue; 58 | } 59 | 60 | switch (mode) { 61 | case 'description': 62 | description += ` ${textLines[j]}`; 63 | break; 64 | case 'link': 65 | url = textLines[j].replace(/^.+(https\:\/\/[^ ]+).+$/, '$1'); 66 | break; 67 | case 'example': 68 | for (let k = j + 1; k < textLines.length; k++) { 69 | if (k !== j + 1 && textLines[k].includes('```')) { 70 | example += '\n```'; 71 | break; 72 | } 73 | 74 | if (!functionName && k >= j + 2 && textLines[k].startsWith('pb()')) { 75 | functionName = textLines[k].replace(/^pb\(\)\.([^(]+).+$/, '$1'); 76 | } 77 | 78 | example += `\n${textLines[k]}`; 79 | } 80 | } 81 | } 82 | 83 | if (description && url && example && functionName) 84 | transformers.push({ description, url, example, functionName }); 85 | } 86 | 87 | const sortedTransformers = transformers.sort((a, b) => 88 | a.functionName.trim().toLowerCase() < b.functionName.trim().toLowerCase() 89 | ? -1 90 | : 1, 91 | ); 92 | 93 | const toc = []; 94 | const markdown = []; 95 | for (let i = 0; i < sortedTransformers.length; i++) { 96 | toc.push( 97 | `- [${sortedTransformers[i].functionName}](#${sortedTransformers[ 98 | i 99 | ].functionName.toLowerCase()}-imgproxy-docs)`, 100 | ); 101 | markdown.push(''); 102 | markdown.push( 103 | `### ${sortedTransformers[i].functionName} ([imgproxy docs](${sortedTransformers[i].url}))`, 104 | ); 105 | markdown.push(''); 106 | markdown.push(sortedTransformers[i].description.trim()); 107 | markdown.push(''); 108 | markdown.push('#### Example'); 109 | markdown.push(''); 110 | markdown.push(sortedTransformers[i].example.trim()); 111 | } 112 | 113 | let newReadme = []; 114 | 115 | for (let i = 0; i < readmeLines.length; i++) { 116 | newReadme.push(readmeLines[i]); 117 | 118 | if (readmeLines[i].startsWith('## Modifiers')) { 119 | break; 120 | } 121 | } 122 | 123 | newReadme.push(''); 124 | newReadme.push(...toc); 125 | newReadme.push(...markdown); 126 | 127 | fs.writeFileSync('README.md', newReadme.join('\n')); 128 | -------------------------------------------------------------------------------- /src/common.ts: -------------------------------------------------------------------------------- 1 | import { base64urlEncode, parseHexString, utf8encode } from './crypto/codec.js'; 2 | import { wordArrayToByteArray } from './crypto/common.js'; 3 | import { hmac } from './crypto/hmac.js'; 4 | 5 | /** 6 | * Stringifies the imgproxy modifier for use within the 7 | * imgproxy URL. 8 | * 9 | * @param opCode The operation key 10 | * @param values The values 11 | * @returns The stringified modifier 12 | */ 13 | const stringifyOptions = ( 14 | opCode: string, 15 | values: Array, 16 | ): string => { 17 | return [ 18 | opCode, 19 | ...values.map((v) => (v == null ? '' : encodeURIComponent(v))), 20 | ] 21 | .join(':') 22 | .replace(/:+$/, ''); 23 | }; 24 | 25 | /** 26 | * Encodes the filepath to base64url. 27 | * 28 | * @param filePath The file path 29 | * @returns The base64url encoded file path 30 | */ 31 | const encodeFilePath = (filePath: string): string => { 32 | return base64urlEncode(utf8encode(filePath)); 33 | }; 34 | 35 | /** 36 | * Generates the URL signature for the specified imgproxy param string. 37 | * 38 | * See https://github.com/imgproxy/imgproxy/blob/947d65cf29fe26e5e4d38ca8a17e44c7402e437c/docs/configuration.md#url-signature 39 | * 40 | * @param paramString The param string 41 | * @param key The hex-encoded key 42 | * @param salt The hex-encoded salt 43 | * @param length The number of bytes to use for the signature before encoding to Base64 44 | * @returns The base64url encoded signature 45 | */ 46 | const generateSignature = ( 47 | paramString: string, 48 | key: string, 49 | salt: string, 50 | length: number, 51 | ): string => { 52 | const path = paramString.startsWith('/') ? paramString : `/${paramString}`; 53 | 54 | // Parse key and salt from hex and ensure they're Uint8Array 55 | const keyBytes = parseHexString(key); 56 | const saltBytes = parseHexString(salt); 57 | 58 | // Create HMAC using the key and the combination of salt and path 59 | const h = hmac(keyBytes, new Uint8Array([...saltBytes, ...utf8encode(path)])); 60 | 61 | // Convert the HMAC output (Uint32Array) into a byte array (Uint8Array) 62 | const truncated = wordArrayToByteArray(h).slice(0, length); 63 | 64 | // Return the base64url-encoded signature 65 | return base64urlEncode(truncated); 66 | }; 67 | 68 | export { stringifyOptions, encodeFilePath, generateSignature }; 69 | -------------------------------------------------------------------------------- /src/crypto/codec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Masks the lowest 6 bits of the specified number 3 | * 4 | * @param num The number 5 | * @returns The lowest 6 bits 6 | */ 7 | const low6 = (num: number): number => num & 0b0011_1111; 8 | 9 | /** 10 | * UTF-8 encodes the specified message 11 | * 12 | * @param msg The message 13 | * @returns The encoded message as a Uint8Array of bytes 14 | */ 15 | const utf8encode = (msg: string): Uint8Array => { 16 | const encoder = new TextEncoder(); 17 | return encoder.encode(msg); 18 | }; 19 | 20 | /** 21 | * Parses a hex character and returns its numeric value 22 | * 23 | * @param char The hex char 24 | * @returns The numeric value 25 | */ 26 | const parseHexChar = (char: string): number => { 27 | if (['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].includes(char)) 28 | return +char; 29 | switch (char.toUpperCase()) { 30 | case 'A': 31 | return 0xa; 32 | case 'B': 33 | return 0xb; 34 | case 'C': 35 | return 0xc; 36 | case 'D': 37 | return 0xd; 38 | case 'E': 39 | return 0xe; 40 | case 'F': 41 | return 0xf; 42 | } 43 | 44 | throw new Error(`Invalid hex char: ${char}`); 45 | }; 46 | 47 | /** 48 | * Parses a string containing hex characters 49 | * into an array of bytes 50 | * 51 | * @param str The string 52 | * @returns The Uint8Array of parsed bytes 53 | */ 54 | const parseHexString = (str: string): Uint8Array => { 55 | const res = new Uint8Array(Math.ceil(str.length / 2)); 56 | 57 | for (let i = 0; i < str.length; i += 2) { 58 | res[i / 2] = (parseHexChar(str[i]) << 4) | parseHexChar(str[i + 1] || '0'); 59 | } 60 | 61 | return res; 62 | }; 63 | 64 | /** 65 | * Encodes the lowest 6 bits of the specified 66 | * number to its base64url representation 67 | * 68 | * @param b The number 69 | * @returns The base64url encoded character 70 | */ 71 | const base64urlChar = (b: number): string => { 72 | const r = low6(b); 73 | 74 | // Uppercase letters 75 | if (r <= 25) return String.fromCharCode(65 + r); 76 | // Lowercase letters 77 | if (r <= 51) return String.fromCharCode(97 + r - 26); 78 | // Numbers 79 | if (r <= 61) return String.fromCharCode(48 + r - 52); 80 | // Base64 URL replacements for '+' and '/' 81 | return r === 62 ? '-' : '_'; 82 | }; 83 | 84 | /** 85 | * Encodes the specified array of bytes to 86 | * its base64url representation 87 | * 88 | * @param bytes The Uint8Array of bytes 89 | * @returns The base64url string 90 | */ 91 | const base64urlEncode = (bytes: Uint8Array): string => { 92 | let res = ''; 93 | 94 | for (let i = 0; i < bytes.length; i += 3) { 95 | // First byte 96 | res += base64urlChar(bytes[i] >>> 2); 97 | // Second byte 98 | res += base64urlChar(((bytes[i] & 0b11) << 4) | (bytes[i + 1] >>> 4)); 99 | // Handle cases where fewer than 3 bytes are available 100 | if (i + 1 < bytes.length) { 101 | res += base64urlChar( 102 | ((bytes[i + 1] & 0b1111) << 2) | (bytes[i + 2] >>> 6), 103 | ); 104 | if (i + 2 < bytes.length) { 105 | res += base64urlChar(bytes[i + 2] & 0b0011_1111); 106 | } 107 | } 108 | } 109 | 110 | return res; 111 | }; 112 | 113 | export { utf8encode, base64urlEncode, parseHexString }; 114 | -------------------------------------------------------------------------------- /src/crypto/common.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The block size used for hashing functions 3 | */ 4 | const BLOCK_SIZE = 512; 5 | 6 | /** 7 | * Converts a word array (Uint32Array) into a byte array (Uint8Array) 8 | * 9 | * @param wordArray The Uint32Array 10 | * @returns The Uint8Array 11 | */ 12 | const wordArrayToByteArray = (wordArray: Uint32Array): Uint8Array => { 13 | const byteArray = new Uint8Array(wordArray.length * 4); 14 | for (let i = 0; i < wordArray.length; i++) { 15 | byteArray[i * 4] = (wordArray[i] >>> 24) & 0xff; 16 | byteArray[i * 4 + 1] = (wordArray[i] >>> 16) & 0xff; 17 | byteArray[i * 4 + 2] = (wordArray[i] >>> 8) & 0xff; 18 | byteArray[i * 4 + 3] = wordArray[i] & 0xff; 19 | } 20 | return byteArray; 21 | }; 22 | 23 | /** 24 | * Converts a byte array (Uint8Array) into a word array (Uint32Array) 25 | * 26 | * @param byteArray The Uint8Array 27 | * @returns The Uint32Array 28 | */ 29 | const byteArrayToWordArray = (byteArray: Uint8Array): Uint32Array => { 30 | const wordArray = new Uint32Array(byteArray.length / 4); 31 | for (let i = 0; i < wordArray.length; i++) { 32 | wordArray[i] = 33 | (byteArray[i * 4] << 24) | 34 | (byteArray[i * 4 + 1] << 16) | 35 | (byteArray[i * 4 + 2] << 8) | 36 | byteArray[i * 4 + 3]; 37 | } 38 | return wordArray; 39 | }; 40 | 41 | export { BLOCK_SIZE, wordArrayToByteArray, byteArrayToWordArray }; 42 | -------------------------------------------------------------------------------- /src/crypto/hmac.ts: -------------------------------------------------------------------------------- 1 | import { sha256 } from './sha256.js'; 2 | import { BLOCK_SIZE, wordArrayToByteArray } from './common.js'; 3 | 4 | /** 5 | * Pads the specified byte-array to the block size. 6 | * 7 | * @param arr The Uint8Array 8 | * @param val The value to pad the array with 9 | * @returns The padded Uint8Array 10 | */ 11 | const blockPad = (arr: Uint8Array, val = 0): Uint8Array => { 12 | const paddingSize = BLOCK_SIZE / 8 - arr.length; 13 | const paddedArray = new Uint8Array(arr.length + paddingSize); 14 | paddedArray.set(arr); 15 | if (val !== 0) { 16 | paddedArray.fill(val, arr.length); 17 | } 18 | return paddedArray; 19 | }; 20 | 21 | /** 22 | * Gets the block-padded key. 23 | * If the key is longer than the block size, it is hashed using SHA-256. 24 | * If the key is shorter, it is padded to the block size. 25 | * 26 | * @param keyBytes The key as a Uint8Array 27 | * @returns The block-padded key 28 | */ 29 | const getBlockKey = (keyBytes: Uint8Array): Uint8Array => { 30 | // If key is exactly BLOCK_SIZE (512 bits), return as is. 31 | if (keyBytes.length === BLOCK_SIZE / 8) return keyBytes; 32 | 33 | // If key is longer than BLOCK_SIZE, hash it and use that as the key. 34 | if (keyBytes.length > BLOCK_SIZE / 8) 35 | return blockPad(wordArrayToByteArray(sha256(keyBytes))); 36 | 37 | // Otherwise, pad the key to the block size. 38 | return blockPad(keyBytes); 39 | }; 40 | 41 | /** 42 | * Creates the HMAC of the specified message. 43 | * Combines the key and message using inner and outer padding and returns the final HMAC as a Uint32Array. 44 | * 45 | * @param key The key (Uint8Array) 46 | * @param message The message (Uint8Array) 47 | * @returns The HMAC as a Uint32Array 48 | */ 49 | const hmac = (key: Uint8Array, message: Uint8Array): Uint32Array => { 50 | const bK = getBlockKey(key); // Get block-padded key 51 | 52 | // Initialize inner and outer padding 53 | const oPad = new Uint8Array(bK.length); 54 | const iPad = new Uint8Array(bK.length); 55 | 56 | // XOR the key with 0x36 for iPad and 0x5c for oPad 57 | for (let i = 0; i < bK.length; i++) { 58 | oPad[i] = bK[i] ^ 0x5c; 59 | iPad[i] = bK[i] ^ 0x36; 60 | } 61 | 62 | // Perform inner hash: H( K ⊕ ipad || message ) 63 | const innerHash = sha256(new Uint8Array([...iPad, ...message])); 64 | 65 | // Perform outer hash: H( K ⊕ opad || innerHash ) 66 | return sha256(new Uint8Array([...oPad, ...wordArrayToByteArray(innerHash)])); 67 | }; 68 | 69 | export { hmac }; 70 | -------------------------------------------------------------------------------- /src/crypto/sha256.ts: -------------------------------------------------------------------------------- 1 | import { BLOCK_SIZE, byteArrayToWordArray } from './common.js'; 2 | 3 | // Constants 4 | const HASH_VALUES: Uint32Array = new Uint32Array([ 5 | 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 6 | 0x1f83d9ab, 0x5be0cd19, 7 | ]); 8 | 9 | const ROUND_CONSTANTS: Uint32Array = new Uint32Array([ 10 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 11 | 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 12 | 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 13 | 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 14 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 15 | 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 16 | 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 17 | 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 18 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 19 | 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 20 | 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, 21 | ]); 22 | 23 | /** 24 | * Rotates the word right by the specified number of bits 25 | * 26 | * @param word The word 27 | * @param cnt The number of rotations 28 | * @returns The rotated word 29 | */ 30 | const rotr = (word: number, cnt: number): number => { 31 | return (word >>> cnt) | (word << (32 - cnt)); 32 | }; 33 | 34 | /** 35 | * Prepares the message for chunking 36 | * 37 | * @param bytes The message bytes 38 | * @returns The padded message (32-bit word array) 39 | */ 40 | const prepareMessage = (bytes: Uint8Array): Uint32Array => { 41 | const msgLen = bytes.length * 8; 42 | const totalLen = Math.ceil((msgLen + 65) / BLOCK_SIZE) * (BLOCK_SIZE / 8); 43 | const paddedMessage = new Uint8Array(totalLen); 44 | 45 | // Copy original bytes 46 | paddedMessage.set(bytes); 47 | 48 | // Append '1' bit 49 | paddedMessage[bytes.length] = 0b1000_0000; 50 | 51 | // Append the length of the message in bits (as 64-bit big-endian) 52 | const lenBytes = new DataView(new ArrayBuffer(8)); 53 | lenBytes.setUint32(4, msgLen); // Only the lower 32 bits (since we're not hashing files > 4GB) 54 | 55 | paddedMessage.set(new Uint8Array(lenBytes.buffer), totalLen - 8); 56 | 57 | // Convert the byte array to 32-bit word array 58 | return byteArrayToWordArray(paddedMessage); 59 | }; 60 | 61 | /** 62 | * Processes a single chunk (512-bit block) of the message 63 | * 64 | * @param chunk The chunk (32-bit word array) 65 | * @param hv The current hash value 66 | * @returns The updated hash value 67 | */ 68 | const processChunk = (chunk: Uint32Array, hv: Uint32Array): Uint32Array => { 69 | const w = new Uint32Array(64); 70 | w.set(chunk); 71 | 72 | // Extend the message schedule array 73 | for (let i = 16; i < 64; i++) { 74 | const s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >>> 3); 75 | const s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >>> 10); 76 | w[i] = (w[i - 16] + s0 + w[i - 7] + s1) >>> 0; 77 | } 78 | 79 | // Initialize working variables 80 | let [a, b, c, d, e, f, g, h] = hv; 81 | 82 | // Compression function main loop 83 | for (let i = 0; i < 64; i++) { 84 | const s0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22); 85 | const s1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25); 86 | const ch = (e & f) ^ (~e & g); 87 | const maj = (a & b) ^ (a & c) ^ (b & c); 88 | 89 | const temp1 = (h + s1 + ch + ROUND_CONSTANTS[i] + w[i]) >>> 0; 90 | const temp2 = (s0 + maj) >>> 0; 91 | 92 | h = g; 93 | g = f; 94 | f = e; 95 | e = (d + temp1) >>> 0; 96 | d = c; 97 | c = b; 98 | b = a; 99 | a = (temp1 + temp2) >>> 0; 100 | } 101 | 102 | // Add the compressed chunk to the current hash value 103 | hv[0] = (hv[0] + a) >>> 0; 104 | hv[1] = (hv[1] + b) >>> 0; 105 | hv[2] = (hv[2] + c) >>> 0; 106 | hv[3] = (hv[3] + d) >>> 0; 107 | hv[4] = (hv[4] + e) >>> 0; 108 | hv[5] = (hv[5] + f) >>> 0; 109 | hv[6] = (hv[6] + g) >>> 0; 110 | hv[7] = (hv[7] + h) >>> 0; 111 | 112 | return hv; 113 | }; 114 | 115 | /** 116 | * Calculates the SHA256 of the specified byte array 117 | * 118 | * @param bytes The Uint8Array of the byte array 119 | * @returns The SHA256 as a Uint32Array 120 | */ 121 | const sha256 = (bytes: Uint8Array): Uint32Array => { 122 | const message = prepareMessage(bytes); 123 | let hash = new Uint32Array(HASH_VALUES); // Copy of initial hash values 124 | 125 | // Process each 512-bit chunk 126 | for (let i = 0; i < message.length; i += 16) { 127 | const chunk = message.subarray(i, i + 16); 128 | hash = processChunk(chunk, hash); 129 | } 130 | 131 | return hash; 132 | }; 133 | 134 | export { sha256 }; 135 | -------------------------------------------------------------------------------- /src/enums/gradient-direction.enum.ts: -------------------------------------------------------------------------------- 1 | enum GradientDirection { 2 | UP = 'up', 3 | DOWN = 'down', 4 | LEFT = 'left', 5 | RIGHT = 'RIGHT', 6 | } 7 | 8 | export default GradientDirection; 9 | -------------------------------------------------------------------------------- /src/enums/gravity-type.enum.ts: -------------------------------------------------------------------------------- 1 | enum GravityType { 2 | NORTH = 'no', 3 | SOUTH = 'so', 4 | EAST = 'ea', 5 | WEST = 'we', 6 | NORTHEAST = 'noea', 7 | NORTHWEST = 'nowe', 8 | SOUTHEAST = 'soea', 9 | SOUTHWEST = 'sowe', 10 | CENTER = 'ce', 11 | SMART = 'sm', 12 | FOCUS_POINT = 'fp', 13 | } 14 | 15 | export default GravityType; 16 | -------------------------------------------------------------------------------- /src/enums/hashsum-type.enum.ts: -------------------------------------------------------------------------------- 1 | enum HashsumType { 2 | NONE = 'none', 3 | MD5 = 'md5', 4 | SHA1 = 'sha1', 5 | SHA256 = 'sha256', 6 | SHA512 = 'sha512', 7 | } 8 | 9 | export default HashsumType; 10 | -------------------------------------------------------------------------------- /src/enums/resize-type.enum.ts: -------------------------------------------------------------------------------- 1 | enum ResizeType { 2 | FIT = 'fit', 3 | FILL = 'fill', 4 | FILL_DOWN = 'fill-down', 5 | FORCE = 'force', 6 | AUTO = 'auto', 7 | } 8 | 9 | export default ResizeType; 10 | -------------------------------------------------------------------------------- /src/enums/resizing-algorithm.enum.ts: -------------------------------------------------------------------------------- 1 | enum ResizingAlgorithm { 2 | NEAREST = 'nearest', 3 | LINEAR = 'linear', 4 | CUBIC = 'cubic', 5 | LANCZOS2 = 'lanczos2', 6 | LANCZOS3 = 'lanczos3', 7 | } 8 | 9 | export default ResizingAlgorithm; 10 | -------------------------------------------------------------------------------- /src/enums/unsharpening-mode.enum.ts: -------------------------------------------------------------------------------- 1 | enum UnsharpeningMode { 2 | AUTO = 'auto', 3 | NONE = 'none', 4 | ALWAYS = 'always', 5 | } 6 | 7 | export default UnsharpeningMode; 8 | -------------------------------------------------------------------------------- /src/enums/watermark-position.enum.ts: -------------------------------------------------------------------------------- 1 | enum WatermarkPosition { 2 | CENTER = 'ce', 3 | NORTH = 'no', 4 | SOUTH = 'so', 5 | EAST = 'ea', 6 | WEST = 'we', 7 | NORTH_EAST = 'noea', 8 | NORTH_WEST = 'nowe', 9 | SOUTH_EAST = 'soea', 10 | SOUTH_WEST = 'sowe', 11 | REPLICATE = 're', 12 | } 13 | 14 | export default WatermarkPosition; 15 | -------------------------------------------------------------------------------- /src/transformers/adjust.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The adjust options 5 | */ 6 | type AdjustOptions = { 7 | /** 8 | * Integer ranging from -255 to 255 9 | */ 10 | brightness?: number; 11 | 12 | /** 13 | * Floating point number ranging from 0.0 to 1.0 14 | */ 15 | contrast?: number; 16 | 17 | /** 18 | * Floating point number ranging from 0.0 to 1.0 19 | */ 20 | saturation?: number; 21 | }; 22 | 23 | /** 24 | * Defines the brightness, contrast, and saturation. 25 | * 26 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#adjust-idadjust for the imgproxy documentation 27 | * 28 | * @param options The adjustment options 29 | * @returns The adjustment param string 30 | */ 31 | const adjust = (options: AdjustOptions): string => 32 | stringifyOptions('a', [ 33 | options.brightness, 34 | options.contrast, 35 | options.saturation, 36 | ]); 37 | 38 | export default adjust; 39 | export { AdjustOptions }; 40 | -------------------------------------------------------------------------------- /src/transformers/auto-rotate.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * Automatically rotates the image based on the EXIF orientation parameter. 5 | * 6 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#auto-rotate for the imgproxy documentation 7 | * 8 | * @returns The auto-rotate param string 9 | */ 10 | const autoRotate = (): string => stringifyOptions('ar', [true]); 11 | 12 | export default autoRotate; 13 | -------------------------------------------------------------------------------- /src/transformers/background-alpha.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The background alpha, a positive floating point number ranging from 0 to 1 5 | */ 6 | type BackgroundAlphaOptions = number; 7 | 8 | /** 9 | * Adds alpha channel to background. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#background-alpha-idbackground-alpha for the imgproxy documentation 12 | * 13 | * @param percentage A positive floating point number between 0 and 1 14 | * @returns The background alpha param string 15 | */ 16 | const backgroundAlpha = (percentage: BackgroundAlphaOptions): string => 17 | stringifyOptions('bga', [percentage]); 18 | 19 | export default backgroundAlpha; 20 | export { BackgroundAlphaOptions }; 21 | -------------------------------------------------------------------------------- /src/transformers/background.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The background color 5 | */ 6 | type BackgroundOptions = 7 | | string 8 | | { 9 | /** 10 | * The red channel (0-255) 11 | */ 12 | r: number; 13 | 14 | /** 15 | * The green channel (0-255) 16 | */ 17 | g: number; 18 | 19 | /** 20 | * The blue channel (0-255) 21 | */ 22 | b: number; 23 | }; 24 | 25 | /** 26 | * Fills the image background with the specified color. 27 | * 28 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#background for the imgproxy documentation 29 | * 30 | * @param options The background color (hex encoded string or RGB object) 31 | * @returns The background param string 32 | */ 33 | const background = (options: BackgroundOptions): string => 34 | stringifyOptions('bg', [ 35 | ...(typeof options === 'string' 36 | ? [options] 37 | : [options.r, options.g, options.b]), 38 | ]); 39 | 40 | export default background; 41 | export { BackgroundOptions }; 42 | -------------------------------------------------------------------------------- /src/transformers/blur-detections.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The blur detection options 5 | */ 6 | type BlurDetectionOptions = { 7 | /** 8 | * The blur radius 9 | */ 10 | sigma: number; 11 | 12 | /** 13 | * The class names. If omitted, imgproxy blurs all the detected objects. 14 | */ 15 | classNames?: string[]; 16 | }; 17 | 18 | /** 19 | * Detects objects of the provided classes and blurs them. 20 | * 21 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#blur-detections-idblur-detections for the imgproxy documentation 22 | * 23 | * @param options The detection options 24 | * @returns The blur detection param string 25 | */ 26 | const blurDetections = (options: BlurDetectionOptions): string => 27 | stringifyOptions('bd', [options.sigma, ...(options.classNames ?? [])]); 28 | 29 | export default blurDetections; 30 | export { BlurDetectionOptions }; 31 | -------------------------------------------------------------------------------- /src/transformers/blur.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The blur radius 5 | */ 6 | type BlurOptions = number; 7 | 8 | /** 9 | * Applies a gaussian blur filter to the image. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#blur for the imgproxy documentation 12 | * 13 | * @param sigma The size of the blur mask 14 | * @returns The blur param string 15 | */ 16 | const blur = (sigma: BlurOptions): string => stringifyOptions('bl', [sigma]); 17 | 18 | export default blur; 19 | export { BlurOptions }; 20 | -------------------------------------------------------------------------------- /src/transformers/brightness.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The brightness, an integer ranging from -255 to 255. 5 | */ 6 | type BrightnessOptions = number; 7 | 8 | /** 9 | * Adjusts the brightness of an image. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#brightness-idbrightness for the imgproxy documentation 12 | * 13 | * @param value An integer number ranging from -255 to 255. 14 | * @returns The brightness param string 15 | */ 16 | const brightness = (value: BrightnessOptions): string => 17 | stringifyOptions('br', [value]); 18 | 19 | export default brightness; 20 | export { BrightnessOptions }; 21 | -------------------------------------------------------------------------------- /src/transformers/cache-buster.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The cache buster 5 | */ 6 | type CacheBusterOptions = string; 7 | 8 | /** 9 | * Adds a cache buster to the imgproxy params. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#cache-buster for the imgproxy documentation 12 | * 13 | * @param buster The cache buster 14 | * @returns The cache buster param string 15 | */ 16 | const cacheBuster = (buster: CacheBusterOptions): string => 17 | stringifyOptions('cb', [buster]); 18 | 19 | export default cacheBuster; 20 | export { CacheBusterOptions }; 21 | -------------------------------------------------------------------------------- /src/transformers/contrast.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The percentage (positive floating number from 0-1) 5 | */ 6 | type ContrastOptions = number; 7 | 8 | /** 9 | * Adjust contrast of the resulting image. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#contrast-idcontrast for the imgproxy documentation 12 | * 13 | * @param percentage A positive floating point number, where 1 14 | * keeps the contrast unchanged. 15 | * @returns The contrast param string 16 | */ 17 | const contrast = (percentage: ContrastOptions): string => 18 | stringifyOptions('co', [percentage]); 19 | 20 | export default contrast; 21 | export { ContrastOptions }; 22 | -------------------------------------------------------------------------------- /src/transformers/crop.ts: -------------------------------------------------------------------------------- 1 | import GravityType from '../enums/gravity-type.enum.js'; 2 | import { stringifyOptions } from '../common.js'; 3 | 4 | /** 5 | * The available options for the crop operation 6 | */ 7 | type CropOptions = { 8 | /** 9 | * The width of the cropped size 10 | * 11 | * if width == 0 or unset : imgproxy uses the full width 12 | * if width >= 1 : imgproxy treats it as absolute value 13 | * if width <= 1 : imgproxy treats it as relative value 14 | */ 15 | width?: number; 16 | /** 17 | * The height of the cropped size 18 | * 19 | * if height == 0 or unset : imgproxy uses the full height 20 | * if height >= 1 : imgproxy treats it as absolute value 21 | * if height <= 1 : imgproxy treats it as relative value 22 | */ 23 | height?: number; 24 | /** 25 | * (Optional) The gravity for the cropping operation 26 | */ 27 | gravity?: { 28 | /** 29 | * Specifies the gravity type 30 | */ 31 | type: GravityType; 32 | 33 | /** 34 | * (Optional) Specifies the offset by X and Y axes 35 | */ 36 | offset?: { 37 | /** 38 | * The gravity offset on the X axis 39 | */ 40 | x: number; 41 | /** 42 | * The gravity offset on the Y axis 43 | */ 44 | y: number; 45 | }; 46 | }; 47 | }; 48 | 49 | /** 50 | * Crops the image. 51 | * 52 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#crop for the imgproxy documentation 53 | * 54 | * @param options The cropping options 55 | * @returns The cropping param string 56 | */ 57 | const crop = (options?: CropOptions): string => 58 | stringifyOptions('c', [ 59 | options?.width ?? 0, 60 | options?.height ?? 0, 61 | options?.gravity?.type, 62 | options?.gravity?.offset?.x, 63 | options?.gravity?.offset?.y, 64 | ]); 65 | 66 | export default crop; 67 | export { CropOptions }; 68 | -------------------------------------------------------------------------------- /src/transformers/disable-animation.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * Use a single frame of animated images. 5 | * 6 | * See https://github.com/imgproxy/imgproxy/blob/cfa4b596d1f31656f9116cc16f2a4ff7d15c2837/docs/generating_the_url.md#disable-animation-iddisable-animation for the imgproxy documentation 7 | * 8 | * @returns The disable animation param string 9 | */ 10 | const disableAnimation = (): string => stringifyOptions('da', [true]); 11 | 12 | export default disableAnimation; 13 | -------------------------------------------------------------------------------- /src/transformers/dpi.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The DPI value 5 | */ 6 | type DPIOptions = number; 7 | 8 | /** 9 | * When set, imgproxy will replace the image's DPI metadata with the provided value. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/8629c5eca1e422908363f471513bfc887d778a85/docs/generating_the_url.md#dpi-iddpi for the imgproxy documentation 12 | * 13 | * @param value The DPI value 14 | * @returns The DPI param string 15 | */ 16 | const dpi = (value: DPIOptions): string => stringifyOptions('dpi', [value]); 17 | 18 | export default dpi; 19 | export { DPIOptions }; 20 | -------------------------------------------------------------------------------- /src/transformers/dpr.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The DPR factor (must be greater than 0) 5 | */ 6 | type DprOptions = number; 7 | 8 | /** 9 | * Multiplies the dimensions according to the specified factor. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#dpr for the imgproxy documentation 12 | * 13 | * @param value The DPR factor 14 | * @returns The DPR param string 15 | */ 16 | const dpr = (value: DprOptions): string => stringifyOptions('dpr', [value]); 17 | 18 | export default dpr; 19 | export { DprOptions }; 20 | -------------------------------------------------------------------------------- /src/transformers/draw-detections.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The draw detection options 5 | */ 6 | type DrawDetectionOptions = { 7 | /** 8 | * The class names. If omitted, imgproxy draws the 9 | * bounding boxes of all the detected objects. 10 | */ 11 | classNames?: string[]; 12 | }; 13 | 14 | /** 15 | * Detects objects of the provided classes and draws their 16 | * bounding boxes. 17 | * 18 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#draw-detections-iddraw-detections for the imgproxy documentation 19 | * 20 | * @param options The detection options 21 | * @returns The draw detection param string 22 | */ 23 | const drawDetections = (options: DrawDetectionOptions): string => 24 | stringifyOptions('dd', [true, ...(options.classNames ?? [])]); 25 | 26 | export default drawDetections; 27 | export { DrawDetectionOptions }; 28 | -------------------------------------------------------------------------------- /src/transformers/duotone.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common'; 2 | 3 | type DuotoneOptions = { 4 | /** 5 | * A positive floating-point number between 0 and 1 that 6 | * defines the intensity of the duotone effect 7 | */ 8 | intensity: number; 9 | 10 | /** 11 | * The hex-coded value for the dark areas 12 | */ 13 | color1: string; 14 | 15 | /** 16 | * The hex-coded value for the light areas 17 | */ 18 | color2: string; 19 | }; 20 | 21 | /** 22 | * Converts the image to duotone with specified intensity and colors. 23 | * 24 | * See https://github.com/imgproxy/imgproxy-docs/blob/7d15484aea6a1fae5f1dfd1806b5551a4774658d/docs/usage/processing.mdx?plain=1#L429 for the imgproxy documentation 25 | * 26 | * @param options The duotone options 27 | * @returns The duotone param string 28 | */ 29 | const duotone = (options: DuotoneOptions): string => 30 | stringifyOptions('dt', [options.intensity, options.color1, options.color2]); 31 | 32 | export default duotone; 33 | export { DuotoneOptions }; 34 | -------------------------------------------------------------------------------- /src/transformers/enforce-thumbnail.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * If the source image has an embedded thumbnail, imgproxy will use the 5 | * embedded thumbnail instead of the main image. 6 | * 7 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#enforce-thumbnail for the imgproxy documentation 8 | * 9 | * @returns The enforce thumbnail param string 10 | */ 11 | const enforceThumbnail = (): string => stringifyOptions('eth', [true]); 12 | 13 | export default enforceThumbnail; 14 | -------------------------------------------------------------------------------- /src/transformers/enlarge.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * Enlarges the image if it is smaller than the given size. 5 | * 6 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#enlarge for the imgproxy documentation 7 | * 8 | * @returns The enlarge param string 9 | */ 10 | const enlarge = (): string => stringifyOptions('el', [true]); 11 | 12 | export default enlarge; 13 | -------------------------------------------------------------------------------- /src/transformers/expires.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The expiration date / unix timestamp 5 | */ 6 | type ExpiresOptions = Date | number; 7 | 8 | /** 9 | * Returns a 404 if the expiration date is reached. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#expires for the imgproxy documentation 12 | * 13 | * @param options The unix timestamp 14 | * @returns The expiration param string 15 | */ 16 | const expires = (options: ExpiresOptions): string => 17 | stringifyOptions('exp', [ 18 | typeof options === 'number' 19 | ? options 20 | : Math.floor(options.getTime() / 1000), 21 | ]); 22 | 23 | export default expires; 24 | export { ExpiresOptions }; 25 | -------------------------------------------------------------------------------- /src/transformers/extend-aspect-ratio.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | import { GravityType } from '../index.js'; 4 | 5 | /** 6 | * The extend aspect ratio options 7 | */ 8 | type ExtendAspectRatioOptions = { 9 | /** 10 | * (Optional) The gravity for the cropping operation 11 | */ 12 | gravity?: { 13 | /** 14 | * Specifies the gravity type 15 | */ 16 | type: Exclude; 17 | 18 | /** 19 | * (Optional) Specifies the offset by X and Y axes 20 | */ 21 | offset?: { 22 | /** 23 | * The gravity offset on the X axis 24 | */ 25 | x: number; 26 | /** 27 | * The gravity offset on the Y axis 28 | */ 29 | y: number; 30 | }; 31 | }; 32 | }; 33 | 34 | /** 35 | * Extends the image to the requested aspect ratio. 36 | * 37 | * See https://github.com/imgproxy/imgproxy/blob/1a9768a2c682e88820064aa3d9a05ea234ff3cc4/docs/generating_the_url.md#extend-aspect-ratio for the imgproxy documentation 38 | * 39 | * @returns The extend aspect ratio param string 40 | */ 41 | const extendAspectRatio = (options?: ExtendAspectRatioOptions): string => 42 | stringifyOptions('exar', [ 43 | true, 44 | options?.gravity?.type, 45 | options?.gravity?.offset?.x, 46 | options?.gravity?.offset?.y, 47 | ]); 48 | 49 | export default extendAspectRatio; 50 | export { ExtendAspectRatioOptions }; 51 | -------------------------------------------------------------------------------- /src/transformers/extend.ts: -------------------------------------------------------------------------------- 1 | import GravityType from '../enums/gravity-type.enum.js'; 2 | import { stringifyOptions } from '../common.js'; 3 | 4 | /** 5 | * The extend options 6 | */ 7 | type ExtendOptions = { 8 | /** 9 | * The gravity 10 | */ 11 | gravity: { 12 | type: Exclude; 13 | 14 | /** 15 | * The gravity offset 16 | */ 17 | offset?: { 18 | /** 19 | * The gravity offset on the X axis 20 | */ 21 | x: number; 22 | 23 | /** 24 | * The gravity offset on the y axis 25 | */ 26 | y: number; 27 | }; 28 | }; 29 | }; 30 | 31 | /** 32 | * Extends the image if it is smaller than the given size. 33 | * 34 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#extend for the imgproxy documentation 35 | * 36 | * @param options The extend options 37 | * @returns The extend param string 38 | */ 39 | const extend = (options?: ExtendOptions): string => 40 | stringifyOptions('ex', [ 41 | true, 42 | options?.gravity.type, 43 | options?.gravity.offset?.x, 44 | options?.gravity.offset?.y, 45 | ]); 46 | 47 | export default extend; 48 | export { ExtendOptions }; 49 | -------------------------------------------------------------------------------- /src/transformers/fallback-image-url.ts: -------------------------------------------------------------------------------- 1 | import { base64urlEncode, utf8encode } from '../crypto/codec.js'; 2 | import { stringifyOptions } from '../common.js'; 3 | 4 | /** 5 | * The fallback image URL 6 | */ 7 | type FallbackImageUrlOptions = string; 8 | 9 | /** 10 | * Sets a custom fallback image by specifying its URL. 11 | * 12 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#fallback-image-url-idfallback-image-url for the imgproxy documentation 13 | * 14 | * @param url The fallback image URL 15 | * @returns The fallback image URL param string 16 | */ 17 | const fallbackImageUrl = (url: FallbackImageUrlOptions): string => 18 | stringifyOptions('fiu', [base64urlEncode(utf8encode(url))]); 19 | 20 | export default fallbackImageUrl; 21 | export { FallbackImageUrlOptions }; 22 | -------------------------------------------------------------------------------- /src/transformers/filename.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The file name 5 | */ 6 | type FileNameOptions = string; 7 | 8 | /** 9 | * Sets the filename for the Content-Disposition header. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/41b9ebe9277ef3e664e0a842fbc0e912b2640969/docs/generating_the_url.md#filename for the imgproxy documentation 12 | * 13 | * @param name The filename 14 | * @param base64Encoded Whether the file name is base64 encoded 15 | * @returns The filename param string 16 | */ 17 | const fileName = (name: FileNameOptions, base64Encoded = false): string => 18 | stringifyOptions('fn', [name, base64Encoded ? true : undefined]); 19 | 20 | export default fileName; 21 | export { FileNameOptions }; 22 | -------------------------------------------------------------------------------- /src/transformers/format-quality.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * A record consisting of a mapping from extension/format to the quality factor 5 | */ 6 | type FormatQualityOptions = Record; 7 | 8 | /** 9 | * Sets the desired quality for each format. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#format-quality for the imgproxy documentation 12 | * 13 | * @param options The format quality options 14 | * @returns The format quality param string 15 | */ 16 | const formatQuality = (options: FormatQualityOptions): string => 17 | stringifyOptions( 18 | 'fq', 19 | Object.entries(options).flatMap((e) => e), 20 | ); 21 | 22 | export default formatQuality; 23 | export { FormatQualityOptions }; 24 | -------------------------------------------------------------------------------- /src/transformers/format.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The file format 5 | */ 6 | type FormatOptions = 7 | | 'png' 8 | | 'jpg' 9 | | 'webp' 10 | | 'avif' 11 | | 'gif' 12 | | 'ico' 13 | | 'heic' 14 | | 'bmp' 15 | | 'tiff'; 16 | 17 | /** 18 | * Specifies the resulting image format. 19 | * 20 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#format for the imgproxy documentation 21 | * 22 | * @param imageFormat The target format 23 | * @returns The format param string 24 | */ 25 | const format = (imageFormat: FormatOptions): string => 26 | stringifyOptions('f', [imageFormat]); 27 | 28 | export default format; 29 | export { FormatOptions }; 30 | -------------------------------------------------------------------------------- /src/transformers/gif-options.ts: -------------------------------------------------------------------------------- 1 | // Removed in version 3.0.0 2 | // See: https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/CHANGELOG.md#removed 3 | 4 | import { stringifyOptions } from '../common.js'; 5 | 6 | /** 7 | * The GIF options 8 | */ 9 | type GifOptions = { 10 | /** 11 | * If true, enables GIF frames optimization. 12 | */ 13 | optimizeFrames?: boolean; 14 | 15 | /** 16 | * If true, enables GIF transparency optimization. 17 | */ 18 | optimizeTransparency?: boolean; 19 | }; 20 | 21 | /** 22 | * Allows redefining GIF saving options. 23 | * 24 | * @deprecated Automatically applied since version 3.0.0 25 | * @param options The gif options 26 | * @returns The gif option param string 27 | */ 28 | const gifOptions = (options: GifOptions): string => 29 | stringifyOptions('gifo', [ 30 | options.optimizeFrames, 31 | options.optimizeTransparency, 32 | ]); 33 | 34 | export default gifOptions; 35 | export { GifOptions }; 36 | -------------------------------------------------------------------------------- /src/transformers/gradient.ts: -------------------------------------------------------------------------------- 1 | import GradientDirection from '../enums/gradient-direction.enum.js'; 2 | import { stringifyOptions } from '../common.js'; 3 | 4 | /** 5 | * The gradient options 6 | */ 7 | type GradientOptions = { 8 | /** 9 | * The opacity 10 | */ 11 | opacity: number | string; 12 | 13 | /** 14 | * Hex encoded value of the gradient color 15 | */ 16 | color?: string; 17 | 18 | /** 19 | * The gradient direction 20 | */ 21 | direction?: GradientDirection; 22 | 23 | /** 24 | * Relative position of the gradient start between 0.0 and 1.0 25 | */ 26 | start?: number | string; 27 | 28 | /** 29 | * Relative position of the gradient stop between 0.0 and 1.0 30 | */ 31 | stop?: number | string; 32 | }; 33 | 34 | /** 35 | * Places a gradient on the processed image. 36 | * 37 | * See https://github.com/imgproxy/imgproxy/blob/cfa4b596d1f31656f9116cc16f2a4ff7d15c2837/docs/generating_the_url.md#gradient-idgradient for the imgproxy documentation 38 | * 39 | * @param options The gradient options 40 | * @returns The gradient param string 41 | */ 42 | const gradient = (options: GradientOptions): string => 43 | stringifyOptions('gr', [ 44 | options.opacity, 45 | options.color ?? '000', 46 | options.direction ?? GradientDirection.DOWN, 47 | options.start ?? '0.0', 48 | options.stop ?? '1.0', 49 | ]); 50 | 51 | export default gradient; 52 | export { GradientOptions }; 53 | -------------------------------------------------------------------------------- /src/transformers/gravity.ts: -------------------------------------------------------------------------------- 1 | import GravityType from '../enums/gravity-type.enum.js'; 2 | import { stringifyOptions } from '../common.js'; 3 | 4 | /** 5 | * The gravity options 6 | */ 7 | type GravityOptions = { 8 | /** 9 | * The gravity type 10 | */ 11 | type: GravityType; 12 | 13 | /** 14 | * The gravity offset 15 | */ 16 | offset?: { 17 | /** 18 | * The gravity offset on the X axis 19 | */ 20 | x: number; 21 | 22 | /** 23 | * The gravity offset on the y axis 24 | */ 25 | y: number; 26 | }; 27 | }; 28 | 29 | /** 30 | * Sets the gravity. 31 | * 32 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#gravity for the imgproxy documentation 33 | * 34 | * @param options The gravity options 35 | * @returns The gravity param string 36 | */ 37 | const gravity = (options: GravityOptions): string => 38 | stringifyOptions('g', [options.type, options.offset?.x, options.offset?.y]); 39 | 40 | export default gravity; 41 | export { GravityOptions }; 42 | -------------------------------------------------------------------------------- /src/transformers/hashsum.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | import HashsumType from '../enums/hashsum-type.enum.js'; 4 | 5 | type HashsumOptions = { 6 | /** 7 | * The expected hex-encoded hashsum of the source image 8 | */ 9 | hashsum: string; 10 | 11 | /** 12 | * The hashsum type 13 | */ 14 | type?: HashsumType; 15 | }; 16 | 17 | /** 18 | * When `hashsum_type` is not `none`, imgproxy will calculate the hashsum of the source image 19 | * and compare it with the provided hashsum. 20 | * 21 | * If they don't match, imgproxy will respond with 422. 22 | * 23 | * See https://github.com/imgproxy/imgproxy-docs/blob/f9d7908d253ec2b31425b988a48f8c28cb271c58/docs/usage/processing.mdx#L916 for the imgproxy documentation 24 | * 25 | * @returns The auto-rotate param string 26 | */ 27 | const hashsum = (options: HashsumOptions): string => 28 | stringifyOptions('hashsum', [ 29 | options.type ?? HashsumType.NONE, 30 | options.hashsum, 31 | ]); 32 | 33 | export default hashsum; 34 | export { HashsumOptions }; 35 | -------------------------------------------------------------------------------- /src/transformers/jpeg-options.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The JPEG options 5 | */ 6 | type JpegOptions = { 7 | /** 8 | * If true, enables progressive JPEG compression 9 | */ 10 | progressive?: boolean; 11 | 12 | /** 13 | * If true, chrominance sub-sampling is disabled 14 | */ 15 | noSubsample?: boolean; 16 | 17 | /** 18 | * If true, enables trellis quantization for each 19 | * 8x8 block 20 | */ 21 | trellisQuant?: boolean; 22 | 23 | /** 24 | * If true, enables overshooting of samples with 25 | * extreme values 26 | */ 27 | overshootDeringing?: boolean; 28 | 29 | /** 30 | * If true, split the spectrum of DCT coefficients 31 | * into separate scans 32 | */ 33 | optimizeScans?: boolean; 34 | 35 | /** 36 | * Quantization table to use 37 | * 38 | * 0: Table from JPEG Annex K (default); 39 | * 1: Flat table; 40 | * 2: Table tuned for MSSIM on Kodak image set; 41 | * 3: Table from ImageMagick by N. Robidoux; 42 | * 4: Table tuned for PSNR-HVS-M on Kodak image set; 43 | * 5: Table from Relevance of Human Vision to JPEG-DCT Compression (1992); 44 | * 6: Table from DCTune Perceptual Optimization of Compressed Dental X-Rays (1997); 45 | * 7: Table from A Visual Detection Model for DCT Coefficient Quantization (1993); 46 | * 8: Table from An Improved Detection Model for DCT Coefficient Quantization (1993). 47 | */ 48 | quantizationTable?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8; 49 | }; 50 | 51 | /** 52 | * Allows redefining JPEG saving options. 53 | * 54 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#jpeg-options-idjpeg-options for the imgproxy documentation 55 | * 56 | * @param options The jpeg options 57 | * @returns The jpeg option param string 58 | */ 59 | const jpegOptions = (options: JpegOptions): string => 60 | stringifyOptions('jpgo', [ 61 | options.progressive, 62 | options.noSubsample, 63 | options.trellisQuant, 64 | options.overshootDeringing, 65 | options.optimizeScans, 66 | options.quantizationTable, 67 | ]); 68 | 69 | export default jpegOptions; 70 | export { JpegOptions }; 71 | -------------------------------------------------------------------------------- /src/transformers/keep-copypright.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * Preserve the copyright info while stripping metadata. 5 | * 6 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#keep-copyright for the imgproxy documentation 7 | * 8 | * @returns The keep copyright param string 9 | */ 10 | const keepCopyright = (): string => stringifyOptions('kcr', [true]); 11 | 12 | export default keepCopyright; 13 | -------------------------------------------------------------------------------- /src/transformers/max-bytes.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The number of bytes 5 | */ 6 | type MaxBytesOptions = number; 7 | 8 | /** 9 | * Limits the file size to the specified number of bytes. 10 | * 11 | * Note: only applicable to jpg, webp, heic and tiff. 12 | * 13 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#max-bytes for the imgproxy documentation 14 | * 15 | * @param maxBytes The number of bytes 16 | * @returns The max bytes param string 17 | */ 18 | const maxBytes = (bytes: MaxBytesOptions): string => 19 | stringifyOptions('mb', [bytes]); 20 | 21 | export default maxBytes; 22 | export { MaxBytesOptions }; 23 | -------------------------------------------------------------------------------- /src/transformers/min-height.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The min height of the resulting image 5 | */ 6 | type MinHeightOptions = number; 7 | 8 | /** 9 | * Defines the minimum height of the resulting image. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#min-height for the imgproxy documentation 12 | * 13 | * @param height The minimum height 14 | * @returns The min height param string 15 | */ 16 | const minHeight = (height: MinHeightOptions): string => 17 | stringifyOptions('mh', [height]); 18 | 19 | export default minHeight; 20 | export { MinHeightOptions }; 21 | -------------------------------------------------------------------------------- /src/transformers/min-width.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The min width of the resulting image 5 | */ 6 | type MinWidthOptions = number; 7 | 8 | /** 9 | * Defines the minimum width of the resulting image. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#min-width for the imgproxy documentation 12 | * 13 | * @param width The minimum width 14 | * @returns The min width param string 15 | */ 16 | const minWidth = (width: MinWidthOptions): string => 17 | stringifyOptions('mw', [width]); 18 | 19 | export default minWidth; 20 | export { MinWidthOptions }; 21 | -------------------------------------------------------------------------------- /src/transformers/monochrome.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The monochrome options 5 | */ 6 | type MonochromeOptions = { 7 | /** 8 | * A positive floating-point number between 0 and 1 that defines 9 | * the intensity of the monochrome effect. 10 | * 11 | * When intensity is greater than zero, imgproxy will convert the 12 | * resulting image to monochrome. 13 | */ 14 | intensity: number; 15 | 16 | /** 17 | * A hex-coded value of the color that will be used as a base for the 18 | * monochrome palette. 19 | */ 20 | color?: string; 21 | }; 22 | 23 | /** 24 | * Converts the image to monochrome. 25 | * 26 | * See https://github.com/imgproxy/imgproxy-docs/blob/7d15484aea6a1fae5f1dfd1806b5551a4774658d/docs/usage/processing.mdx?plain=1#L415 for the imgproxy documentation 27 | * 28 | * @param options The monochrome options 29 | * @returns The monochrome param string 30 | */ 31 | const monochrome = (options: MonochromeOptions): string => 32 | stringifyOptions('mc', [ 33 | options.intensity, 34 | ...(options.color ? [options.color] : []), 35 | ]); 36 | 37 | export default monochrome; 38 | export { MonochromeOptions }; 39 | -------------------------------------------------------------------------------- /src/transformers/pad.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The available options for the crop operation 5 | */ 6 | type PaddingOptions = { 7 | /** 8 | * The top padding (and all other sides if not set explicitly) 9 | */ 10 | top?: number; 11 | 12 | /** 13 | * The right padding (and left if it won't be set explicitly) 14 | */ 15 | right?: number; 16 | 17 | /** 18 | * The bottom padding 19 | */ 20 | bottom?: number; 21 | 22 | /** 23 | * The left padding 24 | */ 25 | left?: number; 26 | }; 27 | 28 | /** 29 | * Applies the specified padding to the image. 30 | * 31 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#padding for the imgproxy documentation 32 | * 33 | * @param options The padding options 34 | * @returns The padding param string 35 | */ 36 | const pad = (options: PaddingOptions): string => 37 | stringifyOptions('pd', [ 38 | options.top, 39 | options.right, 40 | options.bottom, 41 | options.left, 42 | ]); 43 | 44 | export default pad; 45 | export { PaddingOptions }; 46 | -------------------------------------------------------------------------------- /src/transformers/page.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The page number (starting from 0) 5 | */ 6 | type PageOptions = number; 7 | 8 | /** 9 | * When source image supports pagination (PDF, TIFF) or animation (GIF, WebP), this option allows 10 | * specifying the page to use. 11 | * 12 | * Pages numeration starts from zero. 13 | * 14 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#page-idpage for the imgproxy documentation 15 | * 16 | * @param pg The page to use 17 | * @returns The page param string 18 | */ 19 | const page = (pg: PageOptions): string => stringifyOptions('pg', [pg]); 20 | 21 | export default page; 22 | export { PageOptions }; 23 | -------------------------------------------------------------------------------- /src/transformers/pixelate.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The size of a pixel 5 | */ 6 | type PixelateOptions = number; 7 | 8 | /** 9 | * Apply the pixelate filter to the resulting image. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#pixelate for the imgproxy documentation 12 | * 13 | * @param pixelSize The size of a pixel 14 | * @returns The pixelate param string 15 | */ 16 | const pixelate = (pixelSize: PixelateOptions): string => 17 | stringifyOptions('pix', [pixelSize]); 18 | 19 | export default pixelate; 20 | export { PixelateOptions }; 21 | -------------------------------------------------------------------------------- /src/transformers/png-options.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The PNG options 5 | */ 6 | type PngOptions = { 7 | /** 8 | * If true, enables interlaced PNG compression 9 | */ 10 | interlaced?: boolean; 11 | 12 | /** 13 | * If true, enables PNG quantization. 14 | */ 15 | quantize?: boolean; 16 | 17 | /** 18 | * Maximum number of quantization palette entries. 19 | * 20 | * Should be between 2 and 256. 21 | */ 22 | quantization_colors?: number; 23 | }; 24 | 25 | /** 26 | * Allows redefining PNG saving options. 27 | * 28 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#png-options-idpng-options for the imgproxy documentation 29 | * 30 | * @param options The png options 31 | * @returns The png option param string 32 | */ 33 | const pngOptions = (options: PngOptions): string => 34 | stringifyOptions('pngo', [ 35 | options.interlaced, 36 | options.quantize, 37 | options.quantization_colors, 38 | ]); 39 | 40 | export default pngOptions; 41 | export { PngOptions }; 42 | -------------------------------------------------------------------------------- /src/transformers/preset.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * A preset or a list of presets 5 | */ 6 | type PresetOptions = string | string[]; 7 | 8 | /** 9 | * Sets one or many presets to be used by the imgproxy. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#preset for the imgproxy documentation 12 | * 13 | * @param presets The preset(s) 14 | * @returns The preset param string 15 | */ 16 | const preset = (presets: PresetOptions): string => 17 | stringifyOptions('pr', Array.isArray(presets) ? presets : [presets]); 18 | 19 | export default preset; 20 | export { PresetOptions }; 21 | -------------------------------------------------------------------------------- /src/transformers/quality.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The quality in percentage (floating point number from 0.0 to 1.0) 5 | */ 6 | type QualityOptions = number; 7 | 8 | /** 9 | * Redefines the quality of the resulting image. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#quality for the imgproxy documentation 12 | * 13 | * @param percentage The percentage as floating point number from 0 to 1 14 | * @returns The quality param string 15 | */ 16 | const quality = (percentage: QualityOptions): string => 17 | stringifyOptions('q', [percentage]); 18 | 19 | export default quality; 20 | export { QualityOptions }; 21 | -------------------------------------------------------------------------------- /src/transformers/raw.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * Returns a raw unprocessed and unchecked source image 5 | * 6 | * See https://github.com/imgproxy/imgproxy/blob/f95f57bb4df35c69ae2257958006ef54b1c1d8c7/docs/generating_the_url.md#raw for the imgproxy documentation 7 | * 8 | * @returns The raw param string 9 | */ 10 | const raw = (): string => stringifyOptions('raw', [true]); 11 | 12 | export default raw; 13 | -------------------------------------------------------------------------------- /src/transformers/resize.ts: -------------------------------------------------------------------------------- 1 | import ResizeType from '../enums/resize-type.enum.js'; 2 | import { stringifyOptions } from '../common.js'; 3 | 4 | /** 5 | * The resize options 6 | */ 7 | type ResizeOptions = { 8 | /** 9 | * The resizing strategy 10 | */ 11 | type?: ResizeType; 12 | 13 | /** 14 | * The target width 15 | */ 16 | width?: number; 17 | 18 | /** 19 | * The target height 20 | */ 21 | height?: number; 22 | }; 23 | 24 | /** 25 | * Resizes the image. 26 | * 27 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#resize for the imgproxy documentation 28 | * 29 | * @param options The resizing options 30 | * @returns The resizing param string 31 | */ 32 | const resize = (options: ResizeOptions): string => 33 | stringifyOptions('rs', [options.type, options.width, options.height]); 34 | 35 | export default resize; 36 | export { ResizeOptions }; 37 | -------------------------------------------------------------------------------- /src/transformers/resizing-algorithm.ts: -------------------------------------------------------------------------------- 1 | import ResizingAlgorithm from '../enums/resizing-algorithm.enum.js'; 2 | import { stringifyOptions } from '../common.js'; 3 | 4 | /** 5 | * The resizing algorithm 6 | */ 7 | type ResizingAlgorithmOptions = ResizingAlgorithm; 8 | 9 | /** 10 | * Defines the algorithm that imgproxy will use for resizing. 11 | * 12 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#resizing-algorithm-idresizing-algorithm for the imgproxy documentation 13 | * 14 | * @param algorithm The resizing algorithm 15 | * @returns The resizing algorithm param string 16 | */ 17 | const resizingAlgorithm = (algorithm: ResizingAlgorithmOptions): string => 18 | stringifyOptions('ra', [algorithm]); 19 | 20 | export default resizingAlgorithm; 21 | export { ResizingAlgorithmOptions }; 22 | -------------------------------------------------------------------------------- /src/transformers/return-attachment.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * Returns attachment in the Content-Disposition header. 5 | * 6 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#return-attachment for the imgproxy documentation 7 | * 8 | * @returns The attachment param string 9 | */ 10 | const returnAttachment = (): string => stringifyOptions('att', [true]); 11 | 12 | export default returnAttachment; 13 | -------------------------------------------------------------------------------- /src/transformers/rotate.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The rotation angle 5 | */ 6 | type RotationOptions = 0 | 90 | 180 | 270; 7 | 8 | /** 9 | * Rotates the image by the specified angle. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#rotate for the imgproxy documentation 12 | * 13 | * @param angle The angle 14 | * @returns The rotate param string 15 | */ 16 | const rotate = (angle: RotationOptions): string => 17 | stringifyOptions('rot', [angle]); 18 | 19 | export default rotate; 20 | export { RotationOptions }; 21 | -------------------------------------------------------------------------------- /src/transformers/saturation.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The saturation (positive floating point number from 0 to 1). 5 | */ 6 | type SaturationOptions = number; 7 | 8 | /** 9 | * Adjust saturation of the resulting image. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#saturation-idsaturation for the imgproxy documentation 12 | * 13 | * @param percentage A positive floating point number, where 1 14 | * keeps the saturation unchanged 15 | * @returns The saturation param string 16 | */ 17 | const saturation = (percentage: SaturationOptions): string => 18 | stringifyOptions('sa', [percentage]); 19 | 20 | export default saturation; 21 | export { SaturationOptions }; 22 | -------------------------------------------------------------------------------- /src/transformers/sharpen.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The size of the sharpen mask (floating point number) 5 | */ 6 | type SharpenOptions = number; 7 | 8 | /** 9 | * Applies a sharpen filter to the image. 10 | * 11 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#sharpen for the imgproxy documentation 12 | * 13 | * @param sigma The size of the sharpen mask 14 | * @returns The sharpen param string 15 | */ 16 | const sharpen = (sigma: SharpenOptions): string => 17 | stringifyOptions('sh', [sigma]); 18 | 19 | export default sharpen; 20 | export { SharpenOptions }; 21 | -------------------------------------------------------------------------------- /src/transformers/skip-processing.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * The list of formats which should not be processed 5 | */ 6 | type SkipProcessingOptions = string[]; 7 | 8 | /** 9 | * Skip the processing of the listed formats. 10 | * 11 | * Note: Processing can only be skipped when the requested format is 12 | * the same as the source format. 13 | * 14 | * Note: Video thumbnail processing can't be skipped 15 | * 16 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#skip-processing for the imgproxy documentation 17 | * 18 | * @param extensions The list of file extensions 19 | * @returns The skip processing param string 20 | */ 21 | const skipProcessing = (extensions: SkipProcessingOptions): string => 22 | stringifyOptions('skp', extensions); 23 | 24 | export default skipProcessing; 25 | export { SkipProcessingOptions }; 26 | -------------------------------------------------------------------------------- /src/transformers/strip-color-profile.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * Strips the color profile from the image. 5 | * 6 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#strip-color-profile for the imgproxy documentation 7 | * 8 | * @returns The strip color profile param string 9 | */ 10 | const stripColorProfile = (): string => stringifyOptions('scp', [true]); 11 | 12 | export default stripColorProfile; 13 | -------------------------------------------------------------------------------- /src/transformers/strip-metadata.ts: -------------------------------------------------------------------------------- 1 | import { stringifyOptions } from '../common.js'; 2 | 3 | /** 4 | * Strips the metadata from the image. 5 | * 6 | * See https://github.com/imgproxy/imgproxy/blob/6f292443eafb2e39f9252175b61faa6b38105a7c/docs/generating_the_url.md#strip-metadata for the imgproxy documentation 7 | * 8 | * @returns The strip metadata param string 9 | */ 10 | const stripMetadata = (): string => stringifyOptions('sm', [true]); 11 | 12 | export default stripMetadata; 13 | -------------------------------------------------------------------------------- /src/transformers/style.ts: -------------------------------------------------------------------------------- 1 | import { base64urlEncode, utf8encode } from '../crypto/codec.js'; 2 | import { stringifyOptions } from '../common.js'; 3 | 4 | /** 5 | * The CSS styles to apply to the source SVG image 6 | */ 7 | type StyleOptions = Record | string; 8 | 9 | /** 10 | * Prepend a `