File API文件操做之FileReader二

上一篇說了FileAPI中FileReader的readAsText,這裏繼續上文,說說另一個API readAsDataURL。html

這個接口是將File或者Blob讀成base64格式的字符串,而後直接掛在HTML5的元素上,例如img就能夠直接使用。html5

實際用途能夠是圖片預覽和圖片剪裁,這裏我將用來實現圖片剪裁。git

思路:github

1. file api的FileReader實現本地圖片預覽  web

2. 用web api的拖拽功能來實現剪裁canvas

 

效果:api

  

那麼話很少說:瀏覽器

html代碼:app

<html>

<head>
    <title>FileReader 之 readAsDataURL</title>
</head>

<body style="margin: 2em 4em"  draggable="false">
    <div>圖片剪裁</div>
    <input type="file" id="fileImageCut" value="選擇圖片"><br/>
    <div  draggable="false" id="imgWrapper" id="container1" style="display: inline-block;width: 500px">
        <div style="width: 404px;height: 404px;border:1px solid cornflowerblue;position: relative">
            <img draggable="false" style="position: absolute;left:-1px;bottom:-1px; border:1px solid greenyellow " id="imgPreview" />
            <div draggable="true" id="cutter" style="position: absolute;cursor:crosshair;left:-px;bottom:-2px; width:300px; height: 300px; border: 2px dotted sienna"></div>
        </div>
    </div>
    <div style="display: inline-block;width: 200px;height:200px;vertical-align:buttom;border: 1px solid cadetblue;overflow: hidden;position:relative">
        <img  draggable="false" style="width:266.7px;height:266.7px;position: absolute;left: 0;bottom: 0" id="imgResult">
    </div>
    <!--<div draggable="true" id="cutter" style="position: absolute;cursor:crosshair;left:62px;top:274px; width:200px; height: 200px; border: 2px dotted sienna"></div> -->
</body>
<script src="./js/readAsDataURL.js"></script>

</html>

 js代碼:ssh

const IMAGE_MAX_SIZE = 2
const CUTTER_WIDTH = CUTTER_HEIGHT = 300

class SimpleImageCutter {
    constructor(options) {
        this.fileUpload = options.fileUpload
        this.imgPreview = options.imgPreview
        this.imgResult = options.imgResult
        this.cutter = options.cutter

        this.percentage = this.imgResult.parentElement.clientWidth / this.cutter.clientWidth
        this.iLeft = this.iRight = this.iTop = this.iBottom = null
    }

    init() {
        this.resgiterEvents()
    }

    resgiterEvents() {
        let cLeft, cRight, cTop, cBottom, cOffsetX, cOffsetY,
            cutter = this.cutter, imgPreview = this.imgPreview, cBorderWidth = Number.parseInt(cutter.style.borderWidth.replace('px', '')),
            cPBorderWidth = Number.parseInt(imgPreview.style.borderWidth.replace('px', ''))

        this.fileUpload.addEventListener('change', (ev) => {
            let files = ev.target.files, file;
            //檢查圖片類型
            if (files.length && (file = files[0])) {
                if (!this.checkFile(file)) {
                    return
                }
                //重置高寬
                imgPreview.removeAttribute('height')
                imgPreview.removeAttribute('width')
                imgPreview.style.width = imgPreview.style.height = null
                imgPreview.style.visibility = 'hidden'
                let fr = new FileReader()
                fr.onload = () => {
                    imgPreview.onload = () => {
                        this.resizeImage()
                        imgPreview.style.visibility = 'visible'
                        this.resizeCutter()
                        this.refreshPercentage()
                        this.resizeResult()
                        //計算圖片相對瀏覽器的限值
                        this.iLeft = imgPreview.getBoundingClientRect().left + document.documentElement.scrollLeft + cPBorderWidth
                        this.iTop = imgPreview.getBoundingClientRect().top + document.documentElement.scrollTop + cPBorderWidth
                        this.iRight = this.iLeft + imgPreview.clientWidth
                        this.iBottom = this.iTop + imgPreview.clientHeight
                    }
                    this.imgResult.src = imgPreview.src = fr.result
                }
                //若是錯誤,拋出異常
                fr.onerror = ev => alert(ev.target.error)                
                fr.readAsDataURL(file)
            }
        }, false)

        cutter.addEventListener('dragstart', ev => {
            cOffsetX = ev.offsetX
            cOffsetY = ev.offsetY
            /*
            let dragIcon = document.createElement("img") 
            dragIcon.src = 'image/drag.jpg'
            dragIcon.width = cutter.width  
            document.body.appendChild(dragIcon) 
            ev.dataTransfer.setDragImage(dragIcon, 0, 0); */
            //cutter.style.border = "2px red solid"   
            console.log('dragstart')
            return false
        }, false)

        cutter.addEventListener('dragover', ev => {
            //ev.stopPropagation()
            //ev.preventDefault()
            console.log('dragover')
            return false
        }, false)

        cutter.addEventListener('dragleave', ev => {
            //ev.stopPropagation()
            //ev.preventDefault()
            console.log('dragleave')
            return false
        }, false)

        cutter.addEventListener('drop', ev => {
            console.log('drop')
        }, false)

        cutter.addEventListener('dragend', ev => {
            cLeft = ev.clientX - cOffsetX - cBorderWidth
            cTop = ev.clientY - cOffsetY - cBorderWidth
            cRight = cLeft + cutter.clientWidth + cBorderWidth
            cBottom = cTop + cutter.clientHeight + cBorderWidth

            if (!this.iTop || cTop < this.iTop || cLeft < this.iLeft || cRight > this.iRight || cBottom > this.iBottom) {
                ev.stopPropagation()
                ev.preventDefault()
            } else {
                cutter.style.left = (cLeft - this.iLeft) + 'px'
                cutter.style.top =  (cTop - this.iTop) + 'px'
                imgResult.style.left = -((cLeft - this.iLeft) * this.percentage).toFixed(2) + 'px'
                imgResult.style.top = -((cTop - this.iTop) * this.percentage).toFixed(2) + 'px'
            }
        }, false)
    }

    checkFile(file) {
        if (!file.type.startsWith("image")) {
            alert('不是有效的圖片')
            return false
        }
        if (file.size > IMAGE_MAX_SIZE * 1024 * 1024) {
            alert(`上傳的圖片不容許大於${IMAGE_MAX_SIZE}M`)
            return false
        }
        return true
    }

    resizeImage() {
        let img = this.imgPreview, h = img.height, w = img.width,
            ph = img.parentElement.clientHeight, pw = img.parentElement.clientWidth,
            phc = h / ph, pwc = w / pw
        phc > pwc ? img.height = ph : img.width = pw
    }

    resizeCutter() {
        let minValue = Math.min(Math.min(imgPreview.clientHeight, CUTTER_HEIGHT), Math.min(imgPreview.clientWidth, CUTTER_WIDTH))
        cutter.style.height = cutter.style.width = minValue + 'px'
        cutter.style.top = cutter.style.left = null
    }

    resizeResult() {
        imgResult.style.width = (imgPreview.clientWidth * this.percentage).toFixed(2) + 'px'
        imgResult.style.height = (imgPreview.clientHeight * this.percentage).toFixed(2) + 'px'
        imgResult.style.top = imgResult.style.left = null
    }

    refreshPercentage() {
        this.percentage = this.imgResult.parentElement.clientWidth / this.cutter.clientWidth
    }
}

(new SimpleImageCutter({
    fileUpload: fileImageCut,
    imgPreview: imgPreview,
    imgResult: imgResult,
    cutter: cutter
})).init()

 

這種簡單實現存在的問題(下一種思路 html5 canvas):

1. 拖動效果體驗比較差

2. 剪裁後的圖片保存問題

源碼路徑:https://github.com/xiangwenhu/BlogCodes

相關文章
相關標籤/搜索