Two Different GCHandle's refer to same array in memory - c#

This is probably not a well-phrased question, because I am not sure what is happenning, so i don't know how to ask it pointedly. I am trying to learn, and i hope i can get some direction on this. Your patience with a neophyte is appreciated.
I have a piece of code i am modifying. It displays an image. I want to modify the image, and display it in a different window. I copy the code that displays the image, do the modification, and it displays the modified image for both the original and modified images.
It seems GCHandle keeps referring to the same memory? Am i not really making a new handle by changing the handle name? Sorry for the long piece of code, but i am just lost.
What is going wrong?
Most perplexing is that it was working, then i changed something, and now can't get back to the working version, tho i think my code is the same as the one that worked. Some setting some where?
System.Runtime.InteropServices.GCHandle gch3 = System.Runtime.InteropServices.GCHandle.Alloc(scaled, System.Runtime.InteropServices.GCHandleType.Pinned);
int pitch = mImageWidth;
if (pitch % 4 != 0)
pitch = ((pitch / 4) + 1) * 4;
System.Drawing.Bitmap bitmap = new Bitmap(mImageWidth, mImageHeight, pitch, System.Drawing.Imaging.PixelFormat.Format8bppIndexed, gch3.AddrOfPinnedObject());
gch3.Free();
if (pal == null)
{
System.Drawing.Imaging.ColorPalette cp = bitmap.Palette;
for (i = 0; i < cp.Entries.Length; ++i)
{
cp.Entries[i] = Color.FromArgb(i, i, i);
}
pal = cp;
}
bitmap.Palette = pal;
FirstImageDisplay.Image = bitmap;
//second image here
for (i = 0; i < frame.Length; ++i)
scaled[i] = (byte)(.5 * scaled[i]);
System.Runtime.InteropServices.GCHandle gch4 = System.Runtime.InteropServices.GCHandle.Alloc(scaled, System.Runtime.InteropServices.GCHandleType.Pinned);
int pitch1 = mImageWidth;
if (pitch1 % 4 != 0)
pitch1 = ((pitch1 / 4) + 1) * 4;
System.Drawing.Bitmap bitmap2 = new Bitmap(mImageWidth, mImageHeight, pitch, System.Drawing.Imaging.PixelFormat.Format8bppIndexed, gch4.AddrOfPinnedObject());
gch4.Free();
if (pal == null)
{
System.Drawing.Imaging.ColorPalette cp = bitmap.Palette;
for (i = 0; i < cp.Entries.Length; ++i)
{
cp.Entries[i] = Color.FromArgb(i, i, i);
}
pal = cp;
}
bitmap.Palette = pal;
SecondImageDisplay.Image = bitmap;
//end second image code

What you're doing definitely isn't safe. Why are you doing this? Is there a reason you're so comfortable leaving the safe, managed environment?
The bitmap is created around that byte[]. This is okay as long as you don't mind having a pinned byte[] in the managed memory (okay for a few moments, not really for the duration of the application etc.). However, on the very next line, you release the pointer!
Then you use the same byte[], modify it, and use it for another bitmap. Boom, it's still the same byte array. It shouldn't be surprising that both bitmaps have the same content - you asked for that.
The reason why it sometimes works and sometimes it doesn't is that if the handle isn't moved by the GC, both bitmaps will be correct. However, if the GC moves the byte array, the Bitmaps have no way of adjusting - they will still point to the same location in memory (which is now wrong).
What you have to understand is that a GCHandle doesn't create a new object. It just instructs the GC not to mess with the physical location (well, in virtual memory, but...) as long as the GCHandle exists. If you want to create a new object, do something like byte[].Clone(). However, you're still going to have to have the handle pinned for all the lifetime of the Bitmap, which is usually a bad idea. Instead, try creating the Bitmap the usual way, then doing Bitmap.LockBits, then use Marshal.Copy to copy the bitmap array to the unmanaged memory of the Bitmap, and you're done, nice and relatively safe.
Here's a code snippet that illustrates the whole concept:
byte[] data = new byte[320 * 200 * 1];
Bitmap bmp1 = new Bitmap(320, 200,
System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
Bitmap bmp2 = new Bitmap(320, 200,
System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
var bdata = bmp1.LockBits(new Rectangle(new Point(0, 0), bmp1.Size),
ImageLockMode.WriteOnly, bmp1.PixelFormat);
try
{
Marshal.Copy(data, 0, bdata.Scan0, data.Length);
}
finally
{
bmp1.UnlockBits(bdata);
}
// Do your modifications
bdata = bmp2.LockBits(new Rectangle(new Point(0, 0), bmp2.Size),
ImageLockMode.WriteOnly, bmp2.PixelFormat);
try
{
Marshal.Copy(data, 0, bdata.Scan0, data.Length);
}
finally
{
bmp2.UnlockBits(bdata);
}
This isn't the best code performance-wise (it does need some copying), but the only real alternative is to use unsafe code - which you really shouldn't be doing, given your current apparent knowledge about the managed environment. It can lead to some nasty issues if you don't use it properly. In any case, the performance gains might be quite negligible - find out if you actually care before you go the unsafe way.
For more information about the problem and the complexities of working with managed and unmanaged memory, you can have a look at my blog at http://www.luaan.cz/2014/07/a-quick-introduction-to-managed-and.html It's still rather high-level, but it explains more than this answer on its own.

Related

Fo-Dicom Window Change is slow

I am using the following render code. This is a slightly modified code because, in the actual code, I am getting all the files from the FTP server. CurrentWindowCenter and CurrentWindowWidth hold the current value of WL and WW. This value can be changed from the UI. I am showing the rendered WritableBitmap directly to the user using an image component inside a canvas.
But the rendering of the image is very slow. Especially for images with large file sizes such as X-Ray. So, the WW and WL change is also very slow since it also uses the render function.
I am not very knowledgeable about this. But is there a way to make the rendering or WW/WL change faster? Is there a way to skip the rendering of the image every time a WW/WL change happens?
Any advice in the right direction is appreciated.
Thanks in advance.
// assume filePath holds an actual file location.
var filePath = "";
var dicomFile = new DicomFile.Open(filePath);
var dicomImage = new DicomImage(dicomFile.DataSet);
if (CurrentWindowCenter.HasValue && CurrentWindowWidth.HasValue)
{
dicomImage.WindowCenter = Convert.ToDouble(CurrentWindowCenter.Value);
dicomImage.WindowWidth = Convert.ToDouble(CurrentWindowWidth.Value);
}
dicomImage.RenderImage().AsWriteableBitmap();
Environment
Fo-Dicom (4.0.8)
.NET Framework 4.8
WPF
My guess is that fo-dicom is not really intended for high performance and more for compatibility. For best performance you should probably use the GPU via DirectX, OpenCL or similar. Second best should be some tightly optimized SIMD code, probably using c++.
But there might be some improvements to be had using just c#. From the looks of it fo-dicom creates a new image, copies pixels to this image, and then creates a writeableBitmap and does another copy. These step will take some extra time.
My code for copying pixels and applying a lut/transfer function look like this:
public static unsafe void Mono16ToMono8(
byte* source,
byte* target,
int sourceStride,
int targetStride,
int width,
int height,
byte[] lut)
{
Parallel.For(0, height, y =>
{
var ySource = source + y * sourceStride;
var yTarget = target + y * targetStride;
var srcUshort = (ushort*)ySource;
for (int x = 0; x < width; x++)
{
var sample = srcUshort[x];
yTarget[x] = lut[sample];
}
});
}
And the code to do the actual update of the writeable bitmap:
public static unsafe void Update(
this WriteableBitmap self,
IImage source,
byte[] lut)
{
self.Lock();
try
{
var targetPtr = (byte*)self.BackBuffer;
fixed (byte* sourcePtr = source.Data)
{
if (source.PixelFormat == PixelType.Mono16)
{
Mono16ToMono8(
sourcePtr,
targetPtr,
source.Stride,
self.BackBufferStride,
source.Width,
source.Height,
lut);
}
}
self.AddDirtyRect(new Int32Rect(0, 0, (int)self.Width, (int)self.Height));
}
finally
{
self.Unlock();
}
}
This uses an internal IImage format, where source.Data is a ReadOnlySpan<byte>, but could just as well be a byte[]. I hope most of the other properties are self-explanatory. I would expect this code to be a bit faster since it avoids both allocations and some copying steps.
All of this assumes the image is in 16-bit unsigned format, that is common for dicom, but not the only format. It also assumes you can actually get a hold of a pointer to the actual pixel-buffer, and an array of the lut that maps each possible pixelvalue to a byte. It also assumes a writeablebitmap of the correct size and color space.
And as previously mentioned, if you want both high performance, and handle all possible image formats, you might need to invest time to build your own image rendering pipeline.

SkiaSharp Tiff support

Currently, SkiaSharp doesn't support tiff images. (It supports jpg, gif, bmp, png, and a few others.)
How can you convert a tiff image into a SKBitmap object?
One idea: Perhaps there's an efficient way to convert a tiff stream > png stream > SKBitmap object? I'm not sure System.Drawing could handle the tiff>png stream efficiently. Another possible option is LibTiff.Net, though would need an example of how to convert a tiff stream to a png stream.
Another idea: Access the tiff pixels and draw it directly onto a SKCanvas?
Other ideas?
#DougS
Your implementation is mostly correct, but it is not very performant because of multiple memory allocations and copies.
I noticed that you are creating 3 memory chunks with a total size of (w*h*4 bytes) each:
// the int[]
raster = new int[width * height];
// the SKColor[]
pixels = new SKColor[width * height];
// the bitmap
bitmap = new SKBitmap(width, height)
You are also copying the pixels between the memory multiple times:
// decode the TIFF (first copy)
tifImg.ReadRGBAImageOriented(width, height, raster, Orientation.TOPLEFT)
// convert to SKColor (second copy)
pixels[arrayOffset] = new SKColor(...);
// set bitmap pixels (third copy)
bitmap.Pixels = pixels;
I think I managed to create a similar method that decodes the stream, with only a single copy and memory allocation:
public static SKBitmap OpenTiff(Stream tiffStream)
{
// open a TIFF stored in the stream
using (var tifImg = Tiff.ClientOpen("in-memory", "r", tiffStream, new TiffStream()))
{
// read the dimensions
var width = tifImg.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
var height = tifImg.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
// create the bitmap
var bitmap = new SKBitmap();
var info = new SKImageInfo(width, height);
// create the buffer that will hold the pixels
var raster = new int[width * height];
// get a pointer to the buffer, and give it to the bitmap
var ptr = GCHandle.Alloc(raster, GCHandleType.Pinned);
bitmap.InstallPixels(info, ptr.AddrOfPinnedObject(), info.RowBytes, null, (addr, ctx) => ptr.Free(), null);
// read the image into the memory buffer
if (!tifImg.ReadRGBAImageOriented(width, height, raster, Orientation.TOPLEFT))
{
// not a valid TIF image.
return null;
}
// swap the red and blue because SkiaSharp may differ from the tiff
if (SKImageInfo.PlatformColorType == SKColorType.Bgra8888)
{
SKSwizzle.SwapRedBlue(ptr.AddrOfPinnedObject(), raster.Length);
}
return bitmap;
}
}
A gist lives here: https://gist.github.com/mattleibow/0a09babdf0dc9d2bc3deedf85f9b57d6
Let me explain the code... I basically am creating the int[] as you are, but then passing that to the SKBitmap and letting it take over. I am pinning it as the SKBitmap lives in unmanaged memory and the GC may move it, but I am sure to unpin it when the bitmap is disposed.
Here is a more detailed step through:
// this does not actually allocate anything
// - the size is 0x0 / 0 bytes of pixels
var bitmap = new SKBitmap();
// I create the only buffer for pixel data
var raster = new int[width * height];
// pin the managed array so it can be passed to unmanaged memory
var ptr = GCHandle.Alloc(raster, GCHandleType.Pinned);
// pass the pointer of the array to the bitmap
// making sure to free the pinned memory in the dispose delegate
// - this is also not an allocation, as the memory already exists
bitmap.InstallPixels(info, ptr.AddrOfPinnedObject(), info.RowBytes, null, (addr, ctx) => ptr.Free(), null);
// the first and only copy from the TIFF stream into memory
tifImg.ReadRGBAImageOriented(width, height, raster, Orientation.TOPLEFT)
// an unfortunate extra memory operation for some platforms
// - this is usually just for Windows as it uses a BGR color format
// - Linux, macOS, iOS, Android all are RGB, so no swizzle is needed
SKSwizzle.SwapRedBlue(ptr.AddrOfPinnedObject(), raster.Length);
Just for some raw stats from a debug session, your code takes about 500ms for one of my images, but my code only takes 20ms.
I hope I don't sound too harsh/negative towards your code, I am not meaning that in any way.
I'm no expert, so I welcome any expert who can make this code more efficient (or has completely different ideas to get a tiff into a SKBitmap).
This uses LibTiff.Net
using BitMiracle.LibTiff.Classic;
. . . .
public static void ConvertTiffToSKBitmap(MemoryStream tifImage)
{
SKColor[] pixels;
int width, height;
// open a Tiff stored in the memory stream, and grab its pixels
using (Tiff tifImg = Tiff.ClientOpen("in-memory", "r", tifImage, new TiffStream()))
{
FieldValue[] value = tifImg.GetField(TiffTag.IMAGEWIDTH);
width = value[0].ToInt();
value = tifImg.GetField(TiffTag.IMAGELENGTH);
height = value[0].ToInt();
// Read the image into the memory buffer
int[] raster = new int[width * height];
if (!tifImg.ReadRGBAImageOriented(width, height, raster, Orientation.TOPLEFT))
{
// Not a valid TIF image.
}
// store the pixels
pixels = new SKColor[width * height];
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int arrayOffset = y * width + x;
int rgba = raster[arrayOffset];
pixels[arrayOffset] = new SKColor((byte)Tiff.GetR(rgba), (byte)Tiff.GetG(rgba), (byte)Tiff.GetB(rgba), (byte)Tiff.GetA(rgba));
}
}
}
using (SKBitmap bitmap = new SKBitmap(width, height))
{
bitmap.Pixels = pixels;
// do something with the SKBitmap
}
}

Unusual Physical memory usage when huge number of bitmap images are created and saved as one bit per pixel image

I am trying to create large number of 1 bit per pixel bmp image from base 64 string and saving. As per the requirement a very huge number of images being created in a short period of time( an average of 50,000 to 1,00,000 in a short duration). I am using the below code.
public void CreateoneBppImageAndSave(String base64ImageString,String ImagePathToSave)
{
byte[] byteArray = Convert.FromBase64String(base64ImageString);
System.Drawing.Image img = byteArrayToImage(byteArray);
Bitmap objBitmap = new Bitmap(img);
BitmapData bmpData = objBitmap.LockBits(new Rectangle(0, 0, objBitmap.Width, objBitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format1bppIndexed);
Bitmap oneBppBitmap = new Bitmap(objBitmap.Width, objBitmap.Height, bmpData.Stride, System.Drawing.Imaging.PixelFormat.Format1bppIndexed, bmpData.Scan0);
oneBppBitmap.Save(ImagePathToSave, ImageFormat.Bmp);
img.Dispose();
objBitmap.Dispose();
objBitmap.UnlockBits(bmpData);
oneBppBitmap.Dispose();
}
private Image byteArrayToImage(byte[] byteArrayIn)
{
using (MemoryStream ms = new MemoryStream(byteArrayIn))
{
return Image.FromStream(ms);
}
}
Here the physical memory usage going very high. Usually the images are generated with size of 200x200 to 754x1024 . After certain duration physical memory usage reaching to the extreme and out of memory exception is being thrown.The physical memory is getting increased by 0.01 GB by every 5-10 seconds. Please help me to optimize the code in terms of memory usage.
You call LockBits on objBitmap however you call UnlockBits on oneBppBitmap. You should be calling unlock on the same object you called lock on.
As for using statements like I mentioned in the comments, a using statement turns this
using(SomeType obj = new SomeType())
{
// Some code
}
in to the equivalent of this
SomeType obj = new SomeType())
try
{
// Some code
}
finally
{
obj.Dispose();
}
That guarantees that even if a exception is thrown in // Some Code the dispose action will still happen. Your code, as it is right now, will not dispose any of its objects if any of your functions between the creation and dispose throws an exception.
Here is a re-written version with all the corrections I mentioned plus a few others..
public void CreateoneBppImageAndSave(String base64ImageString,String ImagePathToSave)
{
byte[] byteArray = Convert.FromBase64String(base64ImageString);
using(Image img = byteArrayToImage(byteArray))
using(Bitmap objBitmap = new Bitmap(img))
{
BitmapData bmpData = objBitmap.LockBits(new Rectangle(0, 0, objBitmap.Width, objBitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format1bppIndexed);
try
{
using(Bitmap oneBppBitmap = new Bitmap(objBitmap.Width, objBitmap.Height, bmpData.Stride, System.Drawing.Imaging.PixelFormat.Format1bppIndexed, bmpData.Scan0))
{
oneBppBitmap.Save(ImagePathToSave, ImageFormat.Bmp);
}
}
finally
{
//put the unlock in a finally to make sure it happens.
objBitmap.UnlockBits(bmpData);
}
}
}
EDIT: If this really is in your code
objBitmap.Dispose();
objBitmap.UnlockBits(bmpData);
That is the source of your problem, you should not call any methods on a class after you dispose. That is another benefit of using, you can't call methods late because the variable goes out of scope when you leave the using block.

Fast way to compare 2 byte arrays

I am uploading jpeg images as fast as i can to a web service (it is the requirement I have been given).
I am using async call to the web service and I calling it within a timer.
I am trying to optimise as much as possible and tend to use an old laptop for testing. On a normal/reasonable build PC all is OK. On the laptop I get high RAM usage.
I know I will get a higher RAM usage using that old laptop but I want to know the lowest spec PC the app will work on.
As you can see in the code below I am converting the jpeg image into a byte array and then I upload the byte array.
If I can reduce/compress/zip the bye array then I am hoping this will be 1 of the ways of improving memory usage.
I know jpegs are already compressed but if I compare the current byte array with the previous byre array then uploading the difference between this byte arrays I could perhaps compress it even more on the basis that some of the byte values will be zero.
If I used a video encoder (which would do the trick) I would not be real time as much I would like.
Is there an optimum way of comparing 2 byte arrays and outputting to a 3rd byte array? I have looked around but could not find an answer that I liked.
This is my code on the client:
bool _uploaded = true;
private void tmrLiveFeed_Tick(object sender, EventArgs e)
{
try
{
if (_uploaded)
{
_uploaded = false;
_live.StreamerAsync(Shared.Alias, imageToByteArray((Bitmap)_frame.Clone()), Guid.NewGuid().ToString()); //web service being called here
}
}
catch (Exception _ex)
{
//do some thing but probably time out error here
}
}
//web service has finished the client invoke
void _live_StreamerCompleted(object sender, AsyncCompletedEventArgs e)
{
_uploaded = true; //we are now saying we start to upload the next byte array
}
private wsLive.Live _live = new wsLive.Live(); //web service
private byte[] imageToByteArray(Image imageIn)
{
MemoryStream ms = new MemoryStream();
imageIn.Save(ms,System.Drawing.Imaging.ImageFormat.Jpeg); //convert image to best image compression
imageIn.Dispose();
return ms.ToArray();
}
thanks...
As C.Evenhuis said - JPEG files are compressed, and changing even few pixels results in complettly differrent file. So - comparing resulting JPEG files is useless.
BUT you can compare your Image objects - quick search results in finding this:
unsafe Bitmap PixelDiff(Bitmap a, Bitmap b)
{
Bitmap output = new Bitmap(a.Width, a.Height, PixelFormat.Format32bppArgb);
Rectangle rect = new Rectangle(Point.Empty, a.Size);
using (var aData = a.LockBitsDisposable(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb))
using (var bData = b.LockBitsDisposable(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb))
using (var outputData = output.LockBitsDisposable(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb))
{
byte* aPtr = (byte*)aData.Scan0;
byte* bPtr = (byte*)bData.Scan0;
byte* outputPtr = (byte*)outputData.Scan0;
int len = aData.Stride * aData.Height;
for (int i = 0; i < len; i++)
{
// For alpha use the average of both images (otherwise pixels with the same alpha won't be visible)
if ((i + 1) % 4 == 0)
*outputPtr = (byte)((*aPtr + *bPtr) / 2);
else
*outputPtr = (byte)~(*aPtr ^ *bPtr);
outputPtr++;
aPtr++;
bPtr++;
}
}
return output;
}
If your goal is to find out whether two byte arrays contain exactly the same data, you can create an MD5 hash and compare these as others have suggested. However in your question you mention you want to upload the difference which means the result of the comparison must be more than a simple yes/no.
As JPEGs are already compressed, the smallest change to the image could lead to a large difference in the binary data. I don't think any two JPEGs contain binary data similar enough to easily compare.
For BMP files you may find that changing a single pixel affects only one or a few bytes, and more importantly, the data for the pixel at a certain offset in the image is located at the same position in both binary files (given that both images are of equal size and color depth). So for BMPs the difference in binary data directly relates to the difference in the images.
In short, I don't think obtaining the binary difference between JPEG files will improve the size of the data to be sent.

OpenGL: glReadPixels "fails" although glGetError returns 0

Problem summary:
I use OpenGL glReadPixels to get a screenshot but the buffer is unchanged.
If I use glGetError to get the error from the last function, it returns 0, as if everything is fine.
I've researched online throughly and haven't found anyone facing a problem as this one.
In details:
I'm using the CsGL.dll, which basically just wraps OpenGL to C#, and I have made the required initializations for using GL:
DC from hWnd, ChoosePixelFormat for DC using PixelFormatDescriptor and setting the it as it's format, creating RC for the DC and calling wglMakeCurrent(RC, DC).
Note that I am using simple wrappers for the Windows API functions.
Here is the code for this initialization I have used:
public unsafe void Init(IntPtr hWnd)
{
this.DC = (IntPtr)User.GetDC(this.HWnd = hWnd);
var pfd = new PIXELFORMATDESCRIPTOR();
var sizeOf = Marshal.SizeOf(pfd);
Kernel.ZeroMemory(new IntPtr(&pfd), sizeOf);
pfd.nSize = (short)sizeOf;
pfd.nVersion = 1;
pfd.dwFlags = (int)(PixelFormatDescriptorFlagsEnum.PFD_DRAW_TO_WINDOW |
PixelFormatDescriptorFlagsEnum.PFD_SUPPORT_OPENGL |
PixelFormatDescriptorFlagsEnum.PFD_DOUBLEBUFFER);
pfd.iPixelType = PIXELFORMATDESCRIPTOR.PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PIXELFORMATDESCRIPTOR.PFD_MAIN_PLANE;
var iFormat = GDI.ChoosePixelFormat(this.DC, ref pfd);
GDI.SetPixelFormat(this.DC, iFormat, ref pfd);
this.RC = wglCreateContext(this.DC);
wglMakeCurrent(this.DC, this.RC);
}
I've sent User.GetForegroundWindow() as the hWnd.
After this initialization I try getting a screenshot into in image (and I have also tried to read it into a simple byte array)
Short psuedo code of glReadPixels usage:
var area = new Rectangle(0, 0, 100, 100);
var bmp = new Bitmap(area.Width, area.Height);
var data = bmp.LockBits(area, ILM.WriteOnly, PF.24bppRgb);
glReadBuffer(BACK);
glReadPixels(0, 0, area.Width, area.Height, BGR_EXT /*also tried RGB and RGBA*/, UNSIGNED_BYTE, data.Scan0);
bmp.UnlockBits(data);
bmp.Save(#"C:\Back.bmp");
data = bmp.LockBits(area, ILM.WriteOnly, PF.24bppRgb);
glReadBuffer(FRONT);
glReadPixels(0, 0, area.Width, area.Height, BGR_EXT /*also tried RGB and RGBA*/, UNSIGNED_BYTE, data.Scan0);
bmp.UnlockBits(data);
bmp.Save(#"C:\Front.bmp");
Trying it with a simple and small byte[] was done like this:
var bytes = new byte[10 * 10 * 3];
glReadPixels(0, 0, 10, 10, RGB, UNSIGNED_BYTE, bytes);
And the byte[] was all zero's.
I've also tried it with bigger size for the array (keeping the 0, 0, 10, 10), but still to no avail.
In both cases, the result is the same.
The buffer doesn't change at all, while a glGetError call returns 0 after each GL function call.
Both Back.bmp and Front.bmp are totally black.
Please tell me what am I doing wrong?
Thanks
Are you trying to create a screenshot of something you rendered, or a screenshot of the screen in general?
glReadPixels is assured to work only for contents of the OpenGL framebuffer. It's not suited for taking screenshots of anything else (there used to be a time, where this was possible, but ever since the advent of compositing window managers those times are gone).
So if you're trying to do general screen capture, glReadPixels is the wrong way to go.
If however you're trying to take a screenshot of what you rendered, then you must make sure that the context you rendered with is also active when calling glReadPixels.

Categories

Resources