前几天由于团队需要,折腾了一下图像液化的处理过程。
现在来整理一下思路,做个记录。
用到公式如下,网上拿来的
话不多说,上代码
本来想尽量写出点逼格。。。后来发现怎么写也还是几个function搞定,就那样了。
(function(global) {
// 计算两点距离平方
function distanceSqr( x1, y1, x2, y2 ) { return sqr(x1-x2) + sqr(y1-y2); }
// 计算平方
function sqr(x) { return x*x; }
// 遍历一个指定圆内的所有点
// 通过callback传入回调方法,回调传出每一个点的相关信息
function eachCircleDot( imageData, ox, oy, r, callback ) {
var imgWidth = imageData.width,
imgHeight = imageData.height,
data = imageData.data,
left = ox-r,
right = ox+r,
top = oy-r,
bottom = oy+r,
dotRedOffset,dotGreenOffset,dotBlueOffset,alphaOffset;
for( var x = left; x < right; x++ )
for( var y = top; y < bottom; y++ )
if( distanceSqr( x, y, ox, oy ) <= sqr(r) ) {
dotRedOffset = y*imgWidth*4+x*4;
dotGreenOffset = dotRedOffset + 1;
dotBlueOffset = dotGreenOffset + 1;
alphaOffset = dotBlueOffset + 1;
callback(
// 当前点的坐标
{ x:x, y:y },
// 点的RGBA四个分量对应字节的下标
{
r: dotRedOffset,
g: dotGreenOffset,
b: dotBlueOffset,
a: alphaOffset,
},
// 传进来的ImageData的data部分
data
);
}
}
// 复制一个imageData的data到一个buff里
function copyImageDataBuff( imgData ) {
var data = imgData.data,
imgDataBuff = [];
for( var i in data )
imgDataBuff[i] = data[i];
return imgDataBuff;
}
// 从buff按照指定坐标复制像素点数据到目标imageData里
function moveDot( imgData, dataBuff, x, y, srcX, srcY ) {
var imgWidth = imgData.width,
imgHeight = imgData.height,
data = imgData.data;
x = Math.floor(x);
y = Math.floor(y);
srcX = Math.floor(srcX);
srcY = Math.floor(srcY);
var targetStartOffset = y*imgHeight*4 + x*4,
srcStartOffset = srcY*imgHeight*4 + srcX*4;
for( var i = 0; i < 4; i++ )
data[ targetStartOffset + i ] = dataBuff[ srcStartOffset + i ];
}
// 执行液化过程
// imgData 通过canvas的getImageData方法得到的数据对象
// cx,cy 圆心坐标
// mx,my 移动目标坐标
// r 作用半径
// strength 力度百分比(1-100)
function liquify( imgData, cx, cy, mx, my, r, strenth ) {
var imgDataBuff = copyImageDataBuff(imgData);
eachCircleDot( imgData, cx, cy, r, function( posi ) {
var tx = posi.x,
ty = posi.y;
var u = transFormula( cx, cy, mx, my, tx, ty, r, strenth );
moveDot( imgData, imgDataBuff, tx, ty, u.x, u.y );
function transFormula( cx, cy, mx, my, tx, ty, r, strenth ) {
strenth = strenth || 100;
var relativity = sqr(r) - distanceSqr( tx, ty, cx, cy );
var distanceMovedSqr = distanceSqr( mx, my, cx, cy );
var rate = sqr( relativity / ( relativity + distanceMovedSqr*(100/strenth) ) );
var ux = tx - rate * (mx-cx),
uy = ty - rate * (my-cy);
return { x:ux, y:uy };
}
});
}
// 挂到全局对象
global.LiquifyFilter = {
liquify: liquify
};
})(window);
使用它
-
先用canvas的
getImageData();
方法获取到要处理图片的imageData
-
全局作用域下调用
LiquifyFilter.liquify( imageData, 圆心X, 圆心Y, 目标点X, 目标点Y, 作用半径, [力度百分比] );
完成转换。
-
然后再用canvas的
puImageData();
把转换后的imageData输出到canvas中
效果图如下
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。