在触屏设备上面利用html5裁剪图片[通俗易懂]

在触屏设备上面利用html5裁剪图片

大家好,又见面了,我是全栈君。

前言

如今触屏设备越来越流行,并且大多数已经支持html5了。针对此。对触屏设备开发图片裁剪功能,

让其能够直接处理图片。减轻服务端压力。

技术点

浏览器必须支持html5,包含fileReader。canvas等api,而且该设备至少支持单点触事件(touchstart,touchmove,touchend),可惜的是

非常多浏览器仅仅能识别一仅仅手指(不支持多点触摸事件,假如支持的话,请告知我)。

思路

利用filereader直接读取本地图片。然后赋予一个图片。该图片及裁剪框的位置计算跟pc端一样,可是触发的事件不一样,触屏版是依据触屏事件触发的。裁剪时,利用cavas的api直接画出相关图像,然后得到数据。再利用xmlhttprequest发送请求。

非html5无法完毕这个过程。

执行结果

这仅仅是一个demo,也是最初的雏形,当然不会太好看了,可是基本实现功能就可以。

在触屏设备上面利用html5裁剪图片[通俗易懂]


部分代码


<!doctype html>
<html>

<head>
    <meta name="Author" content="flashlizi - www.riaidea.com">
    <meta name="Description" content="HTML5 experiment">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>头像上传组件 - HTML5版</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />

    <style>
        body
        {
            padding: 0;
            margin: 0;
            height: 100%;
            background-color: #eee;
            font-size: 12px;
            color: #666;
        }

        a
        {
            text-decoration: none;
            color: #333;
        }

        a:hover
        {
            text-decoration: none;
            color: #f00;
        }


    </style>
    <script>

        if(window.FileReader==undefined){
            alert("该手机不支持html5");
        }

    </script>

    <script type="text/javascript" src="/static/mobile/lib/zepto.min.js"></script>
</head>

<body >
<h1>选择图片:<input type="file" id="browseFile" onchange=""><input type="button" id="saveimg" value="保存图片"/></h1>
<div id="wrapper" style="border: 1px gray dotted; padding: 25px;">

    <div id="component_box" style="position: relative; border: 1px green solid; width: 300px; height: 300px;">
        <div id="tipBox" style="display: none;">
            <img src=""/>
        </div>
        <div id="mainCutter" style="overflow: hidden; display: none; position: relative;">
            <img id="imgPreview" />
            <div id="cutBox" style=" position:absolute; width: 150px; height: 200px; opacity: 0.5; background: gray;"></div>
        </div>
    </div>

    <!--画布-->

    <canvas id="cropper" style=" display:none;border:1px solid red; width: 300px; height: 300px;" ></canvas>
</div>
<div><span style="color: green;">调整裁剪区域大小:</span>
    <!--调整用slider-->
    <div><div id="processBar" style=" margin: 0 auto; position: relative; width: 220px; height: 20px; background: green;"><div id="processPoint" style="background: url(images/horizSlider.png); width: 18px; height: 20px; position: absolute;left: 0;top: 0;"></div></div></div>
</div>
<div id="the_show" style="display: none;">
    <h2>提示:</h2>
    <div id="theTips"></div>

    <h2>后台获得的图像</h2>
    <img src="" id="showImg"/>
</div>
<div style="color: green;">友情提醒:拖动裁剪框裁剪框将随之移动,上划放大裁剪框,下滑缩小裁剪框。</div>
<div id="tips2" style="color: green; position: absolute;left: 0px; bottom: 0px; border: 1px solid green;"></div>


<script type="text/javascript">
//--逻辑。点击图片上传选择后将载入预览图片
var Options={
    width:300,
    height:300,
    cutWidth:150,
    cutHeight:200,
    cutMinSize:50,//裁剪框最小尺寸,即最小能够缩放到这个size,width及height随意一个都无法小于这个值。

    //--系统自带。执行时自己主动运算,请不要改动。

cropViewWidth:0,//在画布里面显示的最大宽度 cropViewHeight:0,//在画布里面显示的最大高度 cropLeft:0, cropTop:0, //--裁剪框 cutViewWidth:0, //当前宽度, cutViewHeight:0,//当前高度 cutMaxWidth:0, //裁剪框最大宽度。 cutMaxHeight:0,//裁剪框最大高度。

//--四象限。用于推断距离。 cutBoxLimitX1:0, cutBoxLimitX2:0, cutBoxLimitY1:0, cutBoxLimitY2:0, cutLeft:0,//裁剪框绝对定位,左側距离。

cutTop:0,//裁剪框绝对定位。离顶部距离。

initStatus:false//当前组件是否已经初始化了。};var Options_image={ width:0, height:0, imgData:""} var input_browseFile = document.getElementById("browseFile"); var img_preview = document.getElementById("imgPreview"); var cutBox=document.getElementById("cutBox"); var tipBox=document.getElementById("tipBox"); var _cropper=document.getElementById("cropper"); var mainCutter=document.getElementById("mainCutter"); var tips2=$("#tips2"); var wrapper=document.getElementById("wrapper"); var component_box=document.getElementById("component_box"); var ctx = _cropper.getContext('2d');//ctx.drawImage(myImage, 50, 50);function previewInImage (file) { //通过file.size能够取得图片大小 var reader = new FileReader(); LoadingImage(); reader.onload = function( evt ){ img_preview.src = evt.target.result; } Options_image.imgData= reader.readAsDataURL(file); }img_preview.onload=function(){ Options_image.width=img_preview.width; Options_image.height=img_preview.height; _initCropAndCut();}function LoadingImage(){ $(img_preview).css({"width":"","height":""});}function _initCropAndCut(){ //--计算比例。将其放到canvas里面。 var scale = Math.max(Options_image.width/Options.width,Options_image.height/Options.height); if(scale>1){ Options.cropViewWidth=parseInt(Math.floor(Options_image.width/scale)); Options.cropViewHeight=parseInt(Math.floor(Options_image.height/scale)); } else{ Options.cropViewWidth=Options_image.width; Options.cropViewHeight=Options_image.height; } //--计算画布里面的图像的位置。 Options.cropLeft=parseInt((Options.width-Options.cropViewWidth)/2); Options.cropTop=parseInt((Options.height-Options.cropViewHeight)/2); //--计算裁剪框实际大小及实际位置。 //计算裁剪框的位置。 var scale_2=Math.max(Options.cutWidth/Options.cropViewWidth,Options.cutHeight/Options.cropViewHeight); if(scale_2>1){ Options.cutViewWidth=parseInt(Math.floor(Options.cutWidth/scale_2)); Options.cutViewHeight=parseInt(Math.floor(Options.cutHeight/scale_2)); } else{ Options.cutViewHeight=Options.cutHeight; Options.cutViewWidth=Options.cutWidth; } Options.cutMaxWidth=Options.cutViewWidth; Options.cutMaxHeight=Options.cutViewHeight; Options.cutLeft=parseInt(Math.floor((Options.cropViewWidth-Options.cutViewWidth))/2); Options.cutTop=parseInt(Math.floor((Options.cropViewHeight-Options.cutViewHeight))/2); //-四象限。 Options.cutBoxLimitX1=0; Options.cutBoxLimitX2=Options.cropViewWidth; Options.cutBoxLimitY1=0; Options.cutBoxLimitY2=Options.cropViewHeight; $(cutBox).css({"display":"block","width":Options.cutViewWidth+"px","height":Options.cutViewHeight+"px","left":Options.cutLeft+"px","top":Options.cutTop+"px"}); $(img_preview).css({"width":Options.cropViewWidth+"px","height":Options.cropViewHeight+"px"}); $(mainCutter).css({"display":"block","width":Options.cropViewWidth+"px","height":Options.cropViewHeight+"px","left":Options.cropLeft+"px","top":Options.cropTop+"px"}); //ctx.drawImage(img_preview,Options.cropLeft,Options.cropTop,Options.cropViewWidth,Options.cropViewHeight); //ctx.drawImage(img_preview, 0, 0, Options_image.width,Options_image.height, Options.cropLeft, Options.cropTop, Options.cropViewWidth, Options.cropViewHeight ); Options.initStatus=true; Options_process.initStatus=true; Options_process.percent=100; Options_process.pointX=Options_process.barWidth; _resizeProcessBar();} input_browseFile.addEventListener("change", function () { //通过 this.files 取到 FileList ,这里仅仅有一个 previewInImage(this.files[0]); }, false); //--加入缩放功能。

Options_zoom={ beginX1:0, beginY1:0, beginX2:0, beginY2:0, endX1:0, endY1:0, endX2:0, endY2:0 };//--加入裁剪框移动功能Options_move={ beginX1:0, beginY1:0, endX1:0, endY1:0};/** * 拖动裁剪框的逻辑处理。 * */cutBox.addEventListener("touchstart",function(event){ event.preventDefault(); event.stopPropagation(); Options_move={ beginX1:0, beginY1:0, endX1:0, endY1:0 }; var beginX=event.changedTouches[0].pageX; var beginY=event.changedTouches[0].pageY; Options_move.beginX1=beginX; Options_move.beginY1=beginY;},false);cutBox.addEventListener("touchmove",function(event){ event.preventDefault(); event.stopPropagation(); //-- var beginX=event.changedTouches[0].pageX; var beginY=event.changedTouches[0].pageY; Options_move.endX1=beginX; Options_move.endY1=beginY; //--计算是否发生位移,依据位移来定位裁剪框位置。

//位移量。 var _d_x=Options_move.endX1-Options_move.beginX1; var _d_y=Options_move.endY1-Options_move.beginY1; //--当前裁剪框原始位置。

var _new_x=Options.cutLeft; var _new_y=Options.cutTop; _new_x+=_d_x; _new_y+=_d_y; //--推断是否在矩形边框,假如超出去,那么就取终于点。 //--注意,推断相关点的范围。 if(_new_x<Options.cutBoxLimitX1){ _new_x=Options.cutBoxLimitX1; } else if(_new_x>Options.cutBoxLimitX2){ _new_x=Options.cutBoxLimitX2; } //--顺便推断。加上宽度后,是否超过了范围。

if((_new_x+Options.cutViewWidth)>Options.cutBoxLimitX2){ _new_x=Options.cutBoxLimitX2-Options.cutViewWidth; } if(_new_y<Options.cutBoxLimitY1){ _new_y=Options.cutBoxLimitY1; } else if(_new_y>Options.cutBoxLimitY2){ _new_y=Options.cutBoxLimitY2; } //--顺便推断,加上裁剪框高度后,是否超过下限。 if((_new_y+Options.cutViewHeight)>Options.cutBoxLimitY2){ _new_y=Options.cutBoxLimitY2-Options.cutViewHeight; } Options.cutLeft=_new_x; Options.cutTop=_new_y; _resizeCutBox(); //---将这一点的放回前一点。 Options_move.beginX1=Options_move.endX1; Options_move.beginY1=Options_move.endY1;},false);cutBox.addEventListener("touchend",function(event){ event.preventDefault(); event.stopPropagation(); return;},false); /** * 依据相关參数又一次resize裁剪框 * */function _resizeCutBox(){ $(cutBox).css({"width":Options.cutViewWidth+"px","height":Options.cutViewHeight+"px","left":Options.cutLeft+"px","top":Options.cutTop+"px"});}function _getCutImageData(){ var output = document.createElement("canvas"); //--坐标换算。 var scale_x=Options_image.width/Options.cropViewWidth; var scale_y=Options_image.height/Options.cropViewHeight; var _o_x=parseInt( (scale_x)*Options.cutLeft); var _o_y=parseInt( (scale_y)*Options.cutTop); //--长度换算 var _o_width=parseInt(scale_x*Options.cutViewWidth); var _o_height=parseInt(scale_y*Options.cutViewHeight); output.width = Options.cutWidth; output.height = Options.cutHeight; output.getContext("2d").drawImage(img_preview, _o_x,_o_y, _o_width, _o_height, 0, 0, output.width, output.height); return output.toDataURL("image/jpeg");}function saveImage(){ var imgData = _getCutImageData(); /* $("#the_show").css("display","block"); document.getElementById("showImg").src=imgData; return; */ var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(e) { if(xhr.readyState == 4) { if(xhr.status == 200) { //--获取返回的数据。 var _res=xhr.responseText; _res= $.trim(_res); var json= $.parseJSON(_res); if(json.status==true){ $("#the_show").css("display","block"); var surl=json.url+"?t="+Math.random(); $("#showImg").attr("src",surl); } else{ alert(json.message); } //document.getElementById("status").innerHTML = "<font color='#f00'>上传成功!</font>"; } else{ alert("服务端无法响应,错误编号:"+xhr.status); } } }; xhr.open("post", "/quickTest/html5CropperHandler.jsp", true); var data = new FormData(); data.append("username", "flashlizi"); data.append("size", 180); data.append("file", imgData); xhr.send(data);}/** * processBar 进度条相关操作。 * */Options_process={ beginX:0,//触摸时候起始点 beginY:0,//触摸时候起始点 endX:0,//触摸时候终点 endY:0,//触摸时候终点 barWidth:200,//进度条长度 pointX:0,//当前指示点位置 pointY:0, percent:0,//百分比值。 initStatus:false};var processBar=document.getElementById("processBar");var processPoint=document.getElementById("processPoint");//--加入触屏事件,监控相关动作。//開始触摸processBar.addEventListener("touchstart",function(event){ event.preventDefault(); event.stopPropagation(); if(!Options_process.initStatus){ return; } var beginX=event.changedTouches[0].pageX; var beginY=event.changedTouches[0].pageY; Options_process.beginX=beginX; Options_process.beginY=beginY;},false) ;//--移动中processBar.addEventListener("touchmove",function(event){ event.preventDefault(); event.stopPropagation(); if(!Options_process.initStatus){ return; } var beginX=event.changedTouches[0].pageX; var beginY=event.changedTouches[0].pageY; Options_process.endX=beginX; Options_process.endY=beginY; //--计算比分比。

var _d_x=Options_process.endX-Options_process.beginX; Options_process.percent+=parseInt(_d_x*100/Options_process.barWidth); if(Options_process.percent<0){ Options_process.percent=0; } else if(Options_process.percent>100){ Options_process.percent=100; } //--计算那个指示点位置。

Options_process.pointX=parseInt(Options_process.barWidth*(Options_process.percent/100)); _resizeProcessBar(); //--依据百分比,设置裁剪框大小。 var _o_cut_x=Options.cutLeft; var _o_cut_y=Options.cutTop; var _o_cut_width=Options.cutViewWidth; var _new_cut_width= parseInt(Options.cutMaxWidth*(Options_process.percent/100)); var _new_cut_height= parseInt(Options.cutMaxHeight*(Options_process.percent/100)); if(_new_cut_width>_o_cut_width){ //--扩大了。 //--计算当前坐标 var _d_x_2=_new_cut_width-Options.cutViewWidth; var _d_y_2=_new_cut_height-Options.cutViewHeight; Options.cutLeft=Options.cutLeft-parseInt(_d_x_2/2); Options.cutTop=Options.cutTop-parseInt(_d_y_2/2); Options.cutViewWidth=_new_cut_width; Options.cutViewHeight=_new_cut_height; _resizeCutBox(); } else if(_new_cut_width<_o_cut_width){ //--缩小了。

var _d_x_2=Options.cutViewWidth-_new_cut_width; var _d_y_2=Options.cutViewHeight-_new_cut_height; Options.cutLeft=Options.cutLeft+parseInt(_d_x_2/2); Options.cutTop=Options.cutTop+parseInt(_d_y_2/2); Options.cutViewWidth=_new_cut_width; Options.cutViewHeight=_new_cut_height; _resizeCutBox(); } //--兴许处理。 Options_process.beginX=Options_process.endX; Options_process.endY=Options_process.endY;},false) ;//--结束processBar.addEventListener("touchend",function(event){ event.preventDefault(); event.stopPropagation(); if(!Options_process.initStatus){ return; }},false) ;/** * 依据相关属性。重设slider位置。 * */function _resizeProcessBar(){ $(processPoint).css("left",Options_process.pointX+"px");} $("#saveimg").click(function(){ if(Options.initStatus==false){ alert("请先选择图片!"); return; } saveImage();});</script></body></html>


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/115254.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 解决keil注册机和编译错误的问题2020-12-28

    解决keil注册机和编译错误的问题2020-12-28https://72k.us/file804/10165491-428107594这个地址的注册机验证可以有效到2032年。当以前的代码可以编译通过,但是新安装的keil确有大量的编译错误的时候。这个时候可能的原因是配置上没有设置C99Mode。勾选C99Mode是解决这个问题的手段之一。…

    2022年5月2日
    46
  • 电脑蓝屏0x000000f4解决步骤_0x000000c4开机就蓝屏

    电脑蓝屏0x000000f4解决步骤_0x000000c4开机就蓝屏电脑蓝屏的问题是大家最常见到的电脑问题之一,大多时候蓝屏故障的出现都和软件有关,少数为硬件不兼容或者故障导致。这里粗略的分析下STOP:0x000000F4字段的问题,仅做参考!以下先来看看网友是怎么分析与解决问题的吧!蓝屏代码0x000000f4原因分析:知道了原因,那么就下手解决类似问题就轻松了。1.先从软处着手,如运行莫软件导致错误,建议重装该软件,一般均可解决。2.考虑是否有其它软件同时运行导致冲突的或者主机配置内存过小导致内存溢出或者耗竭的(如采用XP系统建议配置512MB内存以上或.

    2022年10月8日
    1
  • 趣味编程游戏_全脑开发训练100个游戏

    趣味编程游戏_全脑开发训练100个游戏在信息技术迅猛发展的时代,操纵计算机,与电脑对话的能力已经成了事实上的技能标配,也已经深深地融入了我们每个人的生活当中。游戏行业也不例外,近几年,随着全民编程的热潮,许多游戏厂商也纷纷把编程融入自己的游戏当中,甚至推出了许多专门为编程爱好者/编程学习者制作的编程解密游戏。今天要推荐的九个游戏,可谓风格各异,老少咸宜,不论你是对编程完全陌生的新手,还是硬核老鸟,一定能找到一款适合你的游戏。话…

    2022年4月19日
    97
  • 注册表 ControlSet001、ControlSet002以及CurrentControlSet

    注册表 ControlSet001、ControlSet002以及CurrentControlSet

    2022年1月8日
    110
  • 异步fifo的10个测试关注点_异步FIFO

    异步fifo的10个测试关注点_异步FIFO1、异步FIFO简介及其原理FIFO是英文FirstInFirstOut的缩写,是一种先进先出的数据缓存器,它与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据。异步FIFO是指读写时钟不一致,读写时钟是互相独立的。1.1用途用途1:  跨时钟域:异步FIFO读写分别采用相互异步的不同时钟。在现代集成电路芯片中,随着设计规模的不断扩大,一个系统中往往含有数个时钟,多时钟域带来的一个问题就是,如何设计异步时钟之间的接口电路。异步FIFO是这个问题的一

    2022年8月13日
    6
  • verilog调用vhdl模块_verilog和vhdl哪个更好

    verilog调用vhdl模块_verilog和vhdl哪个更好初学FPGA,记录一些个人的探索历程和心得。本文的初衷是为了验证VHDL和Verilog文件互相调用功能。以一个简单的二选一选择器为例,分别用两种方法实现功能。一、用Verilog文件调用VHDL以Verilog文件为顶层文件,调用VHDL模块,testbench为Verilog文件。1、新建project2、编写.vhd文件,FPGA_VHDL.vhd,文件名与模块名称一致;3、编写FPGA_Verilog.v文件,文件名与模块名称一致,且设为top文件。4、编写testbench文件

    2022年9月21日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号