110,537
社区成员
发帖
与我相关
我的任务
分享
<!DOCTYPE html>
<canvas class="center" id="canvas_4" style="border: 1px solid blue" width="319" height="250">sorry, no canvas, please, upgrade your browser</canvas>
<img border="1" id="imgTest" width="319" height="250" src="..."/>
<script type="text/javascript">
function getCanvas(canvasId) {
//alert(canvasId)
"use strict";
if (canvasId) {
return document.getElementById(canvasId);
} else {
// If not "canvasId" param is present, use the default canvasId registered for this function
return document.getElementById(getCanvas.defaultCanvasId);
}
}
//getCanvas.defaultCanvasId = "canvas_1";
function getContext2d(canvasId) {
"use strict";
return getCanvas(canvasId).getContext('2d');
}
function grabImageData(canvasId, onPixelsLoadedCallback) {
"use strict";
var canvas, context2d, width, height, img, imageData;
canvas = getCanvas(canvasId);
context2d = getContext2d(canvasId);
// read the width and height of the canvas that
// matches the image dimensions on purpose (just to keep the code simple)
width = canvas.width;
height = canvas.height;
img = new Image();
img.src = document.getElementById('imgTest').src;
// We have to wait for the image to load, after the loading completes, this callback will be executed
img.onload = function() {
// Draw the loaded image into the canvas
context2d.drawImage(img, 0, 0);
// Retrieve the pixels from the canvas and pass them to the callback as a parameter
onPixelsLoadedCallback(canvasId, context2d.getImageData(0, 0, width, height));
}
}
function createCompatibleImageData(canvasId, imgData) {
"use strict";
var context2d = getContext2d(canvasId);
return context2d.createImageData(imgData.width, imgData.height);
}
// This renders the 'imageData' parameter into the canvas
function drawPixels(canvasId, imageData) {
"use strict";
var context2d = getContext2d(canvasId);
context2d.putImageData(imageData, 0, 0);
}
// Copy the pixels of the 'srcPixels' ImageData parameter
// into the 'dstPixels' parameter
function copyImageData(srcPixels, dstPixels, width, height) {
"use strict";
var x, y, position;
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
position = y * width + x;
position *= 4;
dstPixels[position + 0] = srcPixels[position + 0];
dstPixels[position + 1] = srcPixels[position + 1];
dstPixels[position + 2] = srcPixels[position + 2];
dstPixels[position + 3] = srcPixels[position + 3];
}
}
}
function liquify(canvasId, originalImageData) {
"use strict";
var x, y, width, height, size, radius, centerX, centerY, sourcePosition, destPosition;
var sourceImgData = originalImageData;
var destImgData = createCompatibleImageData(canvasId, sourceImgData);
var srcPixels = sourceImgData.data;
var dstPixels = destImgData.data;
var radiusSquared;
width = originalImageData.width;
height = originalImageData.height;
centerX = Math.floor(width / 2);
centerY = Math.floor(height / 2);
size = width < height ? width : height;
radius = Math.floor(size / 2);
//radius = 50
radiusSquared = radius * radius;
copyImageData(srcPixels, dstPixels, width, height);
drawPixels(canvasId, destImgData);
function animate(c, growConstant) {
"use strict";
var r, alpha, angle, sourcePosition, destPosition, newX, newY, degrees, delayBetweenFrames;
var k, pos0, pos1, pos2, pos3, deltaX, deltaY, x0, xf, y0, yf, componentX0, componentX1, finalPixelComponent;
var interpolationFactor;
// Iterate over the interest square region
for (y = -radius; y < radius; ++y) {
for (x = -radius; x < radius; ++x) {
// Check if the pixel is inside the effect circle
if (x * x + y * y <= radiusSquared) {
// Get the pixel array position
destPosition = (y + centerY) * width + x + centerX;
destPosition *= 4;
// Transform the pixel Cartesian coordinates (x, y) to polar coordinates (r, alpha)
r = Math.sqrt(x * x + y * y);
alpha = Math.atan2(y, x);
// Remember that the angle alpha is in radians, transform it to degrees
degrees = (alpha * 180.0) / Math.PI;
// Calculate the interpolation factor
interpolationFactor = r / radius;
// Do the interpolation
r = interpolationFactor * r + (1.0 - interpolationFactor) * c * Math.sqrt(r);
// r/rmax * r + (1-r/rmax) *c * √r
// Transform back from polar coordinates to Cartesian
alpha = (degrees * Math.PI) / 180.0;
newY = r * Math.sin(alpha);
newX = r * Math.cos(alpha);
// Calculate the (x, y) coordinates of the transformation and keep
// the fractional in the delta variables
x0 = Math.floor(newX);
xf = x0 + 1;
y0 = Math.floor(newY);
yf = y0 + 1;
deltaX = newX - x0;
deltaY = newY - y0;
// Calculate the array position for the pixels (x, y), (x + 1, y), (x, y + 1) and (x + 1, y + 1)
pos0 = ((y0 + centerY) * width + x0 + centerX) * 4;
pos1 = ((y0 + centerY) * width + xf + centerX) * 4;
pos2 = ((yf + centerY) * width + x0 + centerX) * 4;
pos3 = ((yf + centerY) * width + xf + centerX) * 4;
// Do the bilinear interpolation thing for every component of the pixel
for (k = 0; k < 4; ++k) {
// Interpolate the pixels (x, y) and (x + 1, y)
componentX0 = (srcPixels[pos1 + k] - srcPixels[pos0 + k]) * deltaX + srcPixels[pos0 + k];
// Interpolate the pixels immediately below of (x, y), those are (x, y + 1) and (x + 1, y + 1)
componentX1 = (srcPixels[pos3 + k] - srcPixels[pos2 + k]) * deltaX + srcPixels[pos2 + k];
// Interpolate again the interpolated components
finalPixelComponent = (componentX1 - componentX0) * deltaY + componentX0;
// Set the pixel in the image buffer but first check if it lies between 0 and 255, if not, clamp it to that range
dstPixels[destPosition + k] = finalPixelComponent > 255 ? 255 : (finalPixelComponent < 0 ? 0 : finalPixelComponent);
}
}
}
}
drawPixels(canvasId, destImgData);
setTimeout(function() {
if (c > 15.0) {
growConstant = false;
}
if (c <= 1.0) {
growConstant = true;
}
// Depending on the flag 'leftToRight' value, increase/decrease
// the 'step' parameter by a small value at a time
animate(c + (growConstant ? 0.1 : -0.1), growConstant);
}, 10);
}
animate(1, true);
}
//(function () {
// "use strict";
grabImageData('canvas_4', liquify);
//})();
</script>