{"_id":"@digilabscz/image-cropper-js","name":"@digilabscz/image-cropper-js","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@digilabscz/image-cropper-js","version":"1.0.0","description":"Image cropper","keywords":["image","crop","cropper","canvas"],"homepage":"https://gitlab.com/digilabscz/imagecropper-js#readme","bugs":{"url":"https://gitlab.com/digilabscz/imagecropper-js/issues"},"repository":{"type":"git","url":"git+https://gitlab.com/digilabscz/imagecropper-js.git"},"license":"MIT","author":{"name":"Dominik Smolinský"},"type":"module","main":"./dist/image-cropper.cjs","module":"./dist/image-cropper.esm.js","scripts":{"build":"rollup -c","prepublishOnly":"npm run build"},"devDependencies":{"rollup":"^4.37.0"},"exports":{".":{"import":"./dist/image-cropper.esm.js","require":"./dist/image-cropper.cjs"}},"_id":"@digilabscz/image-cropper-js@1.0.0","_nodeVersion":"24.11.1","_npmVersion":"11.6.2","dist":{"integrity":"sha512-ge1ugg+/eItOmIqPJB+V6IRifYoPbROalmoxAwRntEXif04CnzrXl69XN6LZIiZeugEdM5rENE+S1L7RaP5dXQ==","shasum":"28e423029c8af6ce5a0d408add69aca211ea4bd6","tarball":"https://registry.npmjs.org/@digilabscz/image-cropper-js/-/image-cropper-js-1.0.0.tgz","fileCount":6,"unpackedSize":200694,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCQLgac1OLm34WJIKc8fvluyyCGZ0DWFbli1+twudjTSAIhALw/t9xWcuxDDLqhn8JxtctAPMaA5PoyHl1EHO9eT8qN"}]},"_npmUser":{"name":"smola14","email":"dominik.smolinsky@icloud.com"},"directories":{},"maintainers":[{"name":"hladpe","email":"hladpe@gmail.com"},{"name":"cerv0077","email":"cervenkaondra@gmail.com"},{"name":"smola14","email":"dominik.smolinsky@icloud.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/image-cropper-js_1.0.0_1784620787967_0.07727953883273564"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-21T07:59:47.792Z","1.0.0":"2026-07-21T07:59:48.102Z","modified":"2026-07-21T07:59:48.453Z"},"maintainers":[{"name":"hladpe","email":"hladpe@gmail.com"},{"name":"cerv0077","email":"cervenkaondra@gmail.com"},{"name":"smola14","email":"dominik.smolinsky@icloud.com"}],"description":"Image cropper","homepage":"https://gitlab.com/digilabscz/imagecropper-js#readme","keywords":["image","crop","cropper","canvas"],"repository":{"type":"git","url":"git+https://gitlab.com/digilabscz/imagecropper-js.git"},"author":{"name":"Dominik Smolinský"},"bugs":{"url":"https://gitlab.com/digilabscz/imagecropper-js/issues"},"license":"MIT","readme":"# `@digilabscz/image-cropper-js`\n\nFramework-independent browser image cropper. It lets a user move and zoom an image, resize or move the crop area, and export a physically cropped `File` and `Blob` locally with canvas. The package never uploads data and does not rotate images.\n\n## Installation\n\n```bash\nnpm install @digilabscz/image-cropper-js\n```\n\n## Usage\n\n```html\n<input type=\"file\" id=\"image\" accept=\"image/*\">\n<div id=\"cropper\"></div>\n```\n\n```js\nimport {\n    ImageCropper,\n    createImageCropFormData\n} from '@digilabscz/image-cropper-js';\n\nlet imageCropper = new ImageCropper(document.querySelector('#cropper'), {\n    onConfirm: async (result, context) => {\n        let formData = context.createFormData();\n\n        // Uploading is intentionally controlled by the consuming application.\n        await fetch('/api/images', {\n            method: 'POST',\n            body: formData\n        });\n    },\n    onError: (error) => {\n        console.error(error);\n    }\n});\n\ndocument.querySelector('#image').addEventListener('change', async (event) => {\n    if (event.target.files[0]) {\n        await imageCropper.load(event.target.files[0]);\n    }\n});\n```\n\nThe user can drag the image or crop area, resize from all four corners, use the zoom slider or mouse wheel, and confirm or cancel the selection.\nHolding `Shift` while resizing temporarily locks the crop area to a `1:1` square without changing the selected aspect ratio.\n\n## Demo\n\nRun the local demo server to try the cropper with an upload endpoint:\n\n```bash\ncd ..\nnode demo-server.js\n```\n\nThen open `http://127.0.0.1:8000/demo.html`. The demo uploads the cropped file and crop metadata to `POST /api/images`, stores files in `uploads/`, and renders the URL returned by the server. If you open `demo.html` through another static server, keep `node demo-server.js` running on port `8000`; the demo will use it as a fallback upload backend.\n\nThe demo supports selecting multiple files. It opens the first image, stores each confirmed crop in a queue, automatically loads the next image, and uploads all cropped files together after the last confirmation.\n\nFrom the workspace root you can also run:\n\n```bash\nnode demo-quality-test.js\n```\n\nThe test posts a frontend crop and an original image with crop metadata to the demo server, verifies the expected pixel dimensions, and compares the resulting frontend/backend images pixel by pixel.\n\nFor a real browser canvas comparison, run this from the workspace root after installing Playwright locally:\n\n```bash\nnode demo-playwright-quality-test.js\n```\n\nThat test opens the demo in Chromium, uses the actual browser canvas cropper, then separately asks the demo server for a backend crop from the original image and compares both returned images pixel by pixel.\n\n## Options\n\n```js\nlet imageCropper = new ImageCropper(containerNode, {\n    locale: null,\n    translations: {},\n    initialCrop: null,\n    initialAspectRatio: null,\n    aspectRatios: [\n        { label: 'Free', value: null },\n        { label: '1:1', value: 1 },\n        { label: '4:3', value: 4 / 3 },\n        { label: '3:4', value: 3 / 4 },\n        { label: '16:9', value: 16 / 9 },\n        { label: '9:16', value: 9 / 16 },\n        { label: '3:2', value: 3 / 2 },\n        { label: '2:3', value: 2 / 3 }\n    ],\n    onConfirm: null,\n    onCancel: null,\n    onError: null,\n    confirmLabel: null,\n    cancelLabel: null,\n    aspectRatioLabel: null,\n    zoomLabel: null\n});\n```\n\nThe package does not expose output format controls. It creates a cropped file for upload and returns crop metadata; any final image conversion or normalization can be handled by the backend.\n\n## Translations\n\nThe cropper uses `locale` or the document `<html lang>` value to choose translations. The bundled languages are `en`, `cs`, and `sk`; unsupported languages fall back to English.\n\n```js\nlet imageCropper = new ImageCropper(containerNode, {\n    locale: 'sk',\n    translations: {\n        sk: {\n            Confirm: 'Pouzit vyrez',\n            Cancel: 'Zahodit',\n            AspectRatio: 'Format',\n            AspectRatioFree: 'Bez obmedzenia',\n            Zoom: 'Priblizenie'\n        }\n    },\n    aspectRatios: [\n        { labelKey: 'AspectRatioFree', value: null },\n        { label: 'Stvorec', value: '1:1' },\n        { label: 'Banner', value: '16:9' }\n    ]\n});\n```\n\nLegacy label options such as `confirmLabel`, `cancelLabel`, `aspectRatioLabel`, and `zoomLabel` still work and override translated values when provided.\n\n## Public API\n\n```js\nawait imageCropper.load(file);\n\nlet crop = imageCropper.getCrop();\n\nimageCropper.setCrop({\n    x: 0.1,\n    y: 0.1,\n    width: 0.8,\n    height: 0.8\n});\n\nimageCropper.setAspectRatio('16:9');\n\nlet result = await imageCropper.getResult();\nlet blob = await imageCropper.createCroppedBlob();\nlet file = await imageCropper.createCroppedFile();\n\nawait imageCropper.confirm();\nimageCropper.cancel();\nimageCropper.reset();\nimageCropper.setDisabled(true);\nimageCropper.destroy();\n```\n\n`getCrop()` returns integer pixel coordinates relative to the original image. `setCrop()` accepts normalized coordinates between `0` and `1`. `setAspectRatio()` accepts `null`, a number, or a ratio string such as `'16:9'`.\n\n`confirm()` creates the result before calling `onConfirm`. If the callback returns a promise, controls remain in a loading state until it settles. Repeated confirmation is blocked, and failures are forwarded to `onError` and rethrown.\n\n## Result\n\n```js\n{\n    originalFile,\n    croppedFile,\n    croppedBlob,\n    crop: { x, y, width, height },\n    normalizedCrop: { x, y, width, height },\n    aspectRatio,\n    originalImage: { width, height, type, name, size },\n    croppedImage: { width, height, type, name, size }\n}\n```\n\n## FormData\n\n```js\nlet formData = createImageCropFormData(result, {\n    fileFieldName: 'image',\n    metadataFieldName: 'cropData',\n    includeOriginalFile: true,\n    originalFileFieldName: 'originalImage'\n});\n```\n\nBy default, the cropped file is stored in `image` and JSON metadata in `crop`. Set `includeOriginalFile: true` when the backend should crop from the untouched original image.\n\n## Requirements\n\n- Modern browser with `File`, `Blob`, `URL.createObjectURL`, `FormData`, and canvas support\n- No framework or runtime dependency\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-8c6ac1af324aa0a220255971c7ae5ac2"}