Code Bye

怎么转成 C#

有这样一个 js 动画

原图

代码如下,问一下怎么样转成 C# 代码
<!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>
解决方案

200

private void button1_Click(object sender, EventArgs e) {
    m_imgSrc = Image.FromFile("./test.png");
    Bitmap bmp = (Bitmap)m_imgSrc;
    BitmapData bmpData = bmp.LockBits(new Rectangle(Point.Empty, bmp.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    m_byColorsSrc = new byte[bmpData.Height * bmpData.Stride];
    Marshal.Copy(bmpData.Scan0, m_byColorsSrc, 0, m_byColorsSrc.Length);
    bmp.UnlockBits(bmpData);
    centerX = (int)Math.Floor((double)bmp.Width / 2);
    centerY = (int)Math.Floor((double)bmp.Height / 2);
    //size = width < height ? width : height;
    radius = (int)Math.Floor((double)(bmp.Width < bmp.Height ? bmp.Width : bmp.Height) / 2);
    radiusSquared = radius * radius;
    pictureBox1.Image = this.Animate(1F);
    timer1.Interval = 10;
    timer1.Start();
}
private int radius;
private int radiusSquared;
private int centerX, centerY;
private byte[] m_byColorsSrc;
//private byte[] by_clrsDst;
private Image m_imgSrc;
private Image Animate(float fC) {
    int destPosition;
    double r, alpha, newX, newY, deltaX, deltaY, degrees, componentX0, componentX1, finalPixelComponent;
    int k, pos0, pos1, pos2, pos3, x0, xf, y0, yf;
    double interpolationFactor;
    Bitmap bmpRet = new Bitmap(m_imgSrc.Width, m_imgSrc.Height, PixelFormat.Format32bppArgb);
    BitmapData bmpData = bmpRet.LockBits(new Rectangle(Point.Empty, bmpRet.Size), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
    byte[] byColors = new byte[bmpData.Height * bmpData.Stride];
    //Array.Copy(m_byColorsSrc, byColors, byColors.Length);//拷贝原始图像 注释就是圆形
    // Iterate over the interest square region
    for (int y = -radius; y < radius; ++y) {
        for (int 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;
                destPosition = (y + centerY) * bmpData.Stride + (x + centerX) * 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) * fC * 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 = (int)Math.Floor(newX);
                xf = x0 + 1;
                y0 = (int)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;
                pos0 = (y0 + centerY) * bmpData.Stride + (x0 + centerX) * 4;
                pos1 = (y0 + centerY) * bmpData.Stride + (xf + centerX) * 4;
                pos2 = (yf + centerY) * bmpData.Stride + (x0 + centerX) * 4;
                pos3 = (yf + centerY) * bmpData.Stride + (xf + centerX) * 4;
                //这里本人不知道为什么 pos2 会造成下面索引越界 原因是 yf 算出来是 125 centery也是125 图像是250 高度
                //对哦 假如当作索引 pos2 最大只能是 249 不能 250 但是 上面 Math.Floor 是向下取整啊
                //本人不知道 上面的 x0 + 1 和 yo + 1 是什么意思 莫非js索引是 1 开始的?
                if (pos2 > m_byColorsSrc.Length || pos3 > m_byColorsSrc.Length) {
                    int a = 0;
                    break;//越界本人就跳出了
                    //timer1.Stop();
                    a++;//断掉调试用
                }
                // 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 = (m_byColorsSrc[pos1 + k] - m_byColorsSrc[pos0 + k]) * deltaX + m_byColorsSrc[pos0 + k];
                    // Interpolate the pixels immediately below of (x, y), those are (x, y + 1) and (x + 1, y + 1)
                    componentX1 = (m_byColorsSrc[pos3 + k] - m_byColorsSrc[pos2 + k]) * deltaX + m_byColorsSrc[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
                    byColors[destPosition + k] = (byte)(finalPixelComponent > 255 ? 255 : (finalPixelComponent < 0 ? 0 : finalPixelComponent));
                }
            }
        }
    }
    Marshal.Copy(byColors, 0, bmpData.Scan0, byColors.Length);
    bmpRet.UnlockBits(bmpData);
    return bmpRet;
}
private float m_fC;
private float m_fIncreament = 0.1F;
private void timer1_Tick(object sender, EventArgs e) {
    if (m_fC > 15.0) {
        m_fIncreament = -0.1F;
    }
    if (m_fC <= 1.0) {
        m_fIncreament = 0.1F;
    }
    // Depending on the flag "leftToRight" value, increase/decrease
    // the "step" parameter by a small value at a time
    pictureBox1.Image = this.Animate(m_fC += m_fIncreament);
    Console.WriteLine(m_fC);
}


说实在的 翻译那个代码太痛苦了 很多变量没有用到的 而且很多没有必要的变量 看着一大堆的变量 本人也是有点蒙蔽
所以还是建议  把那两个循环理解一下原理 然后本人写比较靠不
还有一点问题 你本人处理吧
你说你转的有问题 估计是 在取 width 的时候

//destPosition = (y + centerY) * width + x + centerX;
//destPosition *= 4;
destPosition = (y + centerY) * bmpData.Stride + (x + centerX) * 4;

他是用注释的地方地位坐标的
在.NET中用 lockbits 拷贝出来的数组 他的宽度 不是按照 width 来计算 每一行所占用的空间 貌似他会自动补齐 每一行像素所占用的字节数是貌似是4的倍数 所以用Stride来确定每行所占用的像素字节 而不是 y * width * (多少位 / 8) 假如用这种方式 那么数据就错位了


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明怎么转成 C#