1.0.1 • Published 8 months ago

image-editor-cropper v1.0.1

Weekly downloads
-
License
ISC
Repository
github
Last release
8 months ago

image-editor-cropper

Package Version Downloads

Programmatic Usage

npm install image-editor-cropper --save

Synchronous

const loadText = {
    "APPLY": "Apply",
    "BOLD": "Bold",
    "CANCEL": "Cancel",
    "CENTER": "Center",
    "CIRCLE": "Circle",
    "COLOR": "Color",
    "CROP": "Crop",
    "CUSTOM": "Custom",
    "DOWNLOAD": "Download",
    "DELETE": "Delete",
    "DELETE_ALL": "DeleteAll",
    "DRAW": "Draw",
    "FILL": "Fill",
    "FREE": "Free",
    "HAND": "Hand",
    "HISTORY": "History",
    "ITALIC": "Italic",
    "LEFT": "Left",
    "LOAD": "Load",
    "RANGE": "Range",
    "RECTANGLE": "Rectangle",
    "REDO": "Redo",
    "RESET": "Reset",
    "RIGHT": "Right",
    "SHAPE": "Shape",
    "SQUARE": "Square",
    "STRAIGHT": "Straight",
    "STROKE": "Stroke",
    "TRIANGLE": "Triangle",
    "TEXT": "Text",
    "TEXT_SIZE": "Text size",
    "UNDERLINE": "Underline",
    "UNDO": "Undo",
    "ZOOM_IN": "ZoomIn",
    "ZOOM_OUT": "ZoomOut"
}

React.js / Next.js Example

import React from 'react';
import ImageEditorCropper from 'image-editor-cropper';
import styled from "styled-components";
import colors from "@constants/Colors";
import {crossIcon} from "@helpers/Icons"; // SVG icons
const ImageModalWrap = styled.div`
    position:fixed;top:0;bottom:0;left:0;right:0;z-index:9999;display:flex;justify-content:center;align-items:center;background:#0000002b;
    & .back{position:absolute;left:0;top:0;right:0;bottom:0;}
    & .inner{
        background:${colors.white};z-index:99999;max-width:800px;width:calc(100% - 40px);height:calc(100vh - 20px);position:relative;border-radius:17px;overflow:hidden;
        & .header{
            display:flex;align-items:center;column-gap:10px;justify-content:space-between;padding:10px 20px;background:${colors.black};border-radius:17px 17px 0 0;
            & span{font-size:20px;line-height:24px;font-weight:600;color:${colors.white};}
            & .crop{
                display:flex;align-items:center;justify-content:center;padding:8px 15px;border-radius:6px;border:none;background:${colors.primaryButton};color:${colors.white};font-size:14px;line-height:1;cursor:pointer;margin-left:auto;
            }
            & .close{
                z-index:1;width:25px;height:25px;display:flex;align-items:center;justify-content:center;border:none;border-radius:20px;background:${colors.secondaryButton};cursor:pointer;
                & svg{fill:${colors.black};}
            }
        }
        & .body{padding:0;display:flex;flex-direction:column;flex:1;overflow-y:auto;height:calc(100% - 50px);}
    }
    @media (max-width:479px){
        & .inner{
            & .header{
                & span{font-size:16px;}
            }
        }
    }
`;
export default class ImageEditor extends React.Component
{
    rootEl = React.createRef();
    imageEditorInst = null;
    componentDidMount(){
        let boxWidth = window.outerWidth;
        let boxHeight = window.outerHeight;
        this.imageEditorInst = new ImageEditorCropper(this.rootEl.current,{
            includeUI: {
                locale: this.localFactory(),
                loadImage: {
                    path: this.props.image,
                    name: this.props.avatar.name
                },
                // menu: ["crop","flip","rotate","draw","shape","text"],
                menu: ["crop","draw","shape","text"],
                initMenu: '',
                uiSize: {width: '100%',height: '100%'},
                menuBarPosition: 'top'
            },
            cssMaxHeight: ((boxHeight > 680) ? 350 : 300),
            cssMaxWidth: ((boxWidth > 600) ? 550 : 320),
            selectionStyle: {cornerSize: 20,rotatingPointOffset: 70},
            usageStatistics: false
        });
    }
    componentWillUnmount(){
        this.imageEditorInst.destroy();
        this.imageEditorInst = null;
    }
    shouldComponentUpdate(nextProps){
        return false;
    }
    getInstance(){
        return this.imageEditorInst;
    }
    getRootElement(){
        return this.rootEl.current;
    }
    localFactory = () => {
        return {
            Apply: loadText.APPLY,
            Bold: loadText.BOLD,
            Cancel: loadText.CANCEL,
            Center: loadText.CENTER,
            Circle: loadText.CIRCLE,
            Color: loadText.COLOR,
            Crop: loadText.CROP,
            Custom: loadText.CUSTOM,
            Download: loadText.DOWNLOAD,
            Delete: loadText.DELETE,
            DeleteAll: loadText.DELETE_ALL,
            Draw: loadText.DRAW,
            Fill: loadText.FILL,
            Free: loadText.FREE,
            Hand: loadText.HAND,
            History: loadText.HISTORY,
            Italic: loadText.ITALIC,
            Left: loadText.LEFT,
            Load: loadText.LOAD,
            Range: loadText.RANGE,
            Rectangle: loadText.RECTANGLE,
            Redo: loadText.REDO,
            Reset: loadText.RESET,
            Right: loadText.RIGHT,
            Shape: loadText.SHAPE,
            Square: loadText.SQUARE,
            Straight: loadText.STRAIGHT,
            Stroke: loadText.STROKE,
            Triangle: loadText.TRIANGLE,
            Text: loadText.TEXT,
            "Text size": loadText.TEXT_SIZE,
            Underline: loadText.UNDERLINE,
            Undo: loadText.UNDO,
            ZoomIn: loadText.ZOOM_IN,
            ZoomOut: loadText.ZOOM_OUT
        }
    }
    handleClose = () => {
        this.props.changeHandler({type: "closed"});
    }
    handleCropImage = async() => {
        const modifiedImage = await this.getImageFromBinary(this.imageEditorInst.toDataURL({format: this.props.avatar.type.split("/")[1]}),this.props.avatar.name);
        this.props.changeHandler({type: "set",avatar: modifiedImage});
    }
    getImageFromBinary = async(imageSrc,fileName) => {
        if(!imageSrc){
            return;
        }
        var arr = imageSrc.split(",");
        var mime = arr[0].match(/:(.*?);/)[1];
        var bstr = Buffer.from(arr[1],'base64').toString('binary');
        var n = bstr.length;
        var u8arr = new Uint8Array(n);
        while(n--){
            u8arr[n] = bstr.charCodeAt(n);
        }
        return new File([u8arr],fileName,{type: mime});
    }
    render(){
        return (
            <ImageModalWrap>
                <div className="back"></div>
                <div className="inner">
                    <div className="header">
                        <span>IMAGE EDITOR</span>
                        <button className="crop" onClick={this.handleCropImage} type="button">SAVE</button>
                        <button onClick={this.handleClose} title="CLOSE" className="close">{crossIcon({width:24,height:24})}</button>
                    </div>
                    <div className="body">
                        <div ref={this.rootEl}/>
                    </div>
                </div>
            </ImageModalWrap>
        );
    }
}
1.0.1

8 months ago

1.0.0

8 months ago