vue-instagram-cropper

Simple Image Cropper that works like Instagram for Vue

Usage no npm install needed!

<script type="module">
  import vueInstagramCropper from 'https://cdn.skypack.dev/vue-instagram-cropper';
</script>

README

Instagram Cropper for Vue πŸ–Ό

Downloads Version License

try it out

If you are looking to crop and upload images like in Instagram, please visit https://github.com/avidofood/vue-cropgram 😜

Installation in 2 Steps

1: Add with npm πŸ’»

 npm install vue-instagram-cropper

2a: Install as a component

 import InstagramCropper from 'vue-instagram-cropper'

 Vue.component('instagram-cropper', InstagramCropper);

2b: Install as a plugin

 import { PluginΒ } from 'vue-instagram-cropper'

 Vue.use(Plugin);

Usage - (or to make it runnable πŸƒβ€β™‚οΈ)

Easiest version πŸ”

 <instagram-cropper 
    :src="cropper"
 ></instagram-cropper>

 with 

 cropper: 'https://i.picsum.photos/id/468/200/300.jpg',

Advanced version 🌐

 <instagram-cropper
    ref="cropper"
    class="w-100 h-100"
    :src="cropper"
    :quality="4"
    :placeholder-font-size="14"
    placeholder-color="#000000" 
    placeholder="Choose or Drag'n'Drop an image"
 >
    <spinner v-if="loading"/>
 </instagram-cropper>

Demo ⚑️

https://avidofood.github.io/vue-instagram-cropper

Props

This package is made to immitate Instagram's cropper.

Props values

  • src (required: false, type: String or Object)

You can set the source of the placeholder image here. You can also use objects to set images. Test it by saving the meta-object by calling the method getMetadata().

  • quality (default: 2)

Multiplies your image output. If your canvas is 600px wide and the quality is set to 2, the output width will be 1200.

  • canvasColor (default: #F7F7F7)

  • placeholder (default: Choose an image)

  • placeholderColor (default: #67ACFD)

  • placeholderFontSize (default: 0)

Dynamic calculation when it's set to 0.

  • fileSizeLimit (default: 0)

If you love overlays, then copy the overlay from the advanced example.

  • forceCacheBreak (default: false)

This is important if you have still CORS issues. But remember the browser is not caching images anymore.

  • preventWhiteSpace (default: false)

Prevents revealing background white space when moving or zooming the image.

Events

  • init: Initialized
  • initial-image-loaded: Emitted when initial image loaded.
  • file-choose: File was chosen
  • file-size-exceed: File Size Limit was reached
  • file-type-mismatch: Only images are accepted
  • file-loaded: Emitted when a new file is received and read successfully
  • new-image: Emitted when a new valid image is received and read successfully
  • new-image-drawn: Emitted when a new image is drawn on canvas for the first time.
  • image-error: Emitted when an error occurs for the image (onerror-listener)
  • image-remove: Emitted when image is removed from croppa.
  • image-remove-onload: Emitted when image is removed from croppa due to file-loaded or change of src.
  • move:
  • zoom:
  • draw: Emitted on every view update
  • loading-start: Emitted when image loading phase starts.
  • loading-end: Emitted when image loading phase ends.
  • update: When a new image is drawn, you get get the metadata via the event.

Methods

You need to set ref=cropper to the HTML tag <instagram-cropper>. After that you can call all methods like this this.$refs.cropper.hasImage().

  • getCanvas(): returns the canvas object
  • getContext(): returns the canvas context object
  • getChosenFile(): returns File object
  • chooseFile(): Opens the file chooser window to choose an image.
  • refresh(): Reinitialize the component. Useful when you want to change initial image.
  • hasImage(): Return boolean value indicating whether currently there is a image.
  • generateDataUrl( type: string, compressionRate: number ):
    • Returns a data-URL containing a representation of the image in the format specified by the type parameter (defaults to png).
    • compressionRate defaults to 1, you can pass a number between 0 and 1 to get a compressed output image.
  • generateBlob( callback: function, mimeType: string, compressionRate: number ):
    • Creates a Blob object representing the image contained in the canvas.
    • If there is no image, the first argument of callback function is null.
  • promisedBlob( mimeType: string, compressionRate: number ):
    • This method returns a Promise wrapping around generateBlob(), so that you can use async/await syntax instead of a callback to get blob data, it's simpler.
    • If there is no image, the first argument of callback function is null.
  • getMetadata(): Gives an object back with all important information to create the image again at the same scale and position. Useful, if you are using a list of images.
const blob = await this.$refs.cropper.promisedBlob()
  • addClipPlugin(func): Add clip plugin to clip the image. Example:
// Add a clip plugin to make a circle clip on image
onInit(vm) {
  this.$refs.cropper.addClipPlugin(function (ctx, x, y, w, h) {
    /*
     * ctx: canvas context
     * x: start point (top-left corner) x coordination
     * y: start point (top-left corner) y coordination
     * w: croppa width
     * h: croppa height
    */
    ctx.beginPath();
    ctx.arc(x + w / 2, y + h / 2, w / 2, 0, 2 * Math.PI, true);
    ctx.closePath();
  })
},

Note: in the plugin function you should always start with ctx.beginPath() and end with ctx.closePath().

Note: it only works when prevent-white-space is true.

TODO

I have only limited time to develop this package further. It would mean a lot to me, if you would help me to improve it step by step. Here is a small list, what is still missing:

  • When zooming, the grid should be visible (Only moving shows the grid right now)
  • The maximum zoom limit is not the same as in Instagram
  • We need the prop forceAspect. Important if you want to "clip" the image to a specific aspect ratio. Needed for multiple images with vue-cropgram

Security

If you discover any security related issues, please don't email me. I'm afraid 😱. avidofood@protonmail.com

Credits

Now comes the best part! 😍 This package is based on

Oh come on. You read everything?? If you liked it so far, hit the ⭐️ button to give me a 🀩 face.