0

I'm working on a 2D Graphics Engine, when I use the following code to rotate the images I get 'write access violation' exception for newBits if the image dimensions have even numbers. There is no problem on odd numbered dimensions.

Here is my image rotation code :

bool Graphics::Raster::rotate(float angle)
{
    try {
        unsigned int xOrigin{ mWidth / 2 };
        unsigned int yOrigin{ mHeight / 2 };
        std::array<Math::Vector2D, 4> boundingBoxVertices;
        Math::Matrix2x2               rotationMatrix;

        boundingBoxVertices[0].setX((float)xOrigin * -1.0f);
        boundingBoxVertices[0].setY((float)yOrigin);
        boundingBoxVertices[1].setX((float)(mWidth - xOrigin) * 1.0f);
        boundingBoxVertices[1].setY((float)yOrigin);
        boundingBoxVertices[2].setX((float)(mWidth - xOrigin) * 1.0f);
        boundingBoxVertices[2].setY((float)(mHeight - yOrigin) * -1.0f);
        boundingBoxVertices[3].setX((float)xOrigin * -1.0f);
        boundingBoxVertices[3].setY((float)(mHeight - yOrigin) * -1.0f);

        int x{ 0 }, y{ 0 }, maxX{ 0 }, minX{ 0 }, maxY{ 0 }, minY{ 0 };
        rotationMatrix.setToRotation(angle);
        for (size_t i = 0; i < 4; ++i) {
            boundingBoxVertices[i] *= rotationMatrix;
            boundingBoxVertices[i].round();

            x = (int)boundingBoxVertices[i].getX();
            y = (int)boundingBoxVertices[i].getY();

            if (x < minX) {
                minX = x;
            }

            if (x > maxX) {
                maxX = x;
            }

            if (y < minY) {
                minY = y;
            }

            if (y > maxY) {
                maxY = y;
            }
        }

        size_t newWidth = (size_t)(maxX - minX);
        size_t newHeight = (size_t)(maxY - minY);

        BYTE* newBits{ nullptr };
        if (newBits = new BYTE[newWidth * newHeight * 4]{ 0 }) {
            int newOrgX = newWidth  / 2;
            int newOrgY = newHeight / 2;

            Math::Vector2D pixVec{ 0.0f, 0.0f };
            int oldCoordX{ 0 };
            int oldCoordY{ 0 };
            int newCoordX{ 0 };
            int newCoordY{ 0 };
            unsigned int oldIndex{ 0 };
            unsigned int newIndex{ 0 }; 
            for (size_t i = 0; i < mWidth * mHeight; ++i) {
                oldCoordX = i % mWidth - xOrigin;
                oldCoordY = yOrigin - i / mWidth;

                pixVec.setX((float)oldCoordX);
                pixVec.setY((float)oldCoordY);

                pixVec *= rotationMatrix;
                pixVec.round();

                newCoordX = (unsigned int)(pixVec.getX() + newOrgX);
                newCoordY = (unsigned int)(newOrgY - pixVec.getY());

                oldIndex = i * 4;
                newIndex = (newCoordY * newWidth * 4) + ((newCoordX) * 4);
                
                newBits[newIndex + 0] = m32Bits[oldIndex + 0];
                newBits[newIndex + 1] = m32Bits[oldIndex + 1];
                newBits[newIndex + 2] = m32Bits[oldIndex + 2];
                newBits[newIndex + 3] = m32Bits[oldIndex + 3];
            }

            if (angle != 0.0f  || angle != 90.0f  || angle != 180.0f  || angle != 270.0f  || angle != 360.0f  ||
                angle != -0.0f || angle != -90.0f || angle != -180.0f || angle != -270.0f || angle != -360.0f ) {
                for (size_t i = 0; i < newHeight; ++i) {
                    for (size_t j = 0; j < newWidth; ++j) {
                        if (j != 0 && j != newWidth - 1) {
                            if (newBits[(i * newWidth * 4) + (j * 4) + 0] == 0 &&
                                newBits[(i * newWidth * 4) + (j * 4) + 1] == 0 &&
                                newBits[(i * newWidth * 4) + (j * 4) + 2] == 0 &&
                                newBits[(i * newWidth * 4) + (j * 4) + 3] == 0) {
                                newBits[(i * newWidth * 4) + (j * 4) + 0] = (newBits[(i * newWidth * 4) + ((j - 1) * 4) + 0] + 
                                                                             newBits[(i * newWidth * 4) + ((j + 1) * 4) + 0]) / 2;
                                newBits[(i * newWidth * 4) + (j * 4) + 1] = (newBits[(i * newWidth * 4) + ((j - 1) * 4) + 1] +
                                                                             newBits[(i * newWidth * 4) + ((j + 1) * 4) + 1]) / 2;
                                newBits[(i * newWidth * 4) + (j * 4) + 2] = (newBits[(i * newWidth * 4) + ((j - 1) * 4) + 2] +
                                                                             newBits[(i * newWidth * 4) + ((j + 1) * 4) + 2]) / 2;
                                newBits[(i * newWidth * 4) + (j * 4) + 3] = (newBits[(i * newWidth * 4) + ((j - 1) * 4) + 3] +
                                                                             newBits[(i * newWidth * 4) + ((j + 1) * 4) + 3]) / 2;
                            }
                        }

                    }
                }
            }


            if (set32Bits(newBits, newWidth, newHeight)) {
                delete[] newBits;

                return true;
            } else {
                delete[] newBits;

                return false;
            }
        } else {
            throw Error::Exception(L"Resim çevirme işlemi için hafızada yer açılamadı", L"Resim Düzenleme Hatası");
        }
    } catch (Error::Exception& ex) {
        Error::ShowError(ex.getErrorMessage(), ex.getErrorTitle());

        return false;
    }
}

What am I doing wrong here? I can't use a third-party to rotate the images, I must use this function. Thanks in advance.

Caner Kurt
  • 41
  • 1
  • 6
  • FYI: [SO: Rotate an image in C++ without using OpenCV functions](https://stackoverflow.com/a/56985104/7478597) – Scheff's Cat Dec 10 '20 at 15:53
  • Consider running in the debugger so you can see where the crash happens and examine the variables to see if they make sense. – Retired Ninja Dec 10 '20 at 15:53
  • FYI: `BYTE* newBits{ nullptr }; if (newBits = new BYTE[newWidth * newHeight * 4]{ 0 }) { ... } else {throw ... }` There's no need to do that. `new()` will throw a `std::bad_alloc` on a failed allocation. In any case. `std::vector newBits(newWidth * newHeight * 4);` will do the same thing you are doing, and be safe. – Frank Dec 10 '20 at 16:15

1 Answers1

0

The problem was a index problem when setting the newBits. Here is the updated function :

BYTE* Graphics::RotateBits(const BYTE* bits, const int width, const int height, float angle, int* newWidth, int* newHeight)
{
    try {
        int xOrigin{ width / 2 };
        int yOrigin{ height / 2 };
        std::array<Math::Vector2D, 4> boundingBoxVertices;
        Math::Matrix2x2               rotationMatrix;

        boundingBoxVertices[0].setX((float)xOrigin * -1.0f);
        boundingBoxVertices[0].setY((float)yOrigin);
        boundingBoxVertices[1].setX((float)(width - xOrigin) * 1.0f);
        boundingBoxVertices[1].setY((float)yOrigin);
        boundingBoxVertices[2].setX((float)(width - xOrigin) * 1.0f);
        boundingBoxVertices[2].setY((float)(height - yOrigin) * -1.0f);
        boundingBoxVertices[3].setX((float)xOrigin * -1.0f);
        boundingBoxVertices[3].setY((float)(height - yOrigin) * -1.0f);

        int x{ 0 }, y{ 0 }, maxX{ 0 }, minX{ 0 }, maxY{ 0 }, minY{ 0 };
        rotationMatrix.setToRotation(angle);
        for (int i = 0; i < 4; ++i) {
            boundingBoxVertices[i] *= rotationMatrix;
            boundingBoxVertices[i].round();

            x = (int)boundingBoxVertices[i].getX();
            y = (int)boundingBoxVertices[i].getY();

            if (x < minX) {
                minX = x;
            }

            if (x > maxX) {
                maxX = x;
            }

            if (y < minY) {
                minY = y;
            }

            if (y > maxY) {
                maxY = y;
            }
        }

        *newWidth  = (maxX - minX);
        *newHeight = (maxY - minY);
        BYTE* newBits = new BYTE[*newWidth * *newHeight * 4]{ 0 };
        int newOrgX   = *newWidth / 2;
        int newOrgY   = *newHeight / 2;
        Math::Vector2D pixVec{ 0.0f, 0.0f };
        int oldCoordX{ 0 };
        int oldCoordY{ 0 };
        int newCoordX{ 0 };
        int newCoordY{ 0 };
        int oldIndex{ 0 };
        int newIndex{ 0 };
        for (int i = 0; i < width * height; ++i) {
            oldCoordX = i % width - xOrigin;
            oldCoordY = yOrigin - i / width;

            pixVec.setX((float)oldCoordX);
            pixVec.setY((float)oldCoordY);

            pixVec *= rotationMatrix;
            pixVec.round();

            newCoordX = (int)pixVec.getX() + newOrgX;
            newCoordY = newOrgY - (int)pixVec.getY();

            oldIndex = i * 4;
            newIndex = (newCoordY * *newWidth * 4) + (newCoordX * 4);

            if (newIndex >= 0 && newIndex <= *newWidth * *newHeight * 4 - 4) {
                newBits[newIndex + 0] = bits[oldIndex + 0];
                newBits[newIndex + 1] = bits[oldIndex + 1];
                newBits[newIndex + 2] = bits[oldIndex + 2];
                newBits[newIndex + 3] = bits[oldIndex + 3];
            }
        }

        if (((int)angle) % 90) {
            int index{ 0 };
            int prevIndex{ 0 };
            int nextIndex{ 0 };
            for (int i = 0; i < *newHeight; ++i) {
                for (int j = 0; j < *newWidth; ++j) {
                    if (j != 0 && j != *newWidth - 1) {
                        index = (i * *newWidth * 4) + (j * 4);
                        if (newBits[index + 0] == 0 &&
                            newBits[index + 1] == 0 &&
                            newBits[index + 2] == 0 &&
                            newBits[index + 3] == 0) {
                            prevIndex = (i * *newWidth * 4) + ((j - 1) * 4);
                            nextIndex = (i * *newWidth * 4) + ((j + 1) * 4);
                            newBits[index + 0] = (newBits[prevIndex + 0] + newBits[nextIndex + 0]) / 2;
                            newBits[index + 1] = (newBits[prevIndex + 1] + newBits[nextIndex + 1]) / 2;
                            newBits[index + 2] = (newBits[prevIndex + 2] + newBits[nextIndex + 2]) / 2;
                            newBits[index + 3] = (newBits[prevIndex + 3] + newBits[nextIndex + 3]) / 2;

                        }
                    }

                }
            }
        }

        return newBits;
    } catch (Error::Exception& ex) {
        Error::ShowError(ex.getErrorMessage(), ex.getErrorTitle());

        return nullptr;
    } catch (std::exception& ex) {
        Error::ShowError((LPCWSTR)ex.what(), L"Bit Düzenleme Hatası");

        return nullptr;
    }
}
Caner Kurt
  • 41
  • 1
  • 6