2024-02-24 03:06:29
使用 Canvas API 实现图片弯曲拉伸效果的核心思路是:通过操作像素数据或坐标映射,对图像进行非线性变形处理。 以下是具体实现方法及优化方案:
一、基础实现:基于像素偏移的弯曲效果参考代码片段通过修改像素颜色值实现简单弯曲,但存在局限性(仅视觉弯曲,未改变实际像素位置)。以下是改进后的完整实现:
<canvas id="canvas" width="500" height="300"></canvas><img id="image" src="your-image.jpg" style="display:none;"><script> const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); const image = document.getElementById('image'); image.onload = function() { // 创建临时画布保存原始图像 const tempCanvas = document.createElement('canvas'); tempCanvas.width = image.width; tempCanvas.height = image.height; const tempCtx = tempCanvas.getContext('2d'); tempCtx.drawImage(image, 0, 0); // 目标画布绘制变形图像 for(let y = 0; y < canvas.height; y++) { for(let x = 0; x < canvas.width; x++) { // 计算弯曲偏移量(示例为正弦波弯曲) const waveOffset = Math.sin(y / 20) * 30; const srcX = x; const srcY = y + waveOffset; // 边界检查 if(srcY >= 0 && srcY < tempCanvas.height) { const pixel = tempCtx.getImageData(srcX, srcY, 1, 1).data; ctx.fillStyle = `rgba(${pixel[0]},${pixel[1]},${pixel[2]},${pixel[3]/255})`; ctx.fillRect(x, y, 1, 1); } } } };</script>关键点说明:
直接操作像素在性能上存在瓶颈,推荐使用坐标变换方法:
function drawWarpedImage(ctx, image, waveAmplitude, waveFrequency) { ctx.save(); const imgWidth = image.width; const imgHeight = image.height; // 创建离屏画布 const offscreenCanvas = document.createElement('canvas'); offscreenCanvas.width = imgWidth; offscreenCanvas.height = imgHeight; const offscreenCtx = offscreenCanvas.getContext('2d'); offscreenCtx.drawImage(image, 0, 0); // 应用变形 for(let y = 0; y < imgHeight; y++) { const waveOffset = Math.sin(y / waveFrequency) * waveAmplitude; ctx.drawImage( offscreenCanvas, 0, y, imgWidth, 1, // 源图像裁剪区域 0, y + waveOffset, imgWidth, 1 // 目标绘制区域 ); } ctx.restore();}// 使用示例const canvas = document.getElementById('canvas');const ctx = canvas.getContext('2d');const image = new Image();image.src = 'your-image.jpg';image.onload = () => { drawWarpedImage(ctx, image, 40, 30);};优势说明:
对于更复杂的弯曲效果(如弧形、波浪形),可使用贝塞尔曲线进行坐标映射:
function drawBezierWarped(ctx, image, points) { ctx.save(); const imgData = ctx.getImageData(0, 0, image.width, image.height); const offscreenCanvas = document.createElement('canvas'); // ...(类似方案二创建离屏画布) // 定义贝塞尔曲线控制点(示例为简单弧线) const curvePoints = [ {x:0, y:0}, {x:image.width/2, y:-50}, {x:image.width, y:0} ]; for(let y = 0; y < image.height; y++) { for(let x = 0; x < image.width; x++) { // 计算曲线上的对应位置(简化版,实际需使用贝塞尔公式) const t = x / image.width; const curveY = (1-t)2 * 0 + 2*(1-t)*t * (-50) + t2 * 0; const srcY = Math.max(0, Math.min(image.height-1, y - curveY)); const pixel = offscreenCtx.getImageData(x, srcY, 1, 1).data; ctx.fillStyle = `rgb(${pixel[0]},${pixel[1]},${pixel[2]})`; ctx.fillRect(x, y, 1, 1); } } ctx.restore();}四、性能优化建议效果特点:
通过以上方法,可以灵活实现各种图片弯曲拉伸效果,从简单的波浪变形到复杂的路径映射均可覆盖。实际开发中应根据具体需求选择合适方案,并注意性能优化。