JS简单操作像素设置背景图片拉伸区域避免图片拉伸变形
废话开篇:简单设置图片拉伸区域,实现图片当作标签背景图时不被拉伸变形
一、实现效果
左右两个标签,左面的设置了一个不重复的背景图片
现在进行一下操作,让左面的背景图在不变形的前提下进行铺满整个左侧的标签
可以看到左侧的标签在背景图片不变形的情况下铺满了。但是,这里有个明显的问题,就是上面的图中间“凹进去”的部分不在布局正中了,是的,其实,在设置的时候,就是将图片上半部分的一个“重复”像素进行了重复覆盖。
更换一个图片试试。
这张图中间的部分可以作为重复的“填充像素”
二、代码实现
1、HTML
调用很简单,初始化 PictureExtension 操作对象进行相关绑定及操作
// 进行背景延展操作
let pictureExtension = new PictureExtension(document.getElementById('backImageOne'),'./back1.png',(size)=>{
// 需要进行拉伸的区域,因为是纵向拉伸,这里的拉伸区域的宽度为图片等宽
let x = 0
let y = 470
let width = size.width
let height = 20
return {x,y,width,height}
})
2、JS
PictureExtension 对象管理类,实现相关拉伸过程中的像素填充操作
class PictureExtension{
// 需要设置的背景图片的标签
el
// 背景图资源地址
imgSrc
// 图片尺寸
imageSize = {}
// 设置拉伸区域回调
canStretchSizeCallBack = null
// 设置拉伸区域
canStretchSize = {}
// 原像素
originalPiexls
constructor(el,imgSrc,callBack){
this.el = el
this.imgSrc = imgSrc
this.canStretchSizeCallBack = callBack
this.beginImageOption()
}
// 开始对齐图片
async beginImageOption(){
await this.getImageSize(this.imgSrc)
try {
let piexls = this.createNewBackImage()
let url = this.createURLByPiexls(piexls)
this.el.style.backgroundImage = 'url('+url +')';
} catch (error) {
console.log('error:' + error)
}
}
// 获取图片大小
async getImageSize(imgSrc){
var image = new Image();
image.src = imgSrc;
await new Promise((resolve)=>{
image.onload = resolve
})
let width = image.width
let height = image.height
this.imageSize = { width,height }
// 保存当前的自定义设置的拉伸区域
if(this.canStretchSizeCallBack){
this.canStretchSize = this.canStretchSizeCallBack(this.imageSize)
}
let canvas = document.createElement('canvas')
canvas.setAttribute('width',`${width}px`)
canvas.setAttribute('height',`${height}px`)
var ctx = canvas.getContext("2d")
ctx.fillStyle = ctx.createPattern(image, 'no-repeat');
ctx.fillRect(0, 0, width, height);
try {
//保存像素
this.originalPiexls = ctx.getImageData(0,0,width,height)
} catch (error) {
console.log(error)
}
}
// 获取尺寸
getAllNeedSize(){
// 当前需要操作的标签实际尺寸
let elWidth = this.el.offsetWidth
let elHeight = this.el.offsetHeight
// 当前图片的实际尺寸
let imgWidth = this.imageSize.width
let imgHeight = this.imageSize.height
// 创建新图片的尺寸,根据dom对象尺寸进行比例缩放
let finallyWidth = imgWidth
let finallyHeight = imgWidth * (elHeight / elWidth)
// 需要补的像素
let needFillPiexlHeight = finallyHeight - imgHeight
return { elWidth,elHeight,imgWidth,imgHeight,finallyWidth,finallyHeight,needFillPiexlHeight }
}
// 生成新的图片
createNewBackImage(){
if(this.originalPiexls.data.length == 0){
throw('像素为空')
}
let { finallyWidth,finallyHeight,needFillPiexlHeight } = this.getAllNeedSize()
// 创建新的图片
let currentIndex = 0
let finallyPiexls = new Uint8ClampedArray(finallyWidth * finallyHeight * 4)
for(let y = 0;y < finallyHeight;y ++){
for(let x = 0;x < finallyWidth;x ++){
for(let k = 0;k < 4;k++){
let index
if(y <= this.canStretchSize.y) {
// 开头直接对接
index = (y * finallyWidth + x) * 4 + k
} else if( y > this.canStretchSize.y && y <= this.canStretchSize.y + needFillPiexlHeight ){
// 中间重复补像素
index = (((y % this.canStretchSize.height) + this.canStretchSize.y) * finallyWidth + x) * 4 + k
} else {
// 后面错位对齐
index = ((y - needFillPiexlHeight) * finallyWidth + x) * 4 + k
}
finallyPiexls[currentIndex] = this.originalPiexls.data[index]
currentIndex ++
}
}
}
return finallyPiexls
}
// 通过像素点生成URL
createURLByPiexls(piexls){
let url = ''
let { finallyWidth,finallyHeight } = this.getAllNeedSize()
let canvas = document.createElement('canvas')
canvas.setAttribute('width',`${finallyWidth}px`)
canvas.setAttribute('height',`${finallyHeight}px`)
let smallCtx = canvas.getContext("2d")
//初始化ImageData
let finallyImageData = new ImageData(piexls,finallyWidth,finallyHeight)
// 当前范围内需要放大的像素
smallCtx.putImageData(finallyImageData,0,0,0,0,finallyWidth,finallyHeight)
url = canvas.toDataURL('image/jpeg',1)
if(url == ''){
throw('像素转图片失败')
}
return url
}
}
3、逻辑
上面就是全部的逻辑,最终想干的事情就是当填充标签尺寸与背景图片尺寸不一致的时候,将背景图片进行强制拉伸,过程中设置一下“可复制”的拉伸区域,为了保证不变形,无限复制里面的像素值直至填满所有空缺的点。
三、思考与总结
有些复杂的样式CSS可操作性太小,不如直接用JS操作来实现它,代码拙劣,大神勿笑[抱拳][抱拳][抱拳],哪怕能帮助大家一点点,深感欣慰!
转载自:https://juejin.cn/post/7202501172329365565