Repository files navigation

Cropt

A delightful image cropper optimized for both mobile and desktop use.

  • Includes TypeScript definitions.
  • Published as a native ES module.
  • Zero dependencies.
  • Originally based on Croppie, but rewritten in TypeScript with a simpler API and lots of bug fixes and polish.

Installation

npm install cropt

Usage

  1. Include the src/cropt.css stylesheet on your page.
  2. Add a <div> element with a unique ID to your HTML to hold the Cropt instance.
  3. Import Cropt and instantiate it with a reference to the <div> element and an object for options.
  4. Bind to an image URL.
<divid="cropper"></div>
import{Cropt}from"cropt";import"cropt/src/cropt.css";letcroptEl=document.getElementById('cropper');letcropt=newCropt(croptEl,{viewport: {width: 250,height: 250},});cropt.bind("path/to/image.jpg");

Binding from a file input

To let users pick an image from their device, bind from a file <input> element's change event using URL.createObjectURL():

<inputtype="file" id="fileInput" accept="image/*" />
document.getElementById('fileInput').addEventListener('change',(e)=>{constfile=e.target.files[0];if(!file)return;consturl=URL.createObjectURL(file);cropt.bind(url).then(()=>URL.revokeObjectURL(url));});

The object URL can be revoked after binding because Cropt has already loaded the image data into the DOM at that point.

Uploading the cropped image

Use toBlob() to get the cropped image as a Blob, then send it to your server with fetch:

asyncfunctionupload(){constblob=awaitcropt.toBlob(500,"image/webp");// longest side scaled to 500pxconstbody=newFormData();body.append('image',blob,'crop.webp');awaitfetch('/upload',{method: 'POST', body });}

Sizing

The Cropt boundary defaults to 320px wide and 320px high. To customize this, override the .cropt-container .cr-boundary width and height via CSS.

Options

mouseWheelZoom

Type: "off" | "on" | "ctrl"
Default value: "on"

If set to "off", the mouse wheel cannot be used to zoom in and out of the image. If set to "ctrl", the mouse wheel will only zoom in and out while the CTRL key is pressed.

viewport

Type: { width: number, height: number, borderRadius: string }
Default value: { width: 220, height: 220, borderRadius: "0px" }

Defines the size and shape of the crop box. For a circle shape, set the border radius to "50%".

enableResize

Type: boolean
Default value: false

If set to true, resize handles are shown on the edges of the viewport, allowing the user to adjust its size.

enableRotate

Type: boolean
Default value: false

If set to true, rotate buttons are shown beside the zoom slider, allowing the user to rotate the image 90° clockwise or counter-clockwise.

zoomerInputClass

Type: string
Default value: "cr-slider"

Optionally set a different class on the zoom range input to customize styling (e.g. set to "form-range" when using Bootstrap).

rotateButtonClass

Type: string
Default value: "cr-rotate-btn"

Optionally set a different class on the rotate buttons to customize styling.

Methods

bind(src: string, state: CroptState | number | null = null): Promise<void>

Takes an image URL as the first argument. Returns a Promise which resolves when the image has been loaded and state is initialized.

The optional second argument can be:

  • A CroptState object (returned by getState()) to restore a previously saved crop position, zoom, viewport size, and rotation.
  • A number to set only the initial zoom level.

getState(): CroptState

Returns the current crop state as a CroptState object with fields x, y, zoom, width, height, and rotation. This can be stored alongside the original image and later passed to bind() to restore the crop position, zoom level, viewport size, and rotation.

// Save state when the user is done croppingconststate=cropt.getState();// Later, restore the same crop position on the same imagecropt.bind("path/to/image.jpg",state);

destroy(): void

Deconstructs a Cropt instance and removes the elements from the DOM.

refresh(): void

Recalculate points for the image. Necessary if the instance was bound while hidden, or if it has been hidden and re-shown.

toCanvas(size: number | null = null): Promise<HTMLCanvasElement>

Returns a Promise resolving to an HTMLCanvasElement object for the cropped image. If size is specified, the cropped image will be scaled with its longest side set to this value.

toBlob(size: number | null = null, type = "image/webp", quality = 1): Promise<Blob>

Returns a Promise resolving to a Blob object for the cropped image. If size is specified, the cropped image will be scaled with its longest side set to this value. The type and quality parameters are passed directly to the corresponding HTMLCanvasElement.toBlob() method parameters.

setOptions(options: CroptOptions): void

Allows options to be dynamically changed on an existing Cropt instance.

rotate(degrees: number): Promise<void>

Rotates the image by the specified amount (must be a multiple of 90°, e.g. 90, -90, 180). The new crop state is applied immediately, so getState() and toCanvas() reflect the rotation without awaiting. The returned Promise resolves once the rotation animation finishes (or immediately when the animation is skipped, e.g. under prefers-reduced-motion).

This method can be used regardless of whether enableRotate is set to true.

setZoom(value: number): void

Set the zoom of a Cropt instance. The value must be between 0 and 1, and is clamped to the min/max zoom calculated for the current image.

Visibility and binding

Cropt is dependent on its container being visible when the bind method is called. This can be an issue when your component is inside a modal that isn't shown. Consider the Bootstrap modal, for example:

constcropEl=document.getElementById('my-cropt');constc=newCropt(cropEl,opts);constmyModal=document.getElementById('my-modal');myModal.addEventListener('shown.bs.modal',()=>{c.bind("my/image.jpg");});

If your Cropt instance is inside a modal, make sure bind() is called after the modal finishes opening.

If a Cropt instance needs to be hidden and then re-shown, call the refresh() method to recalculate properties for the displayed image.

Browser support

Cropt is tested in the following browsers:

  • Firefox
  • Safari
  • Chrome
  • Edge

Cropt should also work in any other modern browser using an engine based on Gecko, WebKit, or Chromium.

License

MIT

About

A delightful JS image cropper optimized for mobile and desktop.

Topics

Resources

Contributing

Stars

54 stars

Watchers

5 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Cropt

A delightful image cropper optimized for both mobile and desktop use.

  • Includes TypeScript definitions.
  • Published as a native ES module.
  • Zero dependencies.
  • Originally based on Croppie, but rewritten in TypeScript with a simpler API and lots of bug fixes and polish.

Installation

npm install cropt

Usage

  1. Include the src/cropt.css stylesheet on your page.
  2. Add a <div> element with a unique ID to your HTML to hold the Cropt instance.
  3. Import Cropt and instantiate it with a reference to the <div> element and an object for options.
  4. Bind to an image URL.
<divid="cropper"></div>
import{Cropt}from"cropt";import"cropt/src/cropt.css";letcroptEl=document.getElementById('cropper');letcropt=newCropt(croptEl,{viewport: {width: 250,height: 250},});cropt.bind("path/to/image.jpg");

Binding from a file input

To let users pick an image from their device, bind from a file <input> element's change event using URL.createObjectURL():

<inputtype="file" id="fileInput" accept="image/*" />
document.getElementById('fileInput').addEventListener('change',(e)=>{constfile=e.target.files[0];if(!file)return;consturl=URL.createObjectURL(file);cropt.bind(url).then(()=>URL.revokeObjectURL(url));});

The object URL can be revoked after binding because Cropt has already loaded the image data into the DOM at that point.

Uploading the cropped image

Use toBlob() to get the cropped image as a Blob, then send it to your server with fetch:

asyncfunctionupload(){constblob=awaitcropt.toBlob(500,"image/webp");// longest side scaled to 500pxconstbody=newFormData();body.append('image',blob,'crop.webp');awaitfetch('/upload',{method: 'POST', body });}

Sizing

The Cropt boundary defaults to 320px wide and 320px high. To customize this, override the .cropt-container .cr-boundary width and height via CSS.

Options

mouseWheelZoom

Type: "off" | "on" | "ctrl"
Default value: "on"

If set to "off", the mouse wheel cannot be used to zoom in and out of the image. If set to "ctrl", the mouse wheel will only zoom in and out while the CTRL key is pressed.

viewport

Type: { width: number, height: number, borderRadius: string }
Default value: { width: 220, height: 220, borderRadius: "0px" }

Defines the size and shape of the crop box. For a circle shape, set the border radius to "50%".

enableResize

Type: boolean
Default value: false

If set to true, resize handles are shown on the edges of the viewport, allowing the user to adjust its size.

enableRotate

Type: boolean
Default value: false

If set to true, rotate buttons are shown beside the zoom slider, allowing the user to rotate the image 90° clockwise or counter-clockwise.

zoomerInputClass

Type: string
Default value: "cr-slider"

Optionally set a different class on the zoom range input to customize styling (e.g. set to "form-range" when using Bootstrap).

rotateButtonClass

Type: string
Default value: "cr-rotate-btn"

Optionally set a different class on the rotate buttons to customize styling.

Methods

bind(src: string, state: CroptState | number | null = null): Promise<void>

Takes an image URL as the first argument. Returns a Promise which resolves when the image has been loaded and state is initialized.

The optional second argument can be:

  • A CroptState object (returned by getState()) to restore a previously saved crop position, zoom, viewport size, and rotation.
  • A number to set only the initial zoom level.

getState(): CroptState

Returns the current crop state as a CroptState object with fields x, y, zoom, width, height, and rotation. This can be stored alongside the original image and later passed to bind() to restore the crop position, zoom level, viewport size, and rotation.

// Save state when the user is done croppingconststate=cropt.getState();// Later, restore the same crop position on the same imagecropt.bind("path/to/image.jpg",state);

destroy(): void

Deconstructs a Cropt instance and removes the elements from the DOM.

refresh(): void

Recalculate points for the image. Necessary if the instance was bound while hidden, or if it has been hidden and re-shown.

toCanvas(size: number | null = null): Promise<HTMLCanvasElement>

Returns a Promise resolving to an HTMLCanvasElement object for the cropped image. If size is specified, the cropped image will be scaled with its longest side set to this value.

toBlob(size: number | null = null, type = "image/webp", quality = 1): Promise<Blob>

Returns a Promise resolving to a Blob object for the cropped image. If size is specified, the cropped image will be scaled with its longest side set to this value. The type and quality parameters are passed directly to the corresponding HTMLCanvasElement.toBlob() method parameters.

setOptions(options: CroptOptions): void

Allows options to be dynamically changed on an existing Cropt instance.

rotate(degrees: number): Promise<void>

Rotates the image by the specified amount (must be a multiple of 90°, e.g. 90, -90, 180). The new crop state is applied immediately, so getState() and toCanvas() reflect the rotation without awaiting. The returned Promise resolves once the rotation animation finishes (or immediately when the animation is skipped, e.g. under prefers-reduced-motion).

This method can be used regardless of whether enableRotate is set to true.

setZoom(value: number): void

Set the zoom of a Cropt instance. The value must be between 0 and 1, and is clamped to the min/max zoom calculated for the current image.

Visibility and binding

Cropt is dependent on its container being visible when the bind method is called. This can be an issue when your component is inside a modal that isn't shown. Consider the Bootstrap modal, for example:

constcropEl=document.getElementById('my-cropt');constc=newCropt(cropEl,opts);constmyModal=document.getElementById('my-modal');myModal.addEventListener('shown.bs.modal',()=>{c.bind("my/image.jpg");});

If your Cropt instance is inside a modal, make sure bind() is called after the modal finishes opening.

If a Cropt instance needs to be hidden and then re-shown, call the refresh() method to recalculate properties for the displayed image.

Browser support

Cropt is tested in the following browsers:

  • Firefox
  • Safari
  • Chrome
  • Edge

Cropt should also work in any other modern browser using an engine based on Gecko, WebKit, or Chromium.

License

MIT

About

A delightful JS image cropper optimized for mobile and desktop.

Topics

Resources

Contributing

Stars

54 stars

Watchers

5 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Cropt

A delightful image cropper optimized for both mobile and desktop use.

  • Includes TypeScript definitions.
  • Published as a native ES module.
  • Zero dependencies.
  • Originally based on Croppie, but rewritten in TypeScript with a simpler API and lots of bug fixes and polish.

Installation

npm install cropt

Usage

  1. Include the src/cropt.css stylesheet on your page.
  2. Add a <div> element with a unique ID to your HTML to hold the Cropt instance.
  3. Import Cropt and instantiate it with a reference to the <div> element and an object for options.
  4. Bind to an image URL.
<divid="cropper"></div>
import{Cropt}from"cropt";import"cropt/src/cropt.css";letcroptEl=document.getElementById('cropper');letcropt=newCropt(croptEl,{viewport: {width: 250,height: 250},});cropt.bind("path/to/image.jpg");

Binding from a file input

To let users pick an image from their device, bind from a file <input> element's change event using URL.createObjectURL():

<inputtype="file" id="fileInput" accept="image/*" />
document.getElementById('fileInput').addEventListener('change',(e)=>{constfile=e.target.files[0];if(!file)return;consturl=URL.createObjectURL(file);cropt.bind(url).then(()=>URL.revokeObjectURL(url));});

The object URL can be revoked after binding because Cropt has already loaded the image data into the DOM at that point.

Uploading the cropped image

Use toBlob() to get the cropped image as a Blob, then send it to your server with fetch:

asyncfunctionupload(){constblob=awaitcropt.toBlob(500,"image/webp");// longest side scaled to 500pxconstbody=newFormData();body.append('image',blob,'crop.webp');awaitfetch('/upload',{method: 'POST', body });}

Sizing

The Cropt boundary defaults to 320px wide and 320px high. To customize this, override the .cropt-container .cr-boundary width and height via CSS.

Options

mouseWheelZoom

Type: "off" | "on" | "ctrl"
Default value: "on"

If set to "off", the mouse wheel cannot be used to zoom in and out of the image. If set to "ctrl", the mouse wheel will only zoom in and out while the CTRL key is pressed.

viewport

Type: { width: number, height: number, borderRadius: string }
Default value: { width: 220, height: 220, borderRadius: "0px" }

Defines the size and shape of the crop box. For a circle shape, set the border radius to "50%".

enableResize

Type: boolean
Default value: false

If set to true, resize handles are shown on the edges of the viewport, allowing the user to adjust its size.

enableRotate

Type: boolean
Default value: false

If set to true, rotate buttons are shown beside the zoom slider, allowing the user to rotate the image 90° clockwise or counter-clockwise.

zoomerInputClass

Type: string
Default value: "cr-slider"

Optionally set a different class on the zoom range input to customize styling (e.g. set to "form-range" when using Bootstrap).

rotateButtonClass

Type: string
Default value: "cr-rotate-btn"

Optionally set a different class on the rotate buttons to customize styling.

Methods

bind(src: string, state: CroptState | number | null = null): Promise<void>

Takes an image URL as the first argument. Returns a Promise which resolves when the image has been loaded and state is initialized.

The optional second argument can be:

  • A CroptState object (returned by getState()) to restore a previously saved crop position, zoom, viewport size, and rotation.
  • A number to set only the initial zoom level.

getState(): CroptState

Returns the current crop state as a CroptState object with fields x, y, zoom, width, height, and rotation. This can be stored alongside the original image and later passed to bind() to restore the crop position, zoom level, viewport size, and rotation.

// Save state when the user is done croppingconststate=cropt.getState();// Later, restore the same crop position on the same imagecropt.bind("path/to/image.jpg",state);

destroy(): void

Deconstructs a Cropt instance and removes the elements from the DOM.

refresh(): void

Recalculate points for the image. Necessary if the instance was bound while hidden, or if it has been hidden and re-shown.

toCanvas(size: number | null = null): Promise<HTMLCanvasElement>

Returns a Promise resolving to an HTMLCanvasElement object for the cropped image. If size is specified, the cropped image will be scaled with its longest side set to this value.

toBlob(size: number | null = null, type = "image/webp", quality = 1): Promise<Blob>

Returns a Promise resolving to a Blob object for the cropped image. If size is specified, the cropped image will be scaled with its longest side set to this value. The type and quality parameters are passed directly to the corresponding HTMLCanvasElement.toBlob() method parameters.

setOptions(options: CroptOptions): void

Allows options to be dynamically changed on an existing Cropt instance.

rotate(degrees: number): Promise<void>

Rotates the image by the specified amount (must be a multiple of 90°, e.g. 90, -90, 180). The new crop state is applied immediately, so getState() and toCanvas() reflect the rotation without awaiting. The returned Promise resolves once the rotation animation finishes (or immediately when the animation is skipped, e.g. under prefers-reduced-motion).

This method can be used regardless of whether enableRotate is set to true.

setZoom(value: number): void

Set the zoom of a Cropt instance. The value must be between 0 and 1, and is clamped to the min/max zoom calculated for the current image.

Visibility and binding

Cropt is dependent on its container being visible when the bind method is called. This can be an issue when your component is inside a modal that isn't shown. Consider the Bootstrap modal, for example:

constcropEl=document.getElementById('my-cropt');constc=newCropt(cropEl,opts);constmyModal=document.getElementById('my-modal');myModal.addEventListener('shown.bs.modal',()=>{c.bind("my/image.jpg");});

If your Cropt instance is inside a modal, make sure bind() is called after the modal finishes opening.

If a Cropt instance needs to be hidden and then re-shown, call the refresh() method to recalculate properties for the displayed image.

Browser support

Cropt is tested in the following browsers:

  • Firefox
  • Safari
  • Chrome
  • Edge

Cropt should also work in any other modern browser using an engine based on Gecko, WebKit, or Chromium.

License

MIT

About

A delightful JS image cropper optimized for mobile and desktop.

Topics

Resources

Contributing

Stars

54 stars

Watchers

5 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Cropt

A delightful image cropper optimized for both mobile and desktop use.

  • Includes TypeScript definitions.
  • Published as a native ES module.
  • Zero dependencies.
  • Originally based on Croppie, but rewritten in TypeScript with a simpler API and lots of bug fixes and polish.

Installation

npm install cropt

Usage

  1. Include the src/cropt.css stylesheet on your page.
  2. Add a <div> element with a unique ID to your HTML to hold the Cropt instance.
  3. Import Cropt and instantiate it with a reference to the <div> element and an object for options.
  4. Bind to an image URL.
<divid="cropper"></div>
import{Cropt}from"cropt";import"cropt/src/cropt.css";letcroptEl=document.getElementById('cropper');letcropt=newCropt(croptEl,{viewport: {width: 250,height: 250},});cropt.bind("path/to/image.jpg");

Binding from a file input

To let users pick an image from their device, bind from a file <input> element's change event using URL.createObjectURL():

<inputtype="file" id="fileInput" accept="image/*" />
document.getElementById('fileInput').addEventListener('change',(e)=>{constfile=e.target.files[0];if(!file)return;consturl=URL.createObjectURL(file);cropt.bind(url).then(()=>URL.revokeObjectURL(url));});

The object URL can be revoked after binding because Cropt has already loaded the image data into the DOM at that point.

Uploading the cropped image

Use toBlob() to get the cropped image as a Blob, then send it to your server with fetch:

asyncfunctionupload(){constblob=awaitcropt.toBlob(500,"image/webp");// longest side scaled to 500pxconstbody=newFormData();body.append('image',blob,'crop.webp');awaitfetch('/upload',{method: 'POST', body });}

Sizing

The Cropt boundary defaults to 320px wide and 320px high. To customize this, override the .cropt-container .cr-boundary width and height via CSS.

Options

mouseWheelZoom

Type: "off" | "on" | "ctrl"
Default value: "on"

If set to "off", the mouse wheel cannot be used to zoom in and out of the image. If set to "ctrl", the mouse wheel will only zoom in and out while the CTRL key is pressed.

viewport

Type: { width: number, height: number, borderRadius: string }
Default value: { width: 220, height: 220, borderRadius: "0px" }

Defines the size and shape of the crop box. For a circle shape, set the border radius to "50%".

enableResize

Type: boolean
Default value: false

If set to true, resize handles are shown on the edges of the viewport, allowing the user to adjust its size.

enableRotate

Type: boolean
Default value: false

If set to true, rotate buttons are shown beside the zoom slider, allowing the user to rotate the image 90° clockwise or counter-clockwise.

zoomerInputClass

Type: string
Default value: "cr-slider"

Optionally set a different class on the zoom range input to customize styling (e.g. set to "form-range" when using Bootstrap).

rotateButtonClass

Type: string
Default value: "cr-rotate-btn"

Optionally set a different class on the rotate buttons to customize styling.

Methods

bind(src: string, state: CroptState | number | null = null): Promise<void>

Takes an image URL as the first argument. Returns a Promise which resolves when the image has been loaded and state is initialized.

The optional second argument can be:

  • A CroptState object (returned by getState()) to restore a previously saved crop position, zoom, viewport size, and rotation.
  • A number to set only the initial zoom level.

getState(): CroptState

Returns the current crop state as a CroptState object with fields x, y, zoom, width, height, and rotation. This can be stored alongside the original image and later passed to bind() to restore the crop position, zoom level, viewport size, and rotation.

// Save state when the user is done croppingconststate=cropt.getState();// Later, restore the same crop position on the same imagecropt.bind("path/to/image.jpg",state);

destroy(): void

Deconstructs a Cropt instance and removes the elements from the DOM.

refresh(): void

Recalculate points for the image. Necessary if the instance was bound while hidden, or if it has been hidden and re-shown.

toCanvas(size: number | null = null): Promise<HTMLCanvasElement>

Returns a Promise resolving to an HTMLCanvasElement object for the cropped image. If size is specified, the cropped image will be scaled with its longest side set to this value.

toBlob(size: number | null = null, type = "image/webp", quality = 1): Promise<Blob>

Returns a Promise resolving to a Blob object for the cropped image. If size is specified, the cropped image will be scaled with its longest side set to this value. The type and quality parameters are passed directly to the corresponding HTMLCanvasElement.toBlob() method parameters.

setOptions(options: CroptOptions): void

Allows options to be dynamically changed on an existing Cropt instance.

rotate(degrees: number): Promise<void>

Rotates the image by the specified amount (must be a multiple of 90°, e.g. 90, -90, 180). The new crop state is applied immediately, so getState() and toCanvas() reflect the rotation without awaiting. The returned Promise resolves once the rotation animation finishes (or immediately when the animation is skipped, e.g. under prefers-reduced-motion).

This method can be used regardless of whether enableRotate is set to true.

setZoom(value: number): void

Set the zoom of a Cropt instance. The value must be between 0 and 1, and is clamped to the min/max zoom calculated for the current image.

Visibility and binding

Cropt is dependent on its container being visible when the bind method is called. This can be an issue when your component is inside a modal that isn't shown. Consider the Bootstrap modal, for example:

constcropEl=document.getElementById('my-cropt');constc=newCropt(cropEl,opts);constmyModal=document.getElementById('my-modal');myModal.addEventListener('shown.bs.modal',()=>{c.bind("my/image.jpg");});

If your Cropt instance is inside a modal, make sure bind() is called after the modal finishes opening.

If a Cropt instance needs to be hidden and then re-shown, call the refresh() method to recalculate properties for the displayed image.

Browser support

Cropt is tested in the following browsers:

  • Firefox
  • Safari
  • Chrome
  • Edge

Cropt should also work in any other modern browser using an engine based on Gecko, WebKit, or Chromium.

License

MIT

About

A delightful JS image cropper optimized for mobile and desktop.

Topics

Resources

Contributing

Stars

54 stars

Watchers

5 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Cropt

A delightful image cropper optimized for both mobile and desktop use.

  • Includes TypeScript definitions.
  • Published as a native ES module.
  • Zero dependencies.
  • Originally based on Croppie, but rewritten in TypeScript with a simpler API and lots of bug fixes and polish.

Installation

npm install cropt

Usage

  1. Include the src/cropt.css stylesheet on your page.
  2. Add a <div> element with a unique ID to your HTML to hold the Cropt instance.
  3. Import Cropt and instantiate it with a reference to the <div> element and an object for options.
  4. Bind to an image URL.
<divid="cropper"></div>
import{Cropt}from"cropt";import"cropt/src/cropt.css";letcroptEl=document.getElementById('cropper');letcropt=newCropt(croptEl,{viewport: {width: 250,height: 250},});cropt.bind("path/to/image.jpg");

Binding from a file input

To let users pick an image from their device, bind from a file <input> element's change event using URL.createObjectURL():

<inputtype="file" id="fileInput" accept="image/*" />
document.getElementById('fileInput').addEventListener('change',(e)=>{constfile=e.target.files[0];if(!file)return;consturl=URL.createObjectURL(file);cropt.bind(url).then(()=>URL.revokeObjectURL(url));});

The object URL can be revoked after binding because Cropt has already loaded the image data into the DOM at that point.

Uploading the cropped image

Use toBlob() to get the cropped image as a Blob, then send it to your server with fetch:

asyncfunctionupload(){constblob=awaitcropt.toBlob(500,"image/webp");// longest side scaled to 500pxconstbody=newFormData();body.append('image',blob,'crop.webp');awaitfetch('/upload',{method: 'POST', body });}

Sizing

The Cropt boundary defaults to 320px wide and 320px high. To customize this, override the .cropt-container .cr-boundary width and height via CSS.

Options

mouseWheelZoom

Type: "off" | "on" | "ctrl"
Default value: "on"

If set to "off", the mouse wheel cannot be used to zoom in and out of the image. If set to "ctrl", the mouse wheel will only zoom in and out while the CTRL key is pressed.

viewport

Type: { width: number, height: number, borderRadius: string }
Default value: { width: 220, height: 220, borderRadius: "0px" }

Defines the size and shape of the crop box. For a circle shape, set the border radius to "50%".

enableResize

Type: boolean
Default value: false

If set to true, resize handles are shown on the edges of the viewport, allowing the user to adjust its size.

enableRotate

Type: boolean
Default value: false

If set to true, rotate buttons are shown beside the zoom slider, allowing the user to rotate the image 90° clockwise or counter-clockwise.

zoomerInputClass

Type: string
Default value: "cr-slider"

Optionally set a different class on the zoom range input to customize styling (e.g. set to "form-range" when using Bootstrap).

rotateButtonClass

Type: string
Default value: "cr-rotate-btn"

Optionally set a different class on the rotate buttons to customize styling.

Methods

bind(src: string, state: CroptState | number | null = null): Promise<void>

Takes an image URL as the first argument. Returns a Promise which resolves when the image has been loaded and state is initialized.

The optional second argument can be:

  • A CroptState object (returned by getState()) to restore a previously saved crop position, zoom, viewport size, and rotation.
  • A number to set only the initial zoom level.

getState(): CroptState

Returns the current crop state as a CroptState object with fields x, y, zoom, width, height, and rotation. This can be stored alongside the original image and later passed to bind() to restore the crop position, zoom level, viewport size, and rotation.

// Save state when the user is done croppingconststate=cropt.getState();// Later, restore the same crop position on the same imagecropt.bind("path/to/image.jpg",state);

destroy(): void

Deconstructs a Cropt instance and removes the elements from the DOM.

refresh(): void

Recalculate points for the image. Necessary if the instance was bound while hidden, or if it has been hidden and re-shown.

toCanvas(size: number | null = null): Promise<HTMLCanvasElement>

Returns a Promise resolving to an HTMLCanvasElement object for the cropped image. If size is specified, the cropped image will be scaled with its longest side set to this value.

toBlob(size: number | null = null, type = "image/webp", quality = 1): Promise<Blob>

Returns a Promise resolving to a Blob object for the cropped image. If size is specified, the cropped image will be scaled with its longest side set to this value. The type and quality parameters are passed directly to the corresponding HTMLCanvasElement.toBlob() method parameters.

setOptions(options: CroptOptions): void

Allows options to be dynamically changed on an existing Cropt instance.

rotate(degrees: number): Promise<void>

Rotates the image by the specified amount (must be a multiple of 90°, e.g. 90, -90, 180). The new crop state is applied immediately, so getState() and toCanvas() reflect the rotation without awaiting. The returned Promise resolves once the rotation animation finishes (or immediately when the animation is skipped, e.g. under prefers-reduced-motion).

This method can be used regardless of whether enableRotate is set to true.

setZoom(value: number): void

Set the zoom of a Cropt instance. The value must be between 0 and 1, and is clamped to the min/max zoom calculated for the current image.

Visibility and binding

Cropt is dependent on its container being visible when the bind method is called. This can be an issue when your component is inside a modal that isn't shown. Consider the Bootstrap modal, for example:

constcropEl=document.getElementById('my-cropt');constc=newCropt(cropEl,opts);constmyModal=document.getElementById('my-modal');myModal.addEventListener('shown.bs.modal',()=>{c.bind("my/image.jpg");});

If your Cropt instance is inside a modal, make sure bind() is called after the modal finishes opening.

If a Cropt instance needs to be hidden and then re-shown, call the refresh() method to recalculate properties for the displayed image.

Browser support

Cropt is tested in the following browsers:

  • Firefox
  • Safari
  • Chrome
  • Edge

Cropt should also work in any other modern browser using an engine based on Gecko, WebKit, or Chromium.

License

MIT

About

A delightful JS image cropper optimized for mobile and desktop.

Topics

Resources

Contributing

Stars

54 stars

Watchers

5 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Cropt

A delightful image cropper optimized for both mobile and desktop use.

  • Includes TypeScript definitions.
  • Published as a native ES module.
  • Zero dependencies.
  • Originally based on Croppie, but rewritten in TypeScript with a simpler API and lots of bug fixes and polish.

Installation

npm install cropt

Usage

  1. Include the src/cropt.css stylesheet on your page.
  2. Add a <div> element with a unique ID to your HTML to hold the Cropt instance.
  3. Import Cropt and instantiate it with a reference to the <div> element and an object for options.
  4. Bind to an image URL.
<divid="cropper"></div>
import{Cropt}from"cropt";import"cropt/src/cropt.css";letcroptEl=document.getElementById('cropper');letcropt=newCropt(croptEl,{viewport: {width: 250,height: 250},});cropt.bind("path/to/image.jpg");

Binding from a file input

To let users pick an image from their device, bind from a file <input> element's change event using URL.createObjectURL():

<inputtype="file" id="fileInput" accept="image/*" />
document.getElementById('fileInput').addEventListener('change',(e)=>{constfile=e.target.files[0];if(!file)return;consturl=URL.createObjectURL(file);cropt.bind(url).then(()=>URL.revokeObjectURL(url));});

The object URL can be revoked after binding because Cropt has already loaded the image data into the DOM at that point.

Uploading the cropped image

Use toBlob() to get the cropped image as a Blob, then send it to your server with fetch:

asyncfunctionupload(){constblob=awaitcropt.toBlob(500,"image/webp");// longest side scaled to 500pxconstbody=newFormData();body.append('image',blob,'crop.webp');awaitfetch('/upload',{method: 'POST', body });}

Sizing

The Cropt boundary defaults to 320px wide and 320px high. To customize this, override the .cropt-container .cr-boundary width and height via CSS.

Options

mouseWheelZoom

Type: "off" | "on" | "ctrl"
Default value: "on"

If set to "off", the mouse wheel cannot be used to zoom in and out of the image. If set to "ctrl", the mouse wheel will only zoom in and out while the CTRL key is pressed.

viewport

Type: { width: number, height: number, borderRadius: string }
Default value: { width: 220, height: 220, borderRadius: "0px" }

Defines the size and shape of the crop box. For a circle shape, set the border radius to "50%".

enableResize

Type: boolean
Default value: false

If set to true, resize handles are shown on the edges of the viewport, allowing the user to adjust its size.

enableRotate

Type: boolean
Default value: false

If set to true, rotate buttons are shown beside the zoom slider, allowing the user to rotate the image 90° clockwise or counter-clockwise.

zoomerInputClass

Type: string
Default value: "cr-slider"

Optionally set a different class on the zoom range input to customize styling (e.g. set to "form-range" when using Bootstrap).

rotateButtonClass

Type: string
Default value: "cr-rotate-btn"

Optionally set a different class on the rotate buttons to customize styling.

Methods

bind(src: string, state: CroptState | number | null = null): Promise<void>

Takes an image URL as the first argument. Returns a Promise which resolves when the image has been loaded and state is initialized.

The optional second argument can be:

  • A CroptState object (returned by getState()) to restore a previously saved crop position, zoom, viewport size, and rotation.
  • A number to set only the initial zoom level.

getState(): CroptState

Returns the current crop state as a CroptState object with fields x, y, zoom, width, height, and rotation. This can be stored alongside the original image and later passed to bind() to restore the crop position, zoom level, viewport size, and rotation.

// Save state when the user is done croppingconststate=cropt.getState();// Later, restore the same crop position on the same imagecropt.bind("path/to/image.jpg",state);

destroy(): void

Deconstructs a Cropt instance and removes the elements from the DOM.

refresh(): void

Recalculate points for the image. Necessary if the instance was bound while hidden, or if it has been hidden and re-shown.

toCanvas(size: number | null = null): Promise<HTMLCanvasElement>

Returns a Promise resolving to an HTMLCanvasElement object for the cropped image. If size is specified, the cropped image will be scaled with its longest side set to this value.

toBlob(size: number | null = null, type = "image/webp", quality = 1): Promise<Blob>

Returns a Promise resolving to a Blob object for the cropped image. If size is specified, the cropped image will be scaled with its longest side set to this value. The type and quality parameters are passed directly to the corresponding HTMLCanvasElement.toBlob() method parameters.

setOptions(options: CroptOptions): void

Allows options to be dynamically changed on an existing Cropt instance.

rotate(degrees: number): Promise<void>

Rotates the image by the specified amount (must be a multiple of 90°, e.g. 90, -90, 180). The new crop state is applied immediately, so getState() and toCanvas() reflect the rotation without awaiting. The returned Promise resolves once the rotation animation finishes (or immediately when the animation is skipped, e.g. under prefers-reduced-motion).

This method can be used regardless of whether enableRotate is set to true.

setZoom(value: number): void

Set the zoom of a Cropt instance. The value must be between 0 and 1, and is clamped to the min/max zoom calculated for the current image.

Visibility and binding

Cropt is dependent on its container being visible when the bind method is called. This can be an issue when your component is inside a modal that isn't shown. Consider the Bootstrap modal, for example:

constcropEl=document.getElementById('my-cropt');constc=newCropt(cropEl,opts);constmyModal=document.getElementById('my-modal');myModal.addEventListener('shown.bs.modal',()=>{c.bind("my/image.jpg");});

If your Cropt instance is inside a modal, make sure bind() is called after the modal finishes opening.

If a Cropt instance needs to be hidden and then re-shown, call the refresh() method to recalculate properties for the displayed image.

Browser support

Cropt is tested in the following browsers:

  • Firefox
  • Safari
  • Chrome
  • Edge

Cropt should also work in any other modern browser using an engine based on Gecko, WebKit, or Chromium.

License

MIT

About

A delightful JS image cropper optimized for mobile and desktop.

Topics

Resources

Contributing

Stars

54 stars

Watchers

5 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Cropt

A delightful image cropper optimized for both mobile and desktop use.

  • Includes TypeScript definitions.
  • Published as a native ES module.
  • Zero dependencies.
  • Originally based on Croppie, but rewritten in TypeScript with a simpler API and lots of bug fixes and polish.

Installation

npm install cropt

Usage

  1. Include the src/cropt.css stylesheet on your page.
  2. Add a <div> element with a unique ID to your HTML to hold the Cropt instance.
  3. Import Cropt and instantiate it with a reference to the <div> element and an object for options.
  4. Bind to an image URL.
<divid="cropper"></div>
import{Cropt}from"cropt";import"cropt/src/cropt.css";letcroptEl=document.getElementById('cropper');letcropt=newCropt(croptEl,{viewport: {width: 250,height: 250},});cropt.bind("path/to/image.jpg");

Binding from a file input

To let users pick an image from their device, bind from a file <input> element's change event using URL.createObjectURL():

<inputtype="file" id="fileInput" accept="image/*" />
document.getElementById('fileInput').addEventListener('change',(e)=>{constfile=e.target.files[0];if(!file)return;consturl=URL.createObjectURL(file);cropt.bind(url).then(()=>URL.revokeObjectURL(url));});

The object URL can be revoked after binding because Cropt has already loaded the image data into the DOM at that point.

Uploading the cropped image

Use toBlob() to get the cropped image as a Blob, then send it to your server with fetch:

asyncfunctionupload(){constblob=awaitcropt.toBlob(500,"image/webp");// longest side scaled to 500pxconstbody=newFormData();body.append('image',blob,'crop.webp');awaitfetch('/upload',{method: 'POST', body });}

Sizing

The Cropt boundary defaults to 320px wide and 320px high. To customize this, override the .cropt-container .cr-boundary width and height via CSS.

Options

mouseWheelZoom

Type: "off" | "on" | "ctrl"
Default value: "on"

If set to "off", the mouse wheel cannot be used to zoom in and out of the image. If set to "ctrl", the mouse wheel will only zoom in and out while the CTRL key is pressed.

viewport

Type: { width: number, height: number, borderRadius: string }
Default value: { width: 220, height: 220, borderRadius: "0px" }

Defines the size and shape of the crop box. For a circle shape, set the border radius to "50%".

enableResize

Type: boolean
Default value: false

If set to true, resize handles are shown on the edges of the viewport, allowing the user to adjust its size.

enableRotate

Type: boolean
Default value: false

If set to true, rotate buttons are shown beside the zoom slider, allowing the user to rotate the image 90° clockwise or counter-clockwise.

zoomerInputClass

Type: string
Default value: "cr-slider"

Optionally set a different class on the zoom range input to customize styling (e.g. set to "form-range" when using Bootstrap).

rotateButtonClass

Type: string
Default value: "cr-rotate-btn"

Optionally set a different class on the rotate buttons to customize styling.

Methods

bind(src: string, state: CroptState | number | null = null): Promise<void>

Takes an image URL as the first argument. Returns a Promise which resolves when the image has been loaded and state is initialized.

The optional second argument can be:

  • A CroptState object (returned by getState()) to restore a previously saved crop position, zoom, viewport size, and rotation.
  • A number to set only the initial zoom level.

getState(): CroptState

Returns the current crop state as a CroptState object with fields x, y, zoom, width, height, and rotation. This can be stored alongside the original image and later passed to bind() to restore the crop position, zoom level, viewport size, and rotation.

// Save state when the user is done croppingconststate=cropt.getState();// Later, restore the same crop position on the same imagecropt.bind("path/to/image.jpg",state);

destroy(): void

Deconstructs a Cropt instance and removes the elements from the DOM.

refresh(): void

Recalculate points for the image. Necessary if the instance was bound while hidden, or if it has been hidden and re-shown.

toCanvas(size: number | null = null): Promise<HTMLCanvasElement>

Returns a Promise resolving to an HTMLCanvasElement object for the cropped image. If size is specified, the cropped image will be scaled with its longest side set to this value.

toBlob(size: number | null = null, type = "image/webp", quality = 1): Promise<Blob>

Returns a Promise resolving to a Blob object for the cropped image. If size is specified, the cropped image will be scaled with its longest side set to this value. The type and quality parameters are passed directly to the corresponding HTMLCanvasElement.toBlob() method parameters.

setOptions(options: CroptOptions): void

Allows options to be dynamically changed on an existing Cropt instance.

rotate(degrees: number): Promise<void>

Rotates the image by the specified amount (must be a multiple of 90°, e.g. 90, -90, 180). The new crop state is applied immediately, so getState() and toCanvas() reflect the rotation without awaiting. The returned Promise resolves once the rotation animation finishes (or immediately when the animation is skipped, e.g. under prefers-reduced-motion).

This method can be used regardless of whether enableRotate is set to true.

setZoom(value: number): void

Set the zoom of a Cropt instance. The value must be between 0 and 1, and is clamped to the min/max zoom calculated for the current image.

Visibility and binding

Cropt is dependent on its container being visible when the bind method is called. This can be an issue when your component is inside a modal that isn't shown. Consider the Bootstrap modal, for example:

constcropEl=document.getElementById('my-cropt');constc=newCropt(cropEl,opts);constmyModal=document.getElementById('my-modal');myModal.addEventListener('shown.bs.modal',()=>{c.bind("my/image.jpg");});

If your Cropt instance is inside a modal, make sure bind() is called after the modal finishes opening.

If a Cropt instance needs to be hidden and then re-shown, call the refresh() method to recalculate properties for the displayed image.

Browser support

Cropt is tested in the following browsers:

  • Firefox
  • Safari
  • Chrome
  • Edge

Cropt should also work in any other modern browser using an engine based on Gecko, WebKit, or Chromium.

License

MIT

About

A delightful JS image cropper optimized for mobile and desktop.

Topics

Resources

Contributing

Stars

54 stars

Watchers

5 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Cropt

A delightful image cropper optimized for both mobile and desktop use.

  • Includes TypeScript definitions.
  • Published as a native ES module.
  • Zero dependencies.
  • Originally based on Croppie, but rewritten in TypeScript with a simpler API and lots of bug fixes and polish.

Installation

npm install cropt

Usage

  1. Include the src/cropt.css stylesheet on your page.
  2. Add a <div> element with a unique ID to your HTML to hold the Cropt instance.
  3. Import Cropt and instantiate it with a reference to the <div> element and an object for options.
  4. Bind to an image URL.
<divid="cropper"></div>
import{Cropt}from"cropt";import"cropt/src/cropt.css";letcroptEl=document.getElementById('cropper');letcropt=newCropt(croptEl,{viewport: {width: 250,height: 250},});cropt.bind("path/to/image.jpg");

Binding from a file input

To let users pick an image from their device, bind from a file <input> element's change event using URL.createObjectURL():

<inputtype="file" id="fileInput" accept="image/*" />
document.getElementById('fileInput').addEventListener('change',(e)=>{constfile=e.target.files[0];if(!file)return;consturl=URL.createObjectURL(file);cropt.bind(url).then(()=>URL.revokeObjectURL(url));});

The object URL can be revoked after binding because Cropt has already loaded the image data into the DOM at that point.

Uploading the cropped image

Use toBlob() to get the cropped image as a Blob, then send it to your server with fetch:

asyncfunctionupload(){constblob=awaitcropt.toBlob(500,"image/webp");// longest side scaled to 500pxconstbody=newFormData();body.append('image',blob,'crop.webp');awaitfetch('/upload',{method: 'POST', body });}

Sizing

The Cropt boundary defaults to 320px wide and 320px high. To customize this, override the .cropt-container .cr-boundary width and height via CSS.

Options

mouseWheelZoom

Type: "off" | "on" | "ctrl"
Default value: "on"

If set to "off", the mouse wheel cannot be used to zoom in and out of the image. If set to "ctrl", the mouse wheel will only zoom in and out while the CTRL key is pressed.

viewport

Type: { width: number, height: number, borderRadius: string }
Default value: { width: 220, height: 220, borderRadius: "0px" }

Defines the size and shape of the crop box. For a circle shape, set the border radius to "50%".

enableResize

Type: boolean
Default value: false

If set to true, resize handles are shown on the edges of the viewport, allowing the user to adjust its size.

enableRotate

Type: boolean
Default value: false

If set to true, rotate buttons are shown beside the zoom slider, allowing the user to rotate the image 90° clockwise or counter-clockwise.

zoomerInputClass

Type: string
Default value: "cr-slider"

Optionally set a different class on the zoom range input to customize styling (e.g. set to "form-range" when using Bootstrap).

rotateButtonClass

Type: string
Default value: "cr-rotate-btn"

Optionally set a different class on the rotate buttons to customize styling.

Methods

bind(src: string, state: CroptState | number | null = null): Promise<void>

Takes an image URL as the first argument. Returns a Promise which resolves when the image has been loaded and state is initialized.

The optional second argument can be:

  • A CroptState object (returned by getState()) to restore a previously saved crop position, zoom, viewport size, and rotation.
  • A number to set only the initial zoom level.

getState(): CroptState

Returns the current crop state as a CroptState object with fields x, y, zoom, width, height, and rotation. This can be stored alongside the original image and later passed to bind() to restore the crop position, zoom level, viewport size, and rotation.

// Save state when the user is done croppingconststate=cropt.getState();// Later, restore the same crop position on the same imagecropt.bind("path/to/image.jpg",state);

destroy(): void

Deconstructs a Cropt instance and removes the elements from the DOM.

refresh(): void

Recalculate points for the image. Necessary if the instance was bound while hidden, or if it has been hidden and re-shown.

toCanvas(size: number | null = null): Promise<HTMLCanvasElement>

Returns a Promise resolving to an HTMLCanvasElement object for the cropped image. If size is specified, the cropped image will be scaled with its longest side set to this value.

toBlob(size: number | null = null, type = "image/webp", quality = 1): Promise<Blob>

Returns a Promise resolving to a Blob object for the cropped image. If size is specified, the cropped image will be scaled with its longest side set to this value. The type and quality parameters are passed directly to the corresponding HTMLCanvasElement.toBlob() method parameters.

setOptions(options: CroptOptions): void

Allows options to be dynamically changed on an existing Cropt instance.

rotate(degrees: number): Promise<void>

Rotates the image by the specified amount (must be a multiple of 90°, e.g. 90, -90, 180). The new crop state is applied immediately, so getState() and toCanvas() reflect the rotation without awaiting. The returned Promise resolves once the rotation animation finishes (or immediately when the animation is skipped, e.g. under prefers-reduced-motion).

This method can be used regardless of whether enableRotate is set to true.

setZoom(value: number): void

Set the zoom of a Cropt instance. The value must be between 0 and 1, and is clamped to the min/max zoom calculated for the current image.

Visibility and binding

Cropt is dependent on its container being visible when the bind method is called. This can be an issue when your component is inside a modal that isn't shown. Consider the Bootstrap modal, for example:

constcropEl=document.getElementById('my-cropt');constc=newCropt(cropEl,opts);constmyModal=document.getElementById('my-modal');myModal.addEventListener('shown.bs.modal',()=>{c.bind("my/image.jpg");});

If your Cropt instance is inside a modal, make sure bind() is called after the modal finishes opening.

If a Cropt instance needs to be hidden and then re-shown, call the refresh() method to recalculate properties for the displayed image.

Browser support

Cropt is tested in the following browsers:

  • Firefox
  • Safari
  • Chrome
  • Edge

Cropt should also work in any other modern browser using an engine based on Gecko, WebKit, or Chromium.

License

MIT

About

A delightful JS image cropper optimized for mobile and desktop.

Topics

Resources

Contributing

Stars

54 stars

Watchers

5 watching

Forks

Releases

Used by

Contributors

Languages