傻吊表情包加文字功能(canvas+node)

灵感来自微博@bangbang93

大佬写了个记仇生成器,作为表情包大王的我不禁想学习一番。

然而菜鸡如我,写的还是有些不尽如人意,比如canvas图片跨域问题还是没有解决明白,图片大的话保存速度会很慢,代码有些地方略显冗余等。希望有大佬指教一下。可怜


<html>
<head>
<title>文件上传 </title>
<style>
#bigImg{
width: 300px;
height: 239.31px;
}
#write{
width: 300px;
border: none;
overflow-y: visible;
font-size: 15px;
margin-top: 10px;
}
#canvas{
width: 300px;
height: 300px;
display: none;
}
#form{
display: none;
}
#sub{
margin-top: 20px;
}
< /style>
</head>
<body>
<div id= "container" >
</div>
<script>
var jc = new jichou({
container: "container", //容器
initImg: "", //初始图片,不能跨域
initText: "", //初始文字,没有默认“请输入”
method: "/upload", //提交位置
canvasWidth: 300,
canvasHeight: 300,
canvasFont: "normal normal normal 15px Microsoft YaHei UI",
fontSize: 12,
lineHeight: 20
})
//构造函数
function jichou( jcObject){
let that = this;
//默认文字
if(! jcObject. initText){
jcObject. initText = "请输入"
}
//获取id
this. getId= function( id){
return document. getElementById( id)
}
//填充内容
var innerHTML = "<img id = 'bigImg' src="+ jcObject. initImg+ "><br />";
innerHTML += "<div id='write' contenteditable='true'/>"+ jcObject. initText+ "</div>";
innerHTML += "<form action="+ jcObject. method+ " method='post' enctype='multipart/form-data' id = 'form'>";
innerHTML += "<input type='file' name='image' id='image'>";
innerHTML += "<br />";
innerHTML += "<input type='hidden' name='base' id='base'>";
innerHTML += "</form>";
innerHTML += "<input type='button' value='保存' id='sub' />";
innerHTML += "<br/>";
innerHTML += "<canvas id='canvas' width='"+ jcObject. canvasWidth+ "' height='"+ jcObject. canvasHeight+ "'>";
innerHTML += "</canvas>";
this. getId( jcObject. container). innerHTML = innerHTML;
//上传文件的input
var image = this. getId( 'image');
//显示文件的img
var bigImg = this. getId( 'bigImg');
//显示文字的div
var write = this. getId( 'write');
//表单
var form = this. getId( 'form');
//保存base64的input
var base = this. getId( 'base');
//画布
var canvas = this. getId( 'canvas');
var context = canvas. getContext( '2d');
//填充颜色
this. drawCanvas = function( canvas, left, top, width, height, color)
{
context. fillStyle= color;
context. fillRect( left, top, width, height);
}
//清空画布
this. clearCanvas = function( canvas, left, top, width, height, color)
{
context. clearRect( left, top, width, height);
//再填充一下
that. drawCanvas( canvas, left, top, width, height, color);
}
//初始化
if( jcObject. initImg|| jcObject. initText){
//初始化canvas
window. onload= function(){
that. saveImg( jcObject. initImg);
that. saveText( jcObject. initText);
}
}
//保存图片
this. saveImg = function( imgUrl){
//创建image对象
var img = new Image;
img. src = imgUrl;
img. crossOrigin = 'anonymous';
img. onload = function(){
//画图
canvas. height = bigImg. clientHeight + write. clientHeight + 10;
canvas. style. height = bigImg. clientHeight + write. clientHeight + 10 + "px";
context. drawImage( img, 0, 0, jcObject. canvasWidth, bigImg. height);
}
context. stroke();
}
//先填充白色防止透明色块
this. drawCanvas( canvas, 0, 0, canvas. width, canvas. height, "#ffffff");
//canvas文字换行
this. canvasTextAutoLine = function( str, canvas, initX, initY, lineHeight, context){
var context = canvas. getContext( '2d');
context. fillStyle= "#000000";
var lineWidth = 0;
var canvasWidth = canvas. width;
var lastSubStrIndex= 0;
for( let i= 0; i< str. length; i++){
lineWidth+= context. measureText( str[ i]). width;
if( lineWidth> canvasWidth- initX){ //减去initX,防止边界出现的问题
context. fillText( str. substring( lastSubStrIndex, i), initX, initY);
initY+= lineHeight;
lineWidth= 0;
lastSubStrIndex= i;
}
if( i== str. length- 1){
context. fillText( str. substring( lastSubStrIndex, i+ 1), initX, initY);
}
}
}
//换图时修改路径
image. onchange = function(){
var imgUrl = window. URL. createObjectURL( this. files[ 0]);
bigImg. src = imgUrl;
bigImg. style. height = "auto";
image. onload = that. saveImg( imgUrl)
}
//点击图片换图
bigImg. onclick = function(){
image. click();
}
//点击保存
sub. onclick = function(){
var text = write. innerHTML;
that. saveText( text);
//提交表单
window. setTimeout( function(){
var strDataURI = canvas. toDataURL();
base. value = strDataURI;
form. submit();
}, 1000)
}
//存文字
this. saveText = function( text){
//文字样式
context. font= jcObject. canvasFont;
//清空文字
that. clearCanvas( canvas, 0, bigImg. clientHeight+ jcObject. fontSize, canvas. width, write. clientHeight+ jcObject. lineHeight, "#ffffff");
//文字换行
that. canvasTextAutoLine( text, canvas, 0, bigImg. clientHeight+ jcObject. lineHeight, jcObject. lineHeight, content)
context. stroke();
}
}
< /script>
</body>
</html>


upload.js

var express = require( 'express');
var app = express();
var fs = require( 'fs');
var router = express. Router();
//用于解析数据
var bodyParser = require( 'body-parser');
//上传文件中间件
var multer = require( 'multer');

app. use( express. static( 'static'));
app. use( bodyParser. urlencoded({ extended: false}));
app. use( multer({ dest: '/tmp/'}). array( 'image'));

app. get( '/upload.html', function( req, res){
res. sendFile( __dirname + '/' + "upload.html")
})
//设置跨域访问
app. all( '*', function( req, res, next) {
res. header( "Access-Control-Allow-Origin", "*");
res. header( "Access-Control-Allow-Headers", "X-Requested-With");
res. header( "Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res. header( "X-Powered-By", ' 3.2.1');
res. header( "Content-Type", "application/json;charset=utf-8");
next();
});
app. post( '/upload', function( req, res){

var imgData = req. body. base. replace( / ^ data:image \/ \w+ ;base64,/, '');
var imageName = imgData. substr( 0, 10) + Math. random(). toString( 16);
console. log( imageName)
var dataBuffer = new Buffer( imgData, 'base64');
//写入文件
fs. writeFile( 'D:/my/node/static/images/'+ imageName+ '.png', dataBuffer, function( err){
if( err){
res. end( err);
} else{
res. end( JSON. stringify( '保存成功'));
}
});

})
var server = app. listen( 3300, function( req, res){
var host = server. address(). address;
var port = server. address(). port;
console. log( 'running at http://%s:%s', host, port)
})

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值