I'm trying to flip an image which has its pixels stored in a vector. For some reason, when I try to flip it, the image gets distorted and gray/fuzzy. Any idea why?

My code is as follows:

void JNIData::FlipBytes(void*& Result, bool TopDown)
{
    unsigned char* Pixels = &BufferPixels[0];  //vector of pixels/unsigned chars.
    unsigned char* BuffPos = static_cast<unsigned char*>(Result);

    for (int I = 0; I < height; ++I)
    {
        for (int J = 0; J < width; ++J)
        {
            int Offset = TopDown ? (height - 1 - I) * width + J : I * width + J;
            *(BuffPos++) = *(Pixels++ + Offset);
            *(BuffPos++) = *(Pixels++ + Offset);
            *(BuffPos++) = *(Pixels++ + Offset);

            if (Bpp > 24)
                *(BuffPos++) = *(Pixels++ + Offset);
        }

        if (Bpp == 24)
        {
            BuffPos += width % 4;
            Pixels += width % 4;
        }
    }
}

A few questions:
Are BufferPixels, Bpp, height, and width instance variables? They aren't declared or passed anywhere in the method as shown.

Why couldn't unsigned char* Pixels = &BufferPixels[0]; be written as unsigned char* Pixels = BufferPixels;?

What does Bpp represent? Pixel depth (bits per pixel)? If so, shouldn't the pixels be a 32-bit unsigned, rather than an 8-bit unsigned (even if only 24 bits are actually used at times)? Or is this the reason why you have unrolled the loop by three (or four, in cases where Bpp is greater than 24)?

Why is Result a void pointer?

Do the pixels have to be aligned on word or doubleword boundaries in order to be rendered correctly? Is byte order significant?

  1. BufferPixels is a std::vector<unsigned char> within a class. Private member non-static.
  2. Width and Height are also private non-static class members.
  3. Bpp = BitsPerPixel which can be both 24 or 32.
  4. I used unsigned char* Pixels = &BufferPixels[0] because it's a vector. I would have just used Pixels = BufferPixels.data();
  5. What do you mean 32bit unsigned vs. 8bit unsigned?
  6. I loop through 3 times because if it's 24 bit, alpha doesn't matter. 4 times for 32 bit.
  7. Result is a void pointer because I'm given a void pointer that I will be filling with the flipped Pixels. Ex: I take the vector, flip all the bytes and copy the flipped pixels to the void pointer. The void ptr can also be an unsigned char*.
  8. Well it's for rendering so yes I need to align it to render correctly. I assume I'd need to pad it on 4 byte boundaries and byte order would matter.

I'm basically getting a buffer from JNI (Java) and passing it to my DLL. The DLL fills that buffer with the pixels of an image but sometimes it renders badly and sometimes upside down.

My second attempt to flip it was (I didn't want to use Memcpy):

void JNIData::FlipBytes(void*& Result)
{
   unsigned long Chunk = width * Bpp > 24 ? 4 : 3;
   unsigned char* Destination = static_cast<unsigned char*>(Result);

   unsigned char* Source = &BufferPixels[0] + Chunk * (height - 1);

   for (int I = 0; I < height; ++I)
   {
      std::memcpy(Destination, Source, Chunk);
      Destination += Chunk;
      Source -= Chunk;
   }
}

The above works but it will only render if I fake the image size and make the width and height divisible by 4.

In the function you just posted, you forgot to handle the misalignment at the end of the pixel rows. This should work:

void JNIData::FlipBytes(void*& Result) {
   unsigned long Chunk = (Bpp > 24 ? width * 4 : width * 3 + width % 4);
   unsigned char* Destination = static_cast<unsigned char*>(Result);

   unsigned char* Source = &BufferPixels[0] + Chunk * (height - 1);

   while(Source != &BufferPixels[0]) {
      std::memcpy(Destination, Source, Chunk);
      Destination += Chunk;
      Source -= Chunk;
   }
}

As for the earlier version (in original post), I would just forget about it. The monkey business with this line:

int Offset = TopDown ? (height - 1 - I) * width + J : I * width + J;

looks very suspicious to me. If anything, you should probably use a strategy similar to that of the other version, i.e., go backwards in the source image, and forward in the destination image.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.