在画布中旋转imageData

时间:2012-10-12 10:45:25

标签: javascript html5 html5-canvas

好吧,我想我必须更清楚地说明这一点:)

我的代码适用于方形图像,但它对矩形图像无效。 我认为这是因为imageData.width和imageData.height仍然相同,无法更改。

你们知道我怎么能这样做吗?

var canvas = document.getElementById("canvas0calc");
var ctx  = canvas.getContext('2d');

var objImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

// swap canvas size
var temp = canvas.width;
canvas.width = canvas.height;
canvas.height = temp;


//create new Array for Data
var newImageData = new Array(objImageData.height);
for (var k = 0; k < newImageData.length; k++) {
    newImageData[k] = new Array(objImageData.width);
}

//the actual matrix-rotate algorithm which is working perfectly
for (var i = 0; i < objImageData.height; i++) {
    for (var j = 0; j < objImageData.width; j++) {
        newImageData[i][j] = [objImageData.data[((i*(objImageData.width*4)) + ((objImageData.width - j - 1)*4))], objImageData.data[((i*(objImageData.width*4)) + ((objImageData.width - j - 1)*4)) + 1],objImageData.data[((i*(objImageData.width*4)) + ((objImageData.width - j - 1)*4)) + 2],objImageData.data[((i*(objImageData.width*4)) + ((objImageData.width - j - 1)*4)) + 3]];
    }
}

var resultArray = new Array(objImageData.width * objImageData.height * 4);
var count = 0;
for (var y = 0; y < newImageData.length; y++) {
    for (var x = 0; x < newImageData[0].length; x++) {
        for (var z = 0; z < 4; z++) {
            resultArray[count++] = newImageData[x][y][z];
        }
    }
}

for (var u = 0; u < objImageData.data.length; u++) {
    objImageData.data[u] = resultArray[u];
}

ctx.putImageData(objImageData, 0, 0);

1 个答案:

答案 0 :(得分:3)

除了交换宽度和高度值之外,还有更多内容!如果我拿一个正方形然后旋转45°,然后交换宽度和高度将什么都不做 - 图像实际上是以前的宽度和高度的sqrt(2)倍(从一个对角线到另一个对角线的长度是sqrt (1 ^ 2 + 1 ^ 2)乘以相邻角之间的长度。重点是,您需要比简单交换更好地计算新图像尺寸。

我似乎无法像10年或15年前那样轻松地在网络上找到图像旋转例程 - 这是我们现在拥有的所有快速图形硬件,这使得它可以满足很多人的需求。 / p>

目前还不清楚你是想旋转90°,180°还是270° - 我怀疑是通过宽度和高度的简单交换,但我无法确定。如果是这样,请在此处查看此文章:http://www.codeproject.com/Articles/21446/Fast-Image-Rotation-For-NET-Compact-Framework

但是,如果你想以任意角度旋转,请继续阅读。

我意识到它是C而你正在使用javascript - 但无论如何,旋转数学是一样的,只需忽略/使用等效的javascript函数。

// RotateMemoryDC rotates a memory DC and returns the rotated DC as well as its dimensions
HBITMAP RotateMemoryDC(HBITMAP hBmpSrc, float angleDeg)
{
    HBITMAP hBmpDst;
    float x1, x2, x3, x4, y1, y2, y3, y4, cA, sA;
    float CtX, CtY, orgX, orgY, divisor;
    int OfX, OfY;
    int stepX, stepY;
    int iorgX, iorgY;
    RECT rt;
    pBGR src, dst, dstLine;
    BITMAPINFO bi;
    // my edits
    BITMAP bm;
    int SrcX, SrcY, dstX, dstY;     // were input variables, with the & symbol in front of them (input/output vars)\

    HDC hdcSrc, hdcDst, hdcScreen;

    HBITMAP oldDstBmp, oldSrcBmp;

    GetObject(hBmpSrc, sizeof(bm), &bm);
    SrcX = bm.bmWidth;
    SrcY = bm.bmHeight;

    // Rotate the bitmap around the center
    CtX = ((float) SrcX) / 2;
    CtY = ((float) SrcY) / 2;

    // First, calculate the destination positions for the four courners to get dstX and dstY
    float angleRad = angleDeg * 3.1415926 / 180.0;
    cA = (float) cos(angleRad);
    sA = (float) sin(angleRad);

    x1 = CtX + (-CtX) * cA - (-CtY) * sA;
    x2 = CtX + (SrcX - CtX) * cA - (-CtY) * sA;
    x3 = CtX + (SrcX - CtX) * cA - (SrcY - CtY) * sA;
    x4 = CtX + (-CtX) * cA - (SrcY - CtY) * sA;

    y1 = CtY + (-CtY) * cA + (-CtX) * sA;
    y2 = CtY + (SrcY - CtY) * cA + (-CtX) * sA;
    y3 = CtY + (SrcY - CtY) * cA + (SrcX - CtX) * sA;
    y4 = CtY + (-CtY) * cA + (SrcX - CtX) * sA;

    OfX = ((int) floor(min4(x1, x2, x3, x4)));
    OfY = ((int) floor(min4(y1, y2, y3, y4)));

    dstX = ((int) ceil(max4(x1, x2, x3, x4))) - OfX;
    dstY = ((int) ceil(max4(y1, y2, y3, y4))) - OfY;

    // Create the new memory DC
    hdcScreen = GetDC(NULL);
    hdcDst = CreateCompatibleDC(hdcScreen);
    hdcSrc = CreateCompatibleDC(hdcScreen);
    hBmpDst = CreateCompatibleBitmap(hdcScreen, dstX, dstY);
    oldDstBmp = (HBITMAP)SelectObject(hdcDst, hBmpDst);
    oldSrcBmp = (HBITMAP)SelectObject(hdcSrc, hBmpSrc);

    // Fill the new memory DC with the current Window color
    rt.left = 0;
    rt.top = 0;
    rt.right = dstX;
    rt.bottom = dstY;
    HBRUSH redBrush = CreateSolidBrush(RGB(255,0,0));

    FillRect(hdcDst, &rt, redBrush);
    DeleteObject(redBrush);

    // Get the bitmap bits for the source and destination
    src = MyGetDibBits(hdcSrc, hBmpSrc, SrcX, SrcY);
    dst = MyGetDibBits(hdcDst, hBmpDst, dstX, dstY);

    dstLine = dst;
    divisor = cA*cA + sA*sA;
    // Step through the destination bitmap
    for (stepY = 0; stepY < dstY; stepY++)
    {
        for (stepX = 0; stepX < dstX; stepX++)
        {
            // Calculate the source coordinate
            orgX = (cA * (((float) stepX + OfX) + CtX * (cA - 1)) + sA * (((float) stepY + OfY) + CtY * (sA - 1))) / divisor;
            orgY = CtY + (CtX - ((float) stepX + OfX)) * sA + cA *(((float) stepY + OfY) - CtY + (CtY - CtX) * sA);
            iorgX = (int) orgX;
            iorgY = (int) orgY;
            if ((iorgX >= 0) && (iorgY >= 0) && (iorgX < SrcX) && (iorgY < SrcY))
            {
                // Inside the source bitmap -> copy the bits
                dstLine[dstX - stepX - 1] = src[iorgX + iorgY * SrcX];
            }
            else
            {
                // Outside the source -> set the color to light grey
                //  dstLine[dstX - stepX - 1].b = 240;
                //  dstLine[dstX - stepX - 1].g = 20;
                //  dstLine[dstX - stepX - 1].r = 240;
            }
        }
        dstLine = dstLine + dstX;
    }

    // Set the new Bitmap
    bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
    bi.bmiHeader.biWidth = dstX;
    bi.bmiHeader.biHeight = dstY;
    bi.bmiHeader.biPlanes = 1;
    bi.bmiHeader.biBitCount = 32;
    bi.bmiHeader.biCompression = BI_RGB;
    bi.bmiHeader.biSizeImage = dstX * 4 * dstY;
    bi.bmiHeader.biClrUsed = 0;
    bi.bmiHeader.biClrImportant = 0;
    SetDIBits(hdcDst, hBmpDst, 0, dstY, dst, &bi, DIB_RGB_COLORS);

    // Free the color arrays
    free(src);
    free(dst);
    SelectObject(hdcSrc, oldSrcBmp);
    SelectObject(hdcDst, oldDstBmp);
    ReleaseDC(NULL, hdcScreen);
    DeleteDC(hdcSrc);
    DeleteDC(hdcDst);
    return hBmpDst;
}