Introduction:
There are many images cropper packages on NPM platform. I have tried some of them for my projects and found out the most suitable and compatible image processing tool for Vue Cli 3. It offers the website (https://advanced-cropper.github.io/vue-advanced-cropper/ ) for demonstrations and documentations.
At the same time, there are some details to take care about. Also this article is beginer friendly for a simple setup.
Setup
Instead of using npm install -S vue-advanced-cropper. It requires following command for Vue 3.
npm install -S vue-advanced-cropper@next
Principal Concepts:
It is composed of three main parts: boundaries, visibleArea and coordinates.
Boundaries is the image area inside the cropper section. By default, it is equal to an image fitted to a cropper.
The visibleArea is the part of the image that a user see. It has same aspect ratio as boundaries.
Coordinates is the cropped coordinates of an image( left,top,width,height) inside the the visibleArea which is defined by coordinates.
*Minimal Working Example
*
It is necessary to implement and start with the minimal working example.
`
:src="img"
@change="change"
/>
<br>
import { Cropper } from 'vue-advanced-cropper';<br>
import 'vue-advanced-cropper/dist/style.css';</p>
<p>export default {<br>
components: {<br>
Cropper,<br>
},<br>
data() {<br>
return {<br>
img: '<a href="https://images.pexels.com/photos/4323307/pexels-photo-4323307.jpeg">https://images.pexels.com/photos/4323307/pexels-photo-4323307.jpeg</a>',<br>
};<br>
},<br>
methods: {<br>
change({ coordinates, canvas }) {<br>
console.log(coordinates, canvas);<br>
},<br>
},<br>
};<br>
:src="img"
To achieve the result of static cropper, you only need to alternate the <cropper /> section in the minimal working example with the following code.
:stencil-props="{
handlers: {},
movable: false,
scalable: false,
aspectRatio: 1,
}"
:resize-image="{
adjustStencil: false
}"
image-restriction="stencil"
/>
:src="img"
For the fixed stencil size, change the <cropper/> with
:stencil-props="{
handlers: {},
movable: false,
scalable: false,
}"
:stencil-size="{
width: 280,
height: 280
}"
image-restriction="stencil"
/>
:src="img"
If you need to move and resize its stencil, classic hybrid method is recommended.
:auto-zoom="true"
/>
There are only two default stencil, RectangleStencil, which shows above, and CircleStencil. I created a simple circleStencil example based from the instruction.
src="https://images.pexels.com/photos/1254140/pexels-photo-1254140.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"
:stencil-component="$options.components.CircleStencil"
/>
<br>
import { CircleStencil, Cropper } from 'vue-advanced-cropper';<br>
import 'vue-advanced-cropper/dist/style.css';</p>
<p>export default {<br>
components: {<br>
Cropper,CircleStencil<br>
},<br>
data() {<br>
return {<br>
img: '<a href="https://images.pexels.com/photos/4323307/pexels-photo-4323307.jpeg">https://images.pexels.com/photos/4323307/pexels-photo-4323307.jpeg</a>',<br>
};<br>
},<br>
methods: {<br>
change({ coordinates, canvas }) {<br>
console.log(coordinates, canvas);<br>
},<br>
},<br>
};<br>
Here is the example with circle edition of cropper with upload ability.
Load image
<br>
import { CircleStencil, Cropper } from 'vue-advanced-cropper';<br>
import 'vue-advanced-cropper/dist/style.css';</p>
<p>// This function is used to detect the actual image type, <br>
function getMimeType(file, fallback = null) {<br>
const byteArray = (new Uint8Array(file)).subarray(0, 4);<br>
let header = '';<br>
for (let i = 0; i < byteArray.length; i++) {<br>
header += byteArray[i].toString(16);<br>
}<br>
switch (header) {<br>
case "89504e47":<br>
return "image/png";<br>
case "47494638":<br>
return "image/gif";<br>
case "ffd8ffe0":<br>
case "ffd8ffe1":<br>
case "ffd8ffe2":<br>
case "ffd8ffe3":<br>
case "ffd8ffe8":<br>
return "image/jpeg";<br>
default:<br>
return fallback;<br>
}<br>
}</p>
<p>export default {<br>
components: {<br>
Cropper,<br>
CircleStencil<br>
},<br>
data() {<br>
return {<br>
image: {<br>
src: null,<br>
type: null<br>
}<br>
};<br>
},<br>
methods: {<br>
crop() {<br>
const { canvas } = this.$refs.cropper.getResult();<br>
canvas.toBlob((blob) => {<br>
// Do something with blob: upload to a server, download and etc.<br>
}, this.image.type);<br>
},<br>
reset() {<br>
this.image = {<br>
src: null,<br>
type: null<br>
}<br>
},<br>
loadImage(event) {<br>
// Reference to the DOM input element<br>
const { files } = event.target;<br>
// Ensure that you have a file before attempting to read it<br>
if (files && files[0]) {<br>
// 1. Revoke the object URL, to allow the garbage collector to destroy the uploaded before file<br>
if (this.image.src) {<br>
URL.revokeObjectURL(this.image.src)<br>
}<br>
// 2. Create the blob link to the file to optimize performance:<br>
const blob = URL.createObjectURL(files[0]);<br>
// 3. The steps below are designated to determine a file mime type to use it during the <br>
// getting of a cropped image from the canvas. You can replace it them by the following string, <br>
// but the type will be derived from the extension and it can lead to an incorrect result:<br>
//<br>
// this.image = {<br>
// src: blob;<br>
// type: files[0].type<br>
// }<br>
// Create a new FileReader to read this image binary data<br>
const reader = new FileReader();<br>
// Define a callback function to run, when FileReader finishes its job<br>
reader.onload = (e) => {<br>
// Note: arrow function used here, so that "this.image" refers to the image of Vue component<br>
this.image = {<br>
// Set the image source (it will look like blob:<a href="http://example.com/2c5270a5-18b5-406e-a4fb-07427f5e7b94">http://example.com/2c5270a5-18b5-406e-a4fb-07427f5e7b94</a>)<br>
src: blob,<br>
// Determine the image type to preserve it during the extracting the image from canvas:<br>
type: getMimeType(e.target.result, files[0].type),<br>
};<br>
};<br>
// Start the reader job - read file as a data url (base64 format)<br>
reader.readAsArrayBuffer(files[0]);<br>
}<br>
},<br>
},<br>
destroyed() {<br>
// Revoke the object URL, to allow the garbage collector to destroy the uploaded before file<br>
if (this.image.src) {<br>
URL.revokeObjectURL(this.image.src)<br>
}<br>
}<br>
};<br>
`
Remaind: toBlob is very important because that toBlob() will only do the first bullet synchronously, but will do the conversion to image format in a non blocking manner
Top comments (0)