vue3.0 图片裁剪 https://www.npmjs.com/package/vue-cropper
参考:https://juejin.cn/post/7316811315590135827
图片不清晰
poster(codeurl: any) {
const query = wx.createSelectorQuery()
query.select('#canvas')
.fields({ node: true, size: true })
.exec((res) => {
const canvas = res[0].node
const ctx = canvas.getContext('2d')
// canvas.width = res[0].width
// canvas.height = res[0].height
const dpr = wx.getSystemInfoSync().pixelRatio
canvas.width = res[0].width * dpr
canvas.height = res[0].height * dpr
this.Acanvas = canvas;
this.width = res[0].width * dpr
this.height = res[0].height* dpr;
const img = canvas.createImage()
img.onload = () => {
ctx.drawImage(img, 0, 0, res[0].width* dpr, res[0].height* dpr)
// 小程序码
const img1 = canvas.createImage()
img1.onload = () => {
// ctx.drawImage(img1, rpx2px(128), rpx2px(560), rpx2px(142), rpx2px(142))
ctx.drawImage(img1, rpx2px(125 * dpr), rpx2px(536 * dpr), rpx2px(125 * dpr), rpx2px(125 * dpr))
ctx.scale(dpr, dpr)
}
img1.src = codeurl
}
img.src = '../../images/poster.png'
})
},
html 加水印
加水印:https://zhuanlan.zhihu.com/p/111331319
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style type="text/css">
#ReactApp {
width: 400px;
height: 400px;
border: 1px solid #f00;
}
</style>
</head>
<body>
<div id="ReactApp"></div>
<script>
const wrap = document.querySelector('#ReactApp');
const { clientWidth, clientHeight } = wrap;
const waterHeight = 120;
const waterWidth = 180;
// 计算个数
const [columns, rows] = [~~(clientWidth / waterWidth), ~~(clientHeight / waterHeight)]
for (let i = 0; i < columns; i++) {
for (let j = 0; j <= rows; j++) {
const waterDom = document.createElement('div');
// 动态设置偏移值
waterDom.setAttribute('style', `
width: ${waterWidth}px;
height: ${waterHeight}px;
left: ${waterWidth + (i - 1) * waterWidth + 10}px;
top: ${waterHeight + (j - 1) * waterHeight + 10}px;
color: #000;
position: absolute`
);
waterDom.innerText = '测试水印';
wrap.appendChild(waterDom);
}
}
</script>
</body>
</html>
中心旋转
//---sample rotate center
var width = 100
var height = 100
var x = (canvas.width-width)*0.5 //形状放置在画布中心
var y = (canvas.height-height)*0.5 //形状放置在画布中心
var cx = x + 0.5 * width // cx 形状中心
var cy = y + 0.5 * height // cy 形状中心
//--清空之前的绘制
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.fillStyle = "#ff0000"
ctx.fillRect(x, y, width, height) //没旋转之前的形状
ctx.translate(cx, cy) //坐标圆点设置到形状中心
ctx.rotate( (Math.PI / 180) * 45) //旋转 45 度
ctx.translate(-cx, -cy) //坐标圆点重置到 0,0
ctx.fillStyle = "#0000ff"
ctx.fillRect(x, y, width, height) //没旋转之后的形状
canvas 加水印
方式一
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body><script id="__bs_script__">//<![CDATA[
document.write("<script async src='/browser-sync/browser-sync-client.js?v=2.26.7'><\/script>".replace("HOST", location.hostname));
//]]></script>
<img id="img1" width="100" height="100" crossOrigin="anonymous" src="./1.png" alt="">
<script>
// 图片在前会 压在画片后面 ctx.beginPath() 回到最开始的状态 重新开辟路径
class CanvasWay {
constructor(watermark) {
this.watermark = watermark
const { width, height } = watermark
this.canvas = document.createElement('canvas');
this.canvas.setAttribute('width', width);
this.canvas.setAttribute('height', height);
this.R = Math.sqrt(width * width + height * height)
// this.canvas.setAttribute('width', 2 * this.R);
// this.canvas.setAttribute('height', 2 * this.R);
}
render() {
const { txt, x, y, width, height, font, color, fontSize, alpha, angle } = this.watermark
const ctx = this.canvas.getContext('2d');
ctx.clearRect(0, 0, width, height);
ctx.moveTo(0, 0); // 起点
ctx.lineTo(0, 0 + height)
ctx.lineTo(0 + width, 0 + height)
ctx.lineTo(width + 0, 0)
ctx.stroke();
ctx.clip();
// let oimg = document.getElementById('img1');
// ctx.drawImage(oimg, 0, 0, oimg.width, oimg.height);
let img = new Image()
// img.setAttribute('crossOrigin', 'anonymous');
img.crossOrigin = 'anonymous'
img.src = './2.png'
img.onload = () => {
ctx.beginPath();
ctx.textBaseline = 'top';
ctx.textAlign = 'left'
ctx.fillStyle = color;
ctx.globalAlpha = alpha;
ctx.font = `${fontSize}px ${font}`
const [columns, rows] = [~~(2 * this.R / (ctx.measureText(txt).width + 10)), ~~(2 * this.R / (fontSize + 10))];
// const [columns, rows] = [~~((height * Math.sin(Math.PI / 180 * angle) + width * Math.cos(Math.PI / 180 * angle)) / (ctx.measureText(txt).width + 10)), ~~((height * Math.cos(Math.PI / 180 * angle) + width * Math.sin(Math.PI / 180 * angle)) / (fontSize + 10))];
// ctx.translate(this.R, this.R)
ctx.rotate(-Math.PI / 180 * angle);
let zx = 0, zy = 0;
for (let i = 0; i < columns + 1; i++) {
for (let j = 0; j < rows + 1; j++) {
zx = x + i * (ctx.measureText(txt).width + 10)
zy = y + j * (fontSize + 10)
ctx.fillText(txt, zx - this.R, zy - this.R);
}
}
// ctx.translate(-this.R, -this.R)
// ctx.arc(0, 0, this.R, 0, 2 * Math.PI);//在canvas中绘制圆形
ctx.stroke()
ctx.rotate(Math.PI / 180 * angle);
// ctx.globalAlpha = 1;
ctx.drawImage(img, 0, 0, img.width / 6, img.height / 6);
let zimg = new Image()
zimg.src = this.canvas.toDataURL();
document.body.appendChild(zimg)
}
}
}
let vcanvas = new CanvasWay({
width: 200,
height: 300,
txt: 'xx111',
// x: 10,
// y: 190,
x: 0,
y: 0,
font: 'Arial',
color: '#f00',
fontSize: 16,
alpha: 0.5,
angle: -60
})
vcanvas.render()
// setTimeout(() => {
// let img = new Image()
// img.src = vcanvas.render()
// document.body.appendChild(img)
// }, 1000)
</script>
</body>
</html>
注意:ctx.translate(this.R, this.R) 移动是圆心,移动后,要进行还原 ctx.rotate(-Math.PI / 180 * angle); 以圆心为目标开始
方式二
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body><script id="__bs_script__">//<![CDATA[
document.write("<script async src='/browser-sync/browser-sync-client.js?v=2.26.7'><\/script>".replace("HOST", location.hostname));
//]]></script>
<img id="img1" width="100" height="100" crossOrigin="anonymous" src="./1.png" alt="">
<script>
// 图片在前会 压在画片后面 ctx.beginPath() 回到最开始的状态 重新开辟路径
class CanvasWay {
constructor(watermark) {
this.watermark = watermark
const { width, height } = watermark
this.canvas = document.createElement('canvas');
this.canvas.setAttribute('width', width);
this.canvas.setAttribute('height', height);
// this.canvas.setAttribute('width', 1000);
// this.canvas.setAttribute('height', 1200);
}
render() {
const { txt, x, y, width, height, font, color, fontSize, alpha, angle } = this.watermark
const ctx = this.canvas.getContext('2d');
ctx.clearRect(0, 0, width, height);
// ctx.translate(100, 100)
// ctx.moveTo(0, 0); // 起点
// ctx.lineTo(0, height)
// ctx.lineTo(width, height)
// ctx.lineTo(width, 0)
// ctx.stroke();
ctx.beginPath();
ctx.textBaseline = 'top';
ctx.textAlign = 'left'
ctx.fillStyle = color;
ctx.globalAlpha = alpha;
ctx.font = `${fontSize}px ${font}`
ctx.rotate(Math.PI / 180 * angle);
ctx.translate(0, -width * Math.sin(Math.PI / 180 * angle))
// ctx.fillText(txt, x, y + fontSize);
// 计算个数
// const [columns, rows] = [~~(width / (ctx.measureText(txt).width + 10)), ~~(height / (fontSize + 10))];
const [columns, rows] = [~~((height * Math.sin(Math.PI / 180 * angle) + width * Math.cos(Math.PI / 180 * angle)) / (ctx.measureText(txt).width + 10)), ~~((height * Math.cos(Math.PI / 180 * angle) + width * Math.sin(Math.PI / 180 * angle)) / (fontSize + 10))];
let zx = 0, zy = 0;
for (let i = 0; i < columns + 1; i++) {
for (let j = 0; j < rows + 1; j++) {
console.log(i, j)
zx = x + i * (ctx.measureText(txt).width + 10)
zy = y + j * (fontSize + 10)
ctx.fillText(txt, zx, zy);
}
}
ctx.translate(0, width * Math.sin(Math.PI / 180 * angle))
ctx.rotate(-Math.PI / 180 * angle);
ctx.globalAlpha = 1;
// let oimg = document.getElementById('img1');
// ctx.drawImage(oimg, 0, 0, oimg.width, oimg.height);
let img = new Image()
// img.setAttribute('crossOrigin', 'anonymous');
img.crossOrigin = 'anonymous'
img.src = './2.png'
img.onload = () => {
ctx.drawImage(img, 0, 0, img.width / 6, img.height / 6);
// ctx.translate(-x, -y - fontSize)
let zimg = new Image()
zimg.src = this.canvas.toDataURL();
document.body.appendChild(zimg)
}
}
}
let vcanvas = new CanvasWay({
width: 400,
height: 600,
txt: 'xx111',
// x: 10,
// y: 190,
x: 0,
y: 0,
font: 'Arial',
color: '#f00',
fontSize: 16,
alpha: 0.5,
angle: 45
})
vcanvas.render()
// setTimeout(() => {
// let img = new Image()
// img.src = vcanvas.render()
// document.body.appendChild(img)
// }, 1000)
</script>
</body>
</html>
方式三
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<img id="img1" width="100" height="100" crossOrigin="anonymous" src="./1.png" alt="">
<script>
// 图片在前会 压在画片后面 ctx.beginPath() 回到最开始的状态 重新开辟路径
class CanvasWay {
constructor(watermark) {
this.watermark = watermark
const { width, height } = watermark
this.canvas = document.createElement('canvas');
// this.canvas.setAttribute('width', width);
// this.canvas.setAttribute('height', height);
this.R = Math.sqrt(width * width + height * height)
this.canvas.setAttribute('width', 2 * this.R);
this.canvas.setAttribute('height', 2 * this.R);
}
render() {
const { txt, x, y, width, height, font, color, fontSize, alpha, angle } = this.watermark
const ctx = this.canvas.getContext('2d');
ctx.clearRect(0, 0, width, height);
ctx.moveTo(this.R, this.R); // 起点
ctx.lineTo(this.R, this.R + height)
ctx.lineTo(this.R + width, this.R + height)
ctx.lineTo(width + this.R, this.R)
ctx.stroke();
ctx.clip();
// let oimg = document.getElementById('img1');
// ctx.drawImage(oimg, 0, 0, oimg.width, oimg.height);
let img = new Image()
// img.setAttribute('crossOrigin', 'anonymous');
img.crossOrigin = 'anonymous'
img.src = './2.png'
img.onload = () => {
ctx.beginPath();
ctx.textBaseline = 'top';
ctx.textAlign = 'left'
ctx.fillStyle = color;
ctx.globalAlpha = alpha;
ctx.font = `${fontSize}px ${font}`
const [columns, rows] = [~~(2 * this.R / (ctx.measureText(txt).width + 10)), ~~(2 * this.R / (fontSize + 10))];
// const [columns, rows] = [~~((height * Math.sin(Math.PI / 180 * angle) + width * Math.cos(Math.PI / 180 * angle)) / (ctx.measureText(txt).width + 10)), ~~((height * Math.cos(Math.PI / 180 * angle) + width * Math.sin(Math.PI / 180 * angle)) / (fontSize + 10))];
ctx.translate(this.R, this.R)
ctx.rotate(-Math.PI / 180 * angle);
let zx = 0, zy = 0;
for (let i = 0; i < columns + 1; i++) {
for (let j = 0; j < rows + 1; j++) {
zx = x + i * (ctx.measureText(txt).width + 10)
zy = y + j * (fontSize + 10)
ctx.fillText(txt, zx - this.R, zy - this.R);
}
}
ctx.rotate(Math.PI / 180 * angle);
ctx.translate(-this.R, -this.R)
// ctx.arc(this.R, this.R, this.R, 0, 2 * Math.PI);//在canvas中绘制圆形
ctx.stroke()
ctx.drawImage(img, this.R, this.R, img.width / 6, img.height / 6);
let copy = () => {
var imgData = ctx.getImageData(this.R, this.R, width, height);
// ctx.putImageData(imgData, 0, 0); 复制到其他地方
var canvas2 = document.createElement("canvas")
var cxt2 = canvas2.getContext("2d")
canvas2.width = width;
canvas2.height = height;
cxt2.putImageData(imgData, 0, 0, 0, 0, canvas2.width, canvas2.height)
var img2 = canvas2.toDataURL("image/png");
return img2
}
let zimg = new Image()
// zimg.src = this.canvas.toDataURL();
zimg.src = copy()
document.body.appendChild(zimg)
}
}
}
let vcanvas = new CanvasWay({
width: 200,
height: 300,
txt: 'xx111',
// x: 10,
// y: 190,
x: 0,
y: 0,
font: 'Arial',
color: '#f00',
fontSize: 16,
alpha: 0.5,
angle: 45
})
vcanvas.render()
// setTimeout(() => {
// let img = new Image()
// img.src = vcanvas.render()
// document.body.appendChild(img)
// }, 1000)
</script>
</body>
</html>
canvas特殊形状
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>绘制心形相框</title>
<style>
body { background: url("./images/bg3.jpg") repeat; }
#canvas { border: 1px solid #aaaaaa; display: block; margin: 50px auto; }
</style>
</head>
<body>
<div id="canvas-warp">
<canvas id="canvas">
你的浏览器居然不支持Canvas?!赶快换一个吧!!
</canvas>
</div>
<script>
window.onload = function(){
var canvas = document.getElementById("canvas");
canvas.width = 800;
canvas.height = 600;
var context = canvas.getContext("2d");
context.fillStyle = "#FFF";
context.fillRect(0,0,800,600);
context.beginPath();
context.moveTo(400,260);
context.bezierCurveTo(450,220,450,300,400,315);
context.bezierCurveTo(350,300,350,220,400,260);
context.clip();
context.closePath();
var img = new Image();
img.src = "./images/20-1.jpg";
img.onload = function(){
context.drawImage(img,348,240,100,100);
}
};
</script>
</body>
</html>
canvas镂空
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>绘制其他剪纸图形</title>
</head>
<body>
<canvas id="canvas" width="600" height="400"></canvas>
</body>
<script>
var canvas = document.getElementById('canvas'),
context= canvas.getContext('2d');
//Function……
/**
* 画网格
*/
function drawGird(color,stepX,stepY) {
context.strokeStyle = color;
context.lineWidth = 0.5;
for (var i = stepX + 0.5; i < context.canvas.width; i += stepX) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
context.stroke();
}
for (var i = stepY + 0.5; i < context.canvas.height; i += stepY) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();
}
}
function draw() {
context.clearRect(0,0,canvas.width,canvas.height);
drawGird('lightgray',10,10);
context.save();
context.shadowColor='rgba(200,200,0,0.5)';
context.shadowOffsetX=12;
context.shadowOffsetY=12;
context.shadowBlur=15;
drawCutouts();
strokeCutoutShapes();
context.restore();
}
/**
* 画那些需要镂空的图形
*/
function drawCutouts() {
context.beginPath();
addOuterRectanglePath();//CW,CW代表Clockwise顺时针
addCirclePath();//CCW,CCW代表counter-clockwise逆时针
addRectanglePath();//CCW
addTrianglePath();//CCW
context.fill();//Cut out shapes
}
/**
* 镂空描边
*/
function strokeCutoutShapes() {
context.save();
context.strokeStyle='rgba(0,0,0,0.7)';
context.beginPath();
addOuterRectanglePath();//CW
context.stroke();
context.beginPath();
addCirclePath();
addRectanglePath();
addTrianglePath();
context.stroke();
}
/**
* 重写rect方法,增加了顺序和逆序路径的参数
* @param x
* @param y
* @param w
* @param h
* @param direction 顺序和逆序,布尔类型
*/
function rect(x,y,w,h,direction) {
if(direction){//CCW
context.moveTo(x,y);
context.lineTo(x,y+h);
context.lineTo(x+w,y+h);
context.lineTo(x+w,y);
context.closePath();
}else{
context.moveTo(x,y);
context.lineTo(x + w, y);
context.lineTo(x + w, y + h);
context.lineTo(x, y + h);
context.closePath();
}
}
function addOuterRectanglePath() {
context.rect(110, 25, 370, 335);
}
function addCirclePath() {
context.arc(300,300,40,0,Math.PI*2,true);
}
function addRectanglePath() {
rect(310,55,70,35,true);
}
function addTrianglePath() {
context.moveTo(400,200);
context.lineTo(250, 115);
context.lineTo(200, 200);
context.closePath();
}
//Init……
context.fillStyle='goldenrod';
draw();
</script>
</html>
canvas背景
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<canvas id="canvas" width="400" height="600"></canvas>
<script>
let canvas = document.getElementById("canvas")
let context = canvas.getContext("2d")
var fillImg = new Image();
fillImg.src = '1.png';
fillImg.onload = function () {
context.fillStyle = context.createPattern(fillImg, 'repeat');
context.fillRect(0, 0, 600, 600);
}
</script>
</body>
</html>