博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用 JavaScript 根据用户照片和姓名生成海报
阅读量:7009 次
发布时间:2019-06-28

本文共 3929 字,大约阅读时间需要 13 分钟。

前言

最近在为公司的一个比赛制作专题页,碰到一个使用参赛者上传的照片生成专属海报的需求,实现过程中用到了一些以前没用过的 api,也踩了一些坑,于是将其记录下来。

需求描述

  1. 用户点击按钮进行照片上传

  2. 照片上传完成后,将照片进行裁剪,并和海报背景、姓名等组合得到海报

  3. 将生成的海报上传

效果大概如下:

海报背景:

图片描述

成品:

图片描述

实现过程

1、初始化 canvas

canvas#poster-canvas(width='960' height='1280')
function initCanvas() {  canvasCtx = document.getElementById("poster-canvas").getContext('2d');}

2、绘制海报背景

海报背景为预先提供的一张照片,将其设置到一个隐藏的 img 标签里面,并且预留一个 canvas 元素用于绘制海报:

img.poster-background(src='/assets/xxx/poster-background.jpeg')

页面加载完成后,将海报背景绘制到 canvas 内:

$('img.poster-background').on('load', function () {  var backgroundImg = $('img.poster-background')[0];  canvasCtx.drawImage(backgroundImg, 0, 0, 960, 1280);  renderName();});

海报背景绘制完成之后,需要将用户姓名绘制到特定位置。由于用户姓名长度不一,因此需要进行计算确定字体大小:

function renderName() {  var name = $('input[name="chName"]').val();  var fontSize;  if (name.length < 3) {    fontSize = 100;  } else {    fontSize = parseInt(320 / name.length);  }  canvasCtx.font = "bold " + fontSize + "px Courier New";  canvasCtx.fillStyle = "#de071b";  canvasCtx.fillText(name, 20, 1066);}

3、上传照片

使用 file 类型的 input 元素,因为页面上表现为点击按钮,因此使用经典的将 input 元素透明化并覆盖按钮的方法:

a.upload-btn   input#photo(type='file' name='photo' accept='image/jpeg, image/png')  | 上传自己的照片生成专属海报
.upload-btn input {  position: absolute;  left: 0;  top: 0;  opacity: 0;  width: 100%;  height: 68px;  cursor: pointer;}

然后监听 input 元素的 change 事件,然后使用 FormData API 构造表单数据,使用 ajax 进行异步上传,照片上传完成之后。得到一个地址,将这个地址设置到页面上预留的一个 img 标签里面:

$('#photo').on('change', function (e) {  var file = e.target.files[0];  var type = file.type;  if (type !== 'image/jpeg' && type !== 'image/png') {    window.toastr.error('请上传 jpg 或 png 格式的图片');  } else {    var formData = new FormData();    formData.append('avatar', file);    $.ajax({      type: 'POST',      url: '/upload_url',      data: formData,      contentType: false,      processData: false,      success: function(result) {        var avatarUrl = result.data.url;        $('img.avatar').attr('src', avatarUrl);      },      error: function(err) {              }    });  }});

4、绘制照片

海报中放置照片的区域为正方形,但是用户上传的照片却不一定,因此需要对照片进行裁剪,裁剪的原则为取照片中间部分。然后将裁剪参数传进 canvasdrawImage 方法,进行绘制:

$('img.avatar').on('load', function () {  var avatarImg = $('img.avatar')[0];  var originWidth = avatarImg.width;  var originHeight = avatarImg.height;  var newWidth, cutStartX, cutStartY;  if (originWidth < originHeight) {    newWidth = originWidth;    cutStartX = 0;    cutStartY = (originHeight - originWidth) / 2;  } else if (originWidth > originHeight) {    newWidth = originHeight;    cutStartX = (originWidth - originHeight) / 2;    cutStartY = 0;  } else {    newWidth = originWidth;    cutStartX = 0;    cutStartY = 0;  }    canvasCtx.drawImage(avatarImg, cutStartX, cutStartY, newWidth, newWidth, 0, 0, 960, 960);  uploadPoster();      });

前面绘制海报背景和这里绘制照片,调用的是同一个方法,只不过后者多传进去了裁剪参数。但是需要注意的是,裁剪参数是在绘制位置之前传进去的,而不是简单的补在后面:

canvasCtx.drawImage(backgroundImg, 0, 0, 960, 1280);canvasCtx.drawImage(avatarImg, cutStartX, cutStartY, newWidth, newWidth, 0, 0, 960, 960);

5、上传海报

依然使用 FormData API,因此需要先用 canvas 构造一个 Blob 对象。新版本的 Chrome 和 Firefox 支持 canvastoBlob 方法,可以直接使用:

document.getElementById("poster-canvas").toBlob(function (blob) {});

其它浏览器里,可以先用 toDataURL方法得到 base64 格式的图片数据,再转为 Blob

var blob = dataURLtoBlob(document.getElementById("poster-canvas").toDataURL());function dataURLtoBlob(dataurl) {  if (dataurl.indexOf('base64') < 0) {    dataurl = 'data:image/jpeg;base64,' + dataurl;  }  var arr = dataurl.split(',');  var mime = arr[0].match(/:(.*?);/)[1];  var bstr = atob(arr[1]);  var n = bstr.length;  var u8arr = new Uint8Array(n);  while (n --) {    u8arr[n] = bstr.charCodeAt(n);  }  return new Blob([u8arr], {type: mime});}

然后进行上传,步骤和前面上传照片一致:

var formData = new FormData();formData.append('poster', blob);$.ajax({  type: 'POST',  url: '/upload_poster_url',  data: formdata,  contentType: false,  processData: false,  success: function(result) {      },  error: function(err) {      }});

至此,整个流程完结。

转载地址:http://hcntl.baihongyu.com/

你可能感兴趣的文章
【入门教程】SequoiaDB+Postgresql数据实时检索最佳实践
查看>>
在CentOS/RHEL 6.5上安装Chromium
查看>>
十个你可能没用过的Linux命令
查看>>
为extjs的TabPanel 添加右键关闭效果(修改一个bug)
查看>>
java中传递基础数据类型值与传递数组引用变量给方法的不同之处
查看>>
监控io性能,free命令,ps网络命令,查看网络状态,Linux下抓包
查看>>
@ResponseBody注解的使用
查看>>
在IDEA中实战Git
查看>>
前后端分离后的前端时代
查看>>
一名大学女生的来信
查看>>
任正非:对成功视而不见 成功才能始终伴随华为
查看>>
hibernate 分页
查看>>
springboot配置文件的所有属性
查看>>
华为checkstyle文件
查看>>
iphone开发教程
查看>>
Java编程思想学习录(连载之:内部类)
查看>>
mysql 密码忘记了
查看>>
一个不错的代码共享站
查看>>
我的友情链接
查看>>
我的友情链接
查看>>