1

好的,我想我必须说得更清楚:)

我的代码适用于方形图像,但它对矩形图像没有任何作用。我认为这是因为 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);
4

1 回答 1

3

它不仅仅是交换宽度和高度值!如果我取一个正方形,然后将其旋转 45°,然后交换宽度和高度将无济于事 - 图像实际上是 sqrt(2) 的宽度和高度的两倍(从一个对角角到另一个对角线的长度是 sqrt ( 1^2 + 1^2) 乘以相邻角之间的长度。关键是,您需要比简单的交换更好地计算新的图像尺寸。

我似乎无法像 10 或 15 年前那样轻松地在网上找到图像旋转例程 - 正是我们现在拥有的所有快速图形硬件使得它对于很多人的需求来说是多余的。

目前尚不清楚您是否想旋转 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;
}
于 2012-10-12T14:23:28.367 回答