canvas压缩、裁切图片和格式转换的方法

按照大小压缩图片,或者按照特定分辨率裁切图片,转为blob数据。自动处理ios中可能存在的照片偏差90°问题。

例如,获取300*300大小的头像,实现以下效果:

使用方式:

<!-- 引入js文件 -->
    <script type="text/javascript" src="./compressImage.js"></script>
<!-- input标签 -->
    <input type="file" id="avatar" name="avatar" accept="image/png, image/jpeg">

  

裁取特定分辨率的图片(如300*300):

    compressImage({
        input: document.getElementById(‘avatar‘),
        width: 300,
        height: 300,
        callback: function(blob, fileName) {
            // blob是处理之后的图片二进制数据
            // fileName是文件名,如"avatar.png"
            // ...
        }
    })

  

将图片压缩到指定大小,如500kb以下:

    compressImage({
        input: document.getElementById(‘avatar‘),
        size: 500,
        callback: function(blob, fileName) {
            // ...
        }
    })

  

指定图片名字和格式(允许jpg和png格式互转):

    compressImage({
        input: document.getElementById(‘avatar‘),
        size: 500,
        name: "user_avatar_1024687956"
        type: ‘png‘,
        callback: function(blob, fileName) {
            // 此处得到的fileName就是 user_avatar_1024687956.png
            // ...
        }
    })

  

callback是图片处理之后的回调函数,图片会转为blob数据数据,blob的用法参考:

    callback: function(blob, fileName) {
        var url = URL.createObjectURL(blob);

        /**** 通过<img>显示 ****/
        var img = document.createElement("img");
        img.src = url;
        document.body.append(img);

        /**** formData上传图片 ****/
        var formData = new FormData();
        formData.append("file", blob, fileName);
        $.ajax({
            url: ‘api/upload/img‘,
            type: ‘POST‘,
            data: formData,
            success: function(returndata) {
                console.log("上传成功")
                formData = null;
            }
        })

        /**** 下载图片 ****/
        var a = document.createElement(‘a‘);
        a.setAttribute(‘download‘, fileName);
        a.href = url;
        a.click();
    }

  

compressImage方法:

/**
 * compressImage.js
 * 参数config:{ input, callback, name, type, quality, size, width, height}
 * input: 必填,input[type=file]的表单元素,支持multiple多张图片
 * callback: 必填,处理之后的回调函数,参数(blob,fileName)
 * name: 非必填,自定义文件名,不包含后缀(如.jpg),默认原文件名
 * type: 非必填,图片格式,可选png/jpg,默认原图片格式
 * quality: 非必填,图片质量系数,默认0.92
 * 只传size: 压缩图片至size(单位kb)大小
 * 传width: 根据宽度压缩图片,高度自适应
 * 传height: 根据高度压缩图片,宽度自适应
 * 传width和height: 压缩图片,从中心位置裁取
 * 不传size/width/height: 只进行格式转换,不压缩图片
 * 同时传size和width/height: 会忽略size,根据width/height处理
 **/

function compressImage(config) {
    if (!config.input || !config.input.files || config.input.files.length == 0) {
        console.log("compressImage: 无图片文件")
        return;
    }
    if (!config.callback) {
        console.log("compressImage: 缺少回调函数")
        return;
    }
    if (config.type && config.type != "png" && config.type != "jpg") {
        console.log("compressImage: 图片格式指定错误,请选择png或jpg")
        return;
    }
    config.quality = (config.quality && config.quality > 0 && config.quality <= 1) ? config.quality : 0.92;
    for (var i = 0; i < config.input.files.length; i++) {
        HANDLE_SINGLE_IMAGE(config.input.files[i], config)
    }
}

function HANDLE_SINGLE_IMAGE(file, config) {
    var idx = file.name.lastIndexOf(".");
    var imageName = file.name.substring(0, idx);
    var imageType = file.name.substring(idx + 1, file.name.length).toLowerCase();
    if (imageType != "png" && imageType != "jpg" && imageType != "jpeg") {
        console.log("compressImage: 不支持的图片格式 - " + imageType)
    } else {

        // fileType: canvas.toBlob方法的参数
        config.fileType = (!!config.type ? ("image/" + config.type.replace("jpg", "jpeg")) : file.type);

        // type: 文件名中的格式后缀
        config.type = config.type || imageType.replace("jpeg", "jpg");

        // fileName: 完整的文件名,将在callback中返回
        config.fileName = (config.name ? (config.name + "." + config.type) : (imageName + "." + config.type));

        // ios下的jpg文件需要修正照片方向
        var isIOS = (/iphone|ipad|mac/).test(window.navigator.userAgent.toLowerCase());
        if (isIOS && file.type == "image/jpeg") {
            var reader = new FileReader();
            reader.readAsArrayBuffer(file);
            reader.onload = function() {
                var orientation = GET_ORIENTATION(this.result);
                alert(orientation)
                IMAGE_READER(file, config, orientation)
            }
        } else {
            IMAGE_READER(file, config)
        }
    }
}

function IMAGE_READER(file, config, orientation) {
    var reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = function() {
        var img = document.createElement("img");
        img.src = this.result;
        img.onload = function() {
            if(orientation==6 || orientation==8){
                var origin_width = parseInt(this.width);
                this.width = parseInt(this.height);
                this.height = origin_width;
            }else{
                this.width = parseInt(this.width);
                this.height = parseInt(this.height);
            }

            // 标记是否只按照size要求去压缩
            var bySize = false;

            // 缩放后图片的尺寸,canvas将从中裁切
            var imgWidth = 0;
            var imgHeight = 0;

            // 目标尺寸,即最后生成的图片尺寸
            var targetWidth = 0;
            var targetHeight = 0;

            // config有width/height时
            if (config.width && config.height) {
                targetWidth = config.width;
                targetHeight = config.height;
                var ratio_x = this.width / targetWidth;
                var ratio_y = this.height / targetHeight;
                if (ratio_x > ratio_y) {
                    imgWidth = this.width / ratio_y;
                    imgHeight = targetHeight;
                } else {
                    imgWidth = targetWidth;
                    imgHeight = this.height / ratio_x;
                }
            }
            if (config.width && !config.height) {
                imgWidth = targetWidth = config.width;
                imgHeight = targetHeight = targetWidth / (this.width / this.height);
            }
            if (!config.width && config.height) {
                imgHeight = targetHeight = config.height;
                imgWidth = targetWidth = (this.width / this.height) * targetHeight;
            }
            if (targetWidth == 0 && targetHeight == 0) {
                // config有size时,根据大小进行压缩
                if (config.size && config.size > 0 && file.size > config.size * 1024) {
                    bySize = true;
                    var ratio = Math.sqrt((config.size * 1024) / file.size).toFixed(2);
                    if (ratio < 0.5) {
                        ratio = 0.5;
                    }
                    imgWidth = targetWidth = parseInt(this.width * ratio);
                    imgHeight = targetHeight = parseInt(this.height * ratio);
                } else {
                    // 不压缩或者裁切,只将图片转为blob数据
                    imgWidth = targetWidth = this.width;
                    imgHeight = targetHeight = this.height;
                }
            } else {
                targetWidth = parseInt(targetWidth);
                targetHeight = parseInt(targetHeight);
            }
            var canvas = document.createElement(‘canvas‘);
            var ctx = canvas.getContext(‘2d‘);
            canvas.width = targetWidth;
            canvas.height = targetHeight;

            // 矫正旋转方向
            switch (orientation) {
                case 3:
                    ctx.rotate(180 * Math.PI / 180);
                    ctx.drawImage(this, (imgWidth-targetWidth)/2-imgWidth, (imgHeight-targetHeight)/2-imgHeight, imgWidth, imgHeight );
                    break;
                case 6:
                    ctx.rotate(90 * Math.PI / 180);
                    ctx.drawImage(this, (targetHeight-imgHeight)/2, (imgWidth-targetWidth)/2-imgWidth, imgHeight , imgWidth);
                    break;
                case 8:
                    ctx.rotate(270 * Math.PI / 180);
                    ctx.drawImage(this, (imgHeight-targetHeight)/2-imgHeight, (targetWidth-imgWidth)/2, imgHeight , imgWidth);
                    break;
                default:
                    ctx.drawImage(this, (targetWidth-imgWidth)/2, (targetHeight-imgHeight)/2, imgWidth, imgHeight);
            }

            canvas.toBlob(function(blob) {
                if (bySize && blob.size >= config.size * 1024) {
                    COMPRESS_BY_SIZE(blob, config, canvas, ctx)
                    return;
                }
                config.callback(blob, config.fileName)
            }, config.fileType, config.quality);
        }
    }
}

//将图片按0.9倍缩小至目标size
function COMPRESS_BY_SIZE(old_blob, config, canvas, ctx) {
    console.log("COMPRESS_BY_SIZE")
    config.quality = 0.98;
    var reader = new FileReader();
    reader.readAsDataURL(old_blob);
    reader.onload = function() {
        var img = document.createElement("img");
        img.src = this.result;
        img.onload = function() {
            width = parseInt(img.width * 0.9);
            height = parseInt(img.height * 0.9);
            canvas.width = width;
            canvas.height = height;
            ctx.drawImage(img, 0, 0, width, height);
            canvas.toBlob(function(blob) {
                if (blob.size >= config.size * 1024) {
                    COMPRESS_BY_SIZE(blob, config, canvas, ctx);
                    return;
                }
                config.callback(blob, config.fileName)
            }, config.fileType, config.quality);
        }
    }
}

/**
 * 获取iOS照片的旋转角度
 * 1-0° 3-180° 6-90° 8-270°
 **/
function GET_ORIENTATION(arrayBuffer) {
    var dataView = new DataView(arrayBuffer);
    var length = dataView.byteLength;
    var orientation = 0;
    var exifIDCode;
    var tiffOffset;
    var firstIFDOffset;
    var littleEndian;
    var endianness;
    var app1Start;
    var ifdStart;
    var offset;
    var i;
    if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) {
        offset = 2;
        while (offset < length) {
            if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) {
                app1Start = offset;
                break;
            }
            offset++;
        }
    }
    if (app1Start) {
        exifIDCode = app1Start + 4;
        tiffOffset = app1Start + 10;
        if (GET_CHARCODE_STRING(dataView, exifIDCode, 4) === ‘Exif‘) {
            endianness = dataView.getUint16(tiffOffset);
            littleEndian = endianness === 0x4949;
            if (littleEndian || endianness === 0x4D4D) {
                if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) {
                    firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
                    if (firstIFDOffset >= 0x00000008) {
                        ifdStart = tiffOffset + firstIFDOffset;
                    }
                }
            }
        }
    }
    if (ifdStart) {
        length = dataView.getUint16(ifdStart, littleEndian);
        for (i = 0; i < length; i++) {
            offset = ifdStart + i * 12 + 2;
            if (dataView.getUint16(offset, littleEndian) === 0x0112) {
                offset += 8;
                orientation = dataView.getUint16(offset, littleEndian);
                break;
            }
        }
    }
    return orientation;
}

function GET_CHARCODE_STRING(dataView, start, length) {
    var str = ‘‘;
    var i;
    for (i = start, length += start; i < length; i++) {
        str += String.fromCharCode(dataView.getUint8(i));
    }
    return str;
}

原文地址:https://www.cnblogs.com/yangshifu/p/12690130.html

时间: 2024-10-13 16:13:22

canvas压缩、裁切图片和格式转换的方法的相关文章

音乐格式怎么转换,音频格式转换的方法

今天所说的是教大家如何转换音频.音乐格式.在生活中我们会听到一些比较好听的歌曲,我们经常会将这些好听的歌曲给下载下来.然而有的时候我们会惊奇地发现某些音乐的格式很奇怪,是一些自己没有见过的音频格式,而且许多的播放器不支持播放,这个时候或许会让你们感到头疼,其实碰到这些比较少见的音频格式的时候我们完全没有必要头疼,将其转换成我们比较常见的mp3格式就行了,那么怎么进行转换呢?看看下面的教程吧. 音频转换器https://www.xunjieshipin.com/download-audioedit

【VC++技术杂谈007】使用GDI+进行图片格式转换

本文主要介绍如何使用GDI+对图片进行格式转换,可以转换的图片格式为bmp.jpg.png. 1.加载GDI+库 GDI+是GDI图形库的一个增强版本,提供了一系列Visual C++ API.为了使用GDI+,需要在工程中包含“GdiPlus.h”头文件,并加载“gdiplus.lib”库文件. 具体实现方法为,下载GDI+库,将下载得到的Gdiplus文件夹放到工程中.Gdiplus文件夹中应当包含有“GdiPlus.h”等一系列头文件.Gdiplus.lib库文件和Gdiplus.dll动

CANVAS运用-对图片的压缩上传(仅针对移动浏览器)

最近在移动端设计头像上传功能时,原本是以<input type="file">直接通过formData上传,然而实际使用情况是:对于过大的图片(高像素手机所拍摄的照片等)上传时间过长会导致上传失败,而每次都上传原始大小的图片(后台处理压缩)十分影响用户体验,所以研究了一下通过canvas压缩图片并上传的方法,以下是整理的一些思路和心得: 一.<input type="file">获取本地图片,并将图片绘制到画布中.此处的难点在于:由于浏览器的

megapix-image插件 使用Canvas压缩图片上传

<!DOCTYPE html > <html> <head> <title>通过Canvas及File API缩放并上传图片</title> <script src="/Scripts/Jquery/jquery-1.8.3.min.js" type="text/javascript"></script> <script src="/Scripts/MegaPixIm

开发利器_ImageMagick.基于Linux命令行的图片缩放/编辑/格式转换?

简单介绍: ImageMagick是一系列的用于修改,加工图像的命令行工具,能够快速地使用命令行对图片进行操作,对大量的图片进行批处理,它能执行相当多操作,本文涉及的只是开发中常用的技能. 快速安装: yum -y install epel-release yum install -y ImageMagick ImageMagick-devel 格式转换: convert 1.png 1.jpg 缩放图像: convert 1.jpg -resize 499x 1.jpg 说明: ImageMa

bmp,jpg,png,tif,wmf,emf与eps图片格式转换

wmf/emf是两种Microsoft Windows的图形文件格式.它是一个矢量图格式,但是也允许包含位图.本质上,一个WMF文件保存一系列可以用来重建图片的Windows GDI命令.在某种程度上,它类似于印刷业广泛使用的PostScript格式. 关于wmf2eps安装使用的问题可参考如下两个网页. http://www.kellogg.northwestern.edu/rc/miktex-install.htm http://www.wolf-s.homepage.t-online.de

对图片的统一格式转换处理

package com.eshore.rbss.commons; import java.awt.Graphics;import java.awt.Image;import java.awt.image.BufferedImage;import java.io.InputStream;import java.io.OutputStream; import javax.imageio.ImageIO; import org.apache.log4j.Logger; /** * 1.对图片时行格式转

canvas压缩图片

1.canvas.toDataUrl压缩图片 canvas的toDataUrl方法可以将内容导出为base64编码格式的图片,采用base64编码将比源文件大1/3,但是该方法可以指定导出图片质量,所以前端可实现上传图片的压缩.先通过fileApi拿到本地图片地址,然后新建一个Img元素,图片绘制到canvas中后再将其导出(压缩).例如: $(':file').on('change',function(){         var file = this.files[0];         v

.NET图片操作类,包含图片格式转换、图片缩放、 文字水印、图片水印、路径转换

using System;using System.Collections.Generic;using System.Text;using System.IO;using System.Drawing.Imaging;using System.Drawing;using System.Web;namespace ZC.Utils{  public  static class ImageHelper  { #region 图片格式转换      /// <summary>      /// 图片