zoukankan      html  css  js  c++  java
  • File API文件操作之FileReader二

    上一篇说了FileAPI中FileReader的readAsText,这里继续上文,说说另外一个API readAsDataURL。

    这个接口是将File或者Blob读成base64格式的字符串,然后直接挂在HTML5的元素上,例如img就可以直接使用。

    实际用途可以是图片预览和图片剪裁,这里我将用来实现图片剪裁。

    思路:

    1. file api的FileReader实现本地图片预览  

    2. 用web api的拖拽功能来实现剪裁

    效果:

      

    那么话不多说:

    html代码:

    <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; 500px">
            <div style=" 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; 300px; height: 300px; border: 2px dotted sienna"></div>
            </div>
        </div>
        <div style="display: inline-block; 200px;height:200px;vertical-align:buttom;border: 1px solid cadetblue;overflow: hidden;position:relative">
            <img  draggable="false" style="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; 200px; height: 200px; border: 2px dotted sienna"></div> -->
    </body>
    <script src="./js/readAsDataURL.js"></script>
    
    </html>

     js代码:

    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

  • 相关阅读:
    1014 Waiting in Line (30)(30 point(s))
    1013 Battle Over Cities (25)(25 point(s))
    1012 The Best Rank (25)(25 point(s))
    1011 World Cup Betting (20)(20 point(s))
    1010 Radix (25)(25 point(s))
    1009 Product of Polynomials (25)(25 point(s))
    1008 Elevator (20)(20 point(s))
    1007 Maximum Subsequence Sum (25)(25 point(s))
    1006 Sign In and Sign Out (25)(25 point(s))
    1005 Spell It Right (20)(20 point(s))
  • 原文地址:https://www.cnblogs.com/cloud-/p/6478045.html
Copyright © 2011-2022 走看看