trenmost's picture

Copy screen to byte[] array

Hi! I'm using c#, and i would like to copy my screen content to a byte array:

byte[] image = new byte[resX * resY];
            GL.ReadPixels(0, 0, resX, resY, PixelFormat.Bgr, PixelType.Byte, image);

I tried it with this method, but when the program gets at the GL.ReadPixels method, i get an error message of: "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

what am i doing wrong?
:)


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

PixelFormat.Bgr requires 3 bytes per pixel, so your byte array should have a size of resX * resY * 3.

Consider using PixelFormat.Bgra and resX * resY * 4 for better performance.

trenmost's picture

actually i only need the Red component of the image. so if i use PixelFormat.Red, then is the resx*resy sized buffer enough?

the Fiddler's picture

Yes, that would be enough (but it might still be faster to use Bgra and only read every fourth element - you'd have to measure, provided performance is a concern).

trenmost's picture

yeah but it would be worse memory wise. im not even drawing the image to the screen actually, i just use openGL's fast shape-to-pixel conversion, and then get back the data :)

note: i tried using the PixelFormat.Red, but sometimes it gives this memory error even now! :( but sometimes it works...

the Fiddler's picture

I have been using this method for years without issue. Is this the exact code you are using?

trenmost's picture

yes. in this function im drawing a custom class (Shape), which holds points and some extra data as follows:

int resX = (int)Math.Ceiling(size[0] * resolution), resY = (int)Math.Ceiling(size[1] * resolution);
 
            OpenTK.GLControl glcontrol = new OpenTK.GLControl();
            glcontrol.SetBounds(0, 0, resX, resY);
            glcontrol.MakeCurrent();
            GL.Viewport(0, 0, resX, resY);
            GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
            GL.Clear(ClearBufferMask.ColorBufferBit);
            GL.Color3(1.0f, 1.0f, 0.0f);
            GL.LineWidth(1.0f);
            for (int i = 0; i < A.getPointCount() - 1; i++)
            {
                GL.Begin(BeginMode.Lines);
                {
                    GL.Vertex2(A.getPoint(0, i) / size[0], A.getPoint(1, i) / size[1]); //point(i)
                    GL.Vertex2(A.getPoint(0, i + 1) / size[0], A.getPoint(1, i + 1) / size[1]); //point(i+1)
                }
                GL.End();
             }
 
             byte[] image = new byte[resX * resY];
            GL.ReadPixels(0, 0, resX, resY, PixelFormat.Red, PixelType.Byte, image);
 

this works perfectly when sometimes, but sometimes it doesnt..
by distortion i mean: lets call the first row of the image 0, the second row: 1, third row: 2 etc.
the image looks like if every row was shifted with i, where i is the index of the row (0,1,2...)
oh and i have to allocate more space for the image array, because of the distortion, or else i get this corrupted memory error!

smiley80's picture

OpenGL aligns rows to 4-byte boundaries by default. Which means there are some empty padding bytes at the end of a row, if resX * byte size of the pixelformat isn't a multiple of 4. So you have to set the array size like this:

byte[] image = new byte[GetStride(8, resX) * resY];
 
public static int GetStride(int bitCount, int width)
{
	return (int)(Math.Ceiling(width * bitCount / 32f) * 4);
}
trenmost's picture

wow...that'll be the problem! i'll implement this, but thanks a lot!!!! :)

trenmost's picture

It was the problem! but instead of using that GetStride, i expanded the resolution to the next number which is a multiple of 4 by using this code:

(...)
            int resX = (int)Math.Ceiling(size[0] * resolution), resY = (int)Math.Ceiling(size[1] * resolution);
            resX += 4 - (resX % 4);
            resY += 4 - (resY % 4);
(...)

(i could do this because im not drawing this image to the screen, im just using its data).

Thank you smiley80! :)