{"id":18561283,"url":"https://github.com/apostrophecms/scale","last_synced_at":"2025-08-24T11:40:50.503Z","repository":{"id":178989614,"uuid":"662297875","full_name":"apostrophecms/scale","owner":"apostrophecms","description":"Scale an image file in the browser before uploading it to your server","archived":false,"fork":false,"pushed_at":"2023-07-05T16:40:36.000Z","size":9,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-18T15:51:33.780Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/apostrophecms.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-04T20:10:32.000Z","updated_at":"2025-06-09T08:50:14.000Z","dependencies_parsed_at":null,"dependency_job_id":"65358441-8c75-4f2f-8754-4ec6e8ec9ce5","html_url":"https://github.com/apostrophecms/scale","commit_stats":null,"previous_names":["apostrophecms/scale"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/apostrophecms/scale","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostrophecms%2Fscale","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostrophecms%2Fscale/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostrophecms%2Fscale/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostrophecms%2Fscale/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apostrophecms","download_url":"https://codeload.github.com/apostrophecms/scale/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostrophecms%2Fscale/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271854475,"owners_count":24834453,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-24T02:00:11.135Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-06T22:06:24.976Z","updated_at":"2025-08-24T11:40:50.457Z","avatar_url":"https://github.com/apostrophecms.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `@apostrophecms/scale`\n\n\u003ca href=\"https://apostrophecms.com/\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/apostrophecms/scale/main/logos/logo-box-madefor.png\" align=\"right\" /\u003e\u003c/a\u003e\n\n## Purpose\n\nResizing 16-megapixel images on the server side can easily DOS your server\n(Denial Of Service). This module scales images appropriately in the browser\nbefore uploading them to your server.\n\n## Installation\n\n```bash\nnpm install @apostrophecms/scale\n```\n\n## Usage\n\n```javascript\nimport scale from '@apostrophecms/scale';\n\n// See test.html for sample markup\nconst input = document.querySelector('#file-input');\ninput.addEventListener('change', async e =\u003e {\n  let file = input.files[0];\n\n  // Limit the maximum size\n  file = await scale(file, {\n    maxWidth: 1600,\n    maxHeight: 1600\n  });\n\n  // Upload as multipart/form-data just like always\n  const body = new FormData();\n  body.append('file', file);\n  const response = await fetch('/upload', {\n    method: 'POST',\n    body\n  });\n});\n```\n\n**The aspect ratio always stays the same.** There is no cropping, letterboxing or stretching. All we care about here is reducing file size by reducing overall dimensions.\n\nBy default, the content type stays the same (`image/jpeg` stays JPEG, `image/png` stays PNG, etc).\n\nThat's it! You're good to go.\n\n## Fancy options\n\n### Changing the file's content type\n\nIf you want, you can turn everything into a WebP file (depending on browser support, you may get PNG as a fallback):\n\n```javascript\nfile = await scale(file, {\n  maxWidth: 1600,\n  maxHeight: 1600,\n  type: 'image/webp'\n});\n```\n\nOr, specify a mapping from type names to new type names:\n\n```javascript\nfile = await scale(file, {\n  maxWidth: 1600,\n  maxHeight: 1600,\n  type: {\n    'image/gif': 'image/png',\n    'image/webp': 'image/png',\n    'image/png': 'image/png',\n    'image/jpeg': 'image/jpeg',\n  }\n});\n```\n\nOr, pass your own function:\n\n```javascript\nfile = await scale(file, {\n  maxWidth: 1600,\n  maxHeight: 1600,\n  type(name) =\u003e (name === 'image/gif') ? 'image/png' : name\n});\n```\n\n### Falling back to the original file\n\nIf you want, you can let the browser pass the original file in cases where scaling somehow fails:\n\n```javascript\nfile = await scale(file, {\n  maxWidth: 1600,\n  maxHeight: 1600,\n  fallback: true\n});\n```\n\nOtherwise an error is thrown in this situation.\n\n## Previewing the image\n\n```javascript\nfile = await scale(file, {\n  maxWidth: 1600,\n  maxHeight: 1600\n});\n\nconst img = document.querySelector('#my-img-element');\nimg.setAttribute('src', URL.createObjectURL(file));\n```\n\n`URL.createObjectURL` can turn the returned object into a suitable URL for use with `img src` or `style: background-image`.\n\n## \"What about the server side?\"\n\nThat depends entirely on your language and framework of choice. If you're using\nNode.js, check out [multiparty](https://www.npmjs.com/package/multiparty) and\n[sharp](https://sharp.pixelplumbing.com/). Remember, you can never trust the\nbrowser, so using a library like `sharp` to validate the images is still\nimportant.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapostrophecms%2Fscale","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapostrophecms%2Fscale","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapostrophecms%2Fscale/lists"}