2

I am using a custom class to write an image onto another image of bigger size. Here is the full source code in DotNetFiddle.

My custom GetPixel() works fine. But the following SetPixel() is unable to produce the proper output. Probably, there has been some problems going on with the calculation of addresses. But, I am unable to detect it.

    public void SetPixel(int x, int y, Color color)
    {
        // Get color components count
        int cCount = ColorDepth / 8;
        // Get start index of the specified pixel
        int i = ((y * Width) + x) * cCount;
        //int i = ((x * Width) + y) * cCount;
        if (ColorDepth == 32) // For 32 bpp set Red, Green, Blue and Alpha
        {
            _imageData[i] = color.B;
            _imageData[i + 1] = color.G;
            _imageData[i + 2] = color.R;
            _imageData[i + 3] = color.A;
        }

        if (ColorDepth == 24) // For 24 bpp set Red, Green and Blue
        {
            _imageData[i] = color.B;
            _imageData[i + 1] = color.G;
            _imageData[i + 2] = color.R;
        }
        if (ColorDepth == 8)
        {
            // For 8 bpp set color value (Red, Green and Blue values are the same)
            _imageData[i] = color.B;

            string str = string.Empty;
        }
    }

This is is generating a distorted image:

enter image description here

.

P.S. Here is the input image:

enter image description here

.

.

user366312
  • 16,949
  • 65
  • 235
  • 452
  • "Index out of range" is the clue you get. It is refereing to `_imageData[i]` and has nothing to do with Get/Set pixels, excepting as there is a bug in the code. Since the debugger is already active, take time to inspect the value of `i` and the size of `_imageData`. – user2864740 Aug 05 '16 at 21:38
  • Also, note that `(x * Q) + y` cannot be blindly 'inverted' as `(y * Q) + x` (they will result in a different range), when `y != x`. – user2864740 Aug 05 '16 at 21:41
  • Try resize image with keeping Aspect Ratio: review http://stackoverflow.com/questions/1940581/c-sharp-image-resizing-to-different-size-while-preserving-aspect-ratio – M.Hassan Aug 05 '16 at 23:36

1 Answers1

2
    // Get start index of the specified pixel
    int i = ((y * Width) + x) * cCount;

That is not correct, neither in GetPixel nor SetPixel. You get the skew because you are ignoring Stride. Which are the number of bytes in a single scanline of the image. It is a multiple of 4 to align the pixel data in memory, helps the processor read the data faster. Fix:

    int i = y * Stride + x * cCount;

There is another bug that's hidden in your code, scanlines are stored upside down. In other words, the data for the last scanline is stored first. But only if BitmapData.Height is not negative. Since that bug occurs both in your GetPixel and your SetPixel methods they cancel each other out. Correct code would be (Height - y - 1) * Stride + x * cCount.

This code is not faster than Graphics.DrawImage(), the method you should always prefer.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Please use the provided information to conclude that you did not create the array correctly. Same mistake, you are using Width again instead of Stride. – Hans Passant Aug 08 '16 at 01:12
  • Dear Hans, please see the link. I have used `(Height - y - 1) * Stride + x * cCount`. http://i.imgur.com/MBfMvVh.png – user366312 Aug 08 '16 at 01:19
  • 1
    No, the problem is your `_imageData` **array**, it must of course contain Stride * Height bytes to store the entire bitmap. You are not making it big enough. – Hans Passant Aug 08 '16 at 01:23