Image Data

  • Thread starter Thread starter Drew
  • Start date Start date
D

Drew

Is there a way to obtain the pixel data from an image using C# and the
Compact Framework?

I'm thinking of something that would return a byte array from a bitmap
image, etc.

In Java, I could use something called PixelGrabber.

Regards,

Drew
 
Hi Drew,

This is something that is not implemented directly by the Bitmap object in
the .NET Compact Framework, however, the following link provides a
work-around by blitting the Bitmap to a control and then using
CreateDIBSection to access the pixels.

http://download.microsoft.com/downl...4-9d17-fd6767e66908/SaveBitmapSampleSetup.exe

A whitepaper should be published in the next week or so.

--
Geoff Schwab
Program Manager
Excell Data Corporation
http://msdn.com/mobility
http://msdn.microsoft.com/mobility/prodtechinfo/devtools/netcf/FAQ/default.aspx

This posting is provided "AS IS" with no warranties, and confers no rights.
 
Thanks for the info.

Unfortunately, I don't really understand the internals of this.

I could really use another layer of abstraction here!

Would someone be willing to write a class which would
use this to allow me to get at the image data easily in C#?

Drew
 
Hi Drew,

What is it you want to be able to do? This code will not let you access the
pixels, modify them, then store them back in the Bitmap object but it will
let you access the pixels, modify them, then save them to a file. Depending
on your goals, I may be able to give you some insight or write an
abstraction layer.

--
Geoff Schwab
Program Manager
Excell Data Corporation
http://msdn.com/mobility
http://msdn.microsoft.com/mobility/prodtechinfo/devtools/netcf/FAQ/default.aspx

This posting is provided "AS IS" with no warranties, and confers no rights.
 
I want to access the pixels, modify them, and then store them in a different
Bitmap object
or just display the new image on the screen.

Basically, I'm hoping to do some image manipulation.

In Java, I could use the PixelGrabber class to "grab" a predetermined set of
pixels
from the image and store them in a byte array.

I think that's all I'm looking for at this point...

Drew
 
Hi Drew,

I think all of the code you need is in the sample but since the whitepaper
is still being processed for publishing I will explain it a bit here:

What happens in the sample is a Bitmap object is drawn onto a panel control.
Then the control is used to create a DIB (device independant bitmap) section
and the pixels are accessed. This data is then used to construct a .bmp
file which is saved.

It sounds like what you need an understanding of is how the pixels are
accessed, so I will explain that code in some detail - see the
CopyImageSource function for the actual code.

The first step is to access the device context associated with the control
that has the image on it and use that to create a compatible device context
in memory which will be used to access the pixels. You can get hwnd using
GetCapture or FindWindow - see the FAQ or sample code for more details.

IntPtr hdc = Windows.GetDC(hwnd);
IntPtr hdcComp = Windows.CreateCompatibleDC(hdc);

The next step is to create a BITMAPINFOHEADER that will specify the pixel
data format to CreateDIBSection. The infoHdr.Store function takes care of
filling the byte stream with the header info.

byte[] dummyBitmapInfo = new byte[52];
MemoryStream msDummy = new MemoryStream(dummyBitmapInfo);
BinaryWriter bwDummy = new BinaryWriter(msDummy);
infoHdr.Store(bwDummy, true);

The next set of code has to be placed in an unsafe code block because we
have a pointer to a pointer that we access.

We access the BITMAPINFOHEADER in the byte stream with a pointer, as well as
the destination of the pixel data. This is where you could provide your own
"bytes" array and simply set pPixelDest to &bytes[0] if you are only
interested in the pixel data. In this sample, pPixelDest is offset into the
..bmp file.

fixed (byte* pBitmapInfo = &dummyBitmapInfo[0], pPixelDest =
&bytes[fileHdr.bfOffBits])

Of course, pPixelSource is the source from which we will get the pixel data.

byte* pPixelSource;

Now we are going to create a DIB section from our control's device context.
This will assign pPixelSource to point at the pixel data.

IntPtr hDibSect = Windows.CreateDIBSection(hdc, pBitmapInfo,
Windows.DIB_RGB_COLORS, &pPixelSource, (IntPtr)0, (uint)0);

Select the DIB section into our memory device context.

IntPtr hbmOld = Windows.SelectObject(hdcComp, hDibSect);

Next we copy the pixel data from the control's device context to the newly
created memory device context

Windows.BitBlt(hdcComp, 0, 0, infoHdr.biWidth, infoHdr.biHeight, hdc, 0, 0,
Windows.SRCCOPY);

Now we copy the pixel data into our destination pointer which is the byte
array - at this point we have the pixel data in the correct place so this is
probably what you are looking to do. I believe you could now access
pPixelDest and modify the pixels, then copy them back into pPixelSource.

Windows.CopyMemory(pPixelDest, pPixelSource, (int)fileHdr.sizeOfImageData);

The rest of the code is clean-up

Windows.SelectObject(hdcComp, hbmOld);
Windows.DeleteObject(hDibSect);
bwDummy.Close();
msDummy.Close();
Windows.DeleteDC(hdcComp);
Windows.ReleaseDC(hwnd, hdc);

I hope this helps.

--
Geoff Schwab
Program Manager
Excell Data Corporation
http://msdn.com/mobility
http://msdn.microsoft.com/mobility/prodtechinfo/devtools/netcf/FAQ/default.aspx

This posting is provided "AS IS" with no warranties, and confers no rights.
 
Thank you Geoff!

This is helpful, but I will probably have to read it a couple of times. :)

Now, will I have to actually display the original image in order to make
this work?
(You said the bitmap object is drawn onto a panel control)

I don't want to display the image until after I have changed it's pixels.

Drew




Geoff Schwab said:
Hi Drew,

I think all of the code you need is in the sample but since the whitepaper
is still being processed for publishing I will explain it a bit here:

What happens in the sample is a Bitmap object is drawn onto a panel control.
Then the control is used to create a DIB (device independant bitmap) section
and the pixels are accessed. This data is then used to construct a .bmp
file which is saved.

It sounds like what you need an understanding of is how the pixels are
accessed, so I will explain that code in some detail - see the
CopyImageSource function for the actual code.

The first step is to access the device context associated with the control
that has the image on it and use that to create a compatible device context
in memory which will be used to access the pixels. You can get hwnd using
GetCapture or FindWindow - see the FAQ or sample code for more details.

IntPtr hdc = Windows.GetDC(hwnd);
IntPtr hdcComp = Windows.CreateCompatibleDC(hdc);

The next step is to create a BITMAPINFOHEADER that will specify the pixel
data format to CreateDIBSection. The infoHdr.Store function takes care of
filling the byte stream with the header info.

byte[] dummyBitmapInfo = new byte[52];
MemoryStream msDummy = new MemoryStream(dummyBitmapInfo);
BinaryWriter bwDummy = new BinaryWriter(msDummy);
infoHdr.Store(bwDummy, true);

The next set of code has to be placed in an unsafe code block because we
have a pointer to a pointer that we access.

We access the BITMAPINFOHEADER in the byte stream with a pointer, as well as
the destination of the pixel data. This is where you could provide your own
"bytes" array and simply set pPixelDest to &bytes[0] if you are only
interested in the pixel data. In this sample, pPixelDest is offset into the
.bmp file.

fixed (byte* pBitmapInfo = &dummyBitmapInfo[0], pPixelDest =
&bytes[fileHdr.bfOffBits])

Of course, pPixelSource is the source from which we will get the pixel data.

byte* pPixelSource;

Now we are going to create a DIB section from our control's device context.
This will assign pPixelSource to point at the pixel data.

IntPtr hDibSect = Windows.CreateDIBSection(hdc, pBitmapInfo,
Windows.DIB_RGB_COLORS, &pPixelSource, (IntPtr)0, (uint)0);

Select the DIB section into our memory device context.

IntPtr hbmOld = Windows.SelectObject(hdcComp, hDibSect);

Next we copy the pixel data from the control's device context to the newly
created memory device context

Windows.BitBlt(hdcComp, 0, 0, infoHdr.biWidth, infoHdr.biHeight, hdc, 0, 0,
Windows.SRCCOPY);

Now we copy the pixel data into our destination pointer which is the byte
array - at this point we have the pixel data in the correct place so this is
probably what you are looking to do. I believe you could now access
pPixelDest and modify the pixels, then copy them back into pPixelSource.

Windows.CopyMemory(pPixelDest, pPixelSource, (int)fileHdr.sizeOfImageData);

The rest of the code is clean-up

Windows.SelectObject(hdcComp, hbmOld);
Windows.DeleteObject(hDibSect);
bwDummy.Close();
msDummy.Close();
Windows.DeleteDC(hdcComp);
Windows.ReleaseDC(hwnd, hdc);

I hope this helps.

--
Geoff Schwab
Program Manager
Excell Data Corporation
http://msdn.com/mobility
http://msdn.microsoft.com/mobility/prodtechinfo/devtools/netcf/FAQ/default.aspx

This posting is provided "AS IS" with no warranties, and confers no rights.

Drew said:
I want to access the pixels, modify them, and then store them in a different
Bitmap object
or just display the new image on the screen.

Basically, I'm hoping to do some image manipulation.

In Java, I could use the PixelGrabber class to "grab" a predetermined
set
of
pixels
from the image and store them in a byte array.

I think that's all I'm looking for at this point...

Drew



access
the
http://msdn.microsoft.com/mobility/.../prodtechinfo/devtools/netcf/FAQ/default.aspx
 
Hi Drew,

I have not tried it myself but my thinking is that you could create an
invisible control and draw the bitmap onto it. To be honest, I am not sure
what an invisible control will return from CreateDIBSection. I think this
will be a popular request so I will make a note that a HOWTO based on this
sample should examine this issue more and take a look at the issue ASAP.

--
Geoff Schwab
Program Manager
Excell Data Corporation
http://msdn.com/mobility
http://msdn.microsoft.com/mobility/prodtechinfo/devtools/netcf/FAQ/default.aspx

This posting is provided "AS IS" with no warranties, and confers no rights.
Drew said:
Thank you Geoff!

This is helpful, but I will probably have to read it a couple of times. :)

Now, will I have to actually display the original image in order to make
this work?
(You said the bitmap object is drawn onto a panel control)

I don't want to display the image until after I have changed it's pixels.

Drew




Geoff Schwab said:
Hi Drew,

I think all of the code you need is in the sample but since the whitepaper
is still being processed for publishing I will explain it a bit here:

What happens in the sample is a Bitmap object is drawn onto a panel control.
Then the control is used to create a DIB (device independant bitmap) section
and the pixels are accessed. This data is then used to construct a .bmp
file which is saved.

It sounds like what you need an understanding of is how the pixels are
accessed, so I will explain that code in some detail - see the
CopyImageSource function for the actual code.

The first step is to access the device context associated with the control
that has the image on it and use that to create a compatible device context
in memory which will be used to access the pixels. You can get hwnd using
GetCapture or FindWindow - see the FAQ or sample code for more details.

IntPtr hdc = Windows.GetDC(hwnd);
IntPtr hdcComp = Windows.CreateCompatibleDC(hdc);

The next step is to create a BITMAPINFOHEADER that will specify the pixel
data format to CreateDIBSection. The infoHdr.Store function takes care of
filling the byte stream with the header info.

byte[] dummyBitmapInfo = new byte[52];
MemoryStream msDummy = new MemoryStream(dummyBitmapInfo);
BinaryWriter bwDummy = new BinaryWriter(msDummy);
infoHdr.Store(bwDummy, true);

The next set of code has to be placed in an unsafe code block because we
have a pointer to a pointer that we access.

We access the BITMAPINFOHEADER in the byte stream with a pointer, as
well
as
the destination of the pixel data. This is where you could provide your own
"bytes" array and simply set pPixelDest to &bytes[0] if you are only
interested in the pixel data. In this sample, pPixelDest is offset into the
.bmp file.

fixed (byte* pBitmapInfo = &dummyBitmapInfo[0], pPixelDest =
&bytes[fileHdr.bfOffBits])

Of course, pPixelSource is the source from which we will get the pixel data.

byte* pPixelSource;

Now we are going to create a DIB section from our control's device context.
This will assign pPixelSource to point at the pixel data.

IntPtr hDibSect = Windows.CreateDIBSection(hdc, pBitmapInfo,
Windows.DIB_RGB_COLORS, &pPixelSource, (IntPtr)0, (uint)0);

Select the DIB section into our memory device context.

IntPtr hbmOld = Windows.SelectObject(hdcComp, hDibSect);

Next we copy the pixel data from the control's device context to the newly
created memory device context

Windows.BitBlt(hdcComp, 0, 0, infoHdr.biWidth, infoHdr.biHeight, hdc, 0, 0,
Windows.SRCCOPY);

Now we copy the pixel data into our destination pointer which is the byte
array - at this point we have the pixel data in the correct place so
this
is
probably what you are looking to do. I believe you could now access
pPixelDest and modify the pixels, then copy them back into pPixelSource.

Windows.CopyMemory(pPixelDest, pPixelSource, (int)fileHdr.sizeOfImageData);

The rest of the code is clean-up

Windows.SelectObject(hdcComp, hbmOld);
Windows.DeleteObject(hDibSect);
bwDummy.Close();
msDummy.Close();
Windows.DeleteDC(hdcComp);
Windows.ReleaseDC(hwnd, hdc);

I hope this helps.

--
Geoff Schwab
Program Manager
Excell Data Corporation
http://msdn.com/mobility
http://msdn.microsoft.com/mobility/prodtechinfo/devtools/netcf/FAQ/default.aspx
This posting is provided "AS IS" with no warranties, and confers no rights.

set it
will
http://msdn.microsoft.com/mobility/.../prodtechinfo/devtools/netcf/FAQ/default.aspx
 
Geoff,

If I were to use the full .NET framework, are there any methods
that would let me get the pixels easily or would I still have to use
the same procedure you described?

Drew




Geoff Schwab said:
Hi Drew,

I have not tried it myself but my thinking is that you could create an
invisible control and draw the bitmap onto it. To be honest, I am not sure
what an invisible control will return from CreateDIBSection. I think this
will be a popular request so I will make a note that a HOWTO based on this
sample should examine this issue more and take a look at the issue ASAP.

--
Geoff Schwab
Program Manager
Excell Data Corporation
http://msdn.com/mobility
http://msdn.microsoft.com/mobility/prodtechinfo/devtools/netcf/FAQ/default.aspx

This posting is provided "AS IS" with no warranties, and confers no rights.
Drew said:
Thank you Geoff!

This is helpful, but I will probably have to read it a couple of times. :)

Now, will I have to actually display the original image in order to make
this work?
(You said the bitmap object is drawn onto a panel control)

I don't want to display the image until after I have changed it's pixels.

Drew
care
of
filling the byte stream with the header info.

byte[] dummyBitmapInfo = new byte[52];
MemoryStream msDummy = new MemoryStream(dummyBitmapInfo);
BinaryWriter bwDummy = new BinaryWriter(msDummy);
infoHdr.Store(bwDummy, true);

The next set of code has to be placed in an unsafe code block because we
have a pointer to a pointer that we access.

We access the BITMAPINFOHEADER in the byte stream with a pointer, as
well
as
the destination of the pixel data. This is where you could provide
your
own
"bytes" array and simply set pPixelDest to &bytes[0] if you are only
interested in the pixel data. In this sample, pPixelDest is offset
into
the
.bmp file.

fixed (byte* pBitmapInfo = &dummyBitmapInfo[0], pPixelDest =
&bytes[fileHdr.bfOffBits])

Of course, pPixelSource is the source from which we will get the pixel data.

byte* pPixelSource;

Now we are going to create a DIB section from our control's device context.
This will assign pPixelSource to point at the pixel data.

IntPtr hDibSect = Windows.CreateDIBSection(hdc, pBitmapInfo,
Windows.DIB_RGB_COLORS, &pPixelSource, (IntPtr)0, (uint)0);

Select the DIB section into our memory device context.

IntPtr hbmOld = Windows.SelectObject(hdcComp, hDibSect);

Next we copy the pixel data from the control's device context to the newly
created memory device context

Windows.BitBlt(hdcComp, 0, 0, infoHdr.biWidth, infoHdr.biHeight, hdc,
0,
0,
Windows.SRCCOPY);

Now we copy the pixel data into our destination pointer which is the byte
array - at this point we have the pixel data in the correct place so
this
is
probably what you are looking to do. I believe you could now access
pPixelDest and modify the pixels, then copy them back into pPixelSource.

Windows.CopyMemory(pPixelDest, pPixelSource, (int)fileHdr.sizeOfImageData);

The rest of the code is clean-up

Windows.SelectObject(hdcComp, hbmOld);
Windows.DeleteObject(hDibSect);
bwDummy.Close();
msDummy.Close();
Windows.DeleteDC(hdcComp);
Windows.ReleaseDC(hwnd, hdc);

I hope this helps.

--
Geoff Schwab
Program Manager
Excell Data Corporation
http://msdn.com/mobility
http://msdn.microsoft.com/mobility/prodtechinfo/devtools/netcf/FAQ/default.aspx
predetermined
set
http://msdn.microsoft.com/mobility/prodtechinfo/devtools/netcf/FAQ/default.aspx provides
http://download.microsoft.com/downl.../prodtechinfo/devtools/netcf/FAQ/default.aspx
confers
no C#
and
from
 
Hi Drew,

Yes, the full .NET Framework allows you to access pixels directly through
the LockBits method. There are also several other methods for determining
pixel formats, etc.

http://msdn.microsoft.com/library/en-us/gdicpp/GDIPlus/GDIPlusreference/classes/bitmap.asp

--
Geoff Schwab
Program Manager
Excell Data Corporation
http://msdn.com/mobility
http://msdn.microsoft.com/mobility/prodtechinfo/devtools/netcf/FAQ/default.aspx

This posting is provided "AS IS" with no warranties, and confers no rights.
Drew said:
Geoff,

If I were to use the full .NET framework, are there any methods
that would let me get the pixels easily or would I still have to use
the same procedure you described?

Drew




Geoff Schwab said:
Hi Drew,

I have not tried it myself but my thinking is that you could create an
invisible control and draw the bitmap onto it. To be honest, I am not sure
what an invisible control will return from CreateDIBSection. I think this
will be a popular request so I will make a note that a HOWTO based on this
sample should examine this issue more and take a look at the issue ASAP.

--
Geoff Schwab
Program Manager
Excell Data Corporation
http://msdn.com/mobility
http://msdn.microsoft.com/mobility/prodtechinfo/devtools/netcf/FAQ/default.aspx
This posting is provided "AS IS" with no warranties, and confers no rights.
Drew said:
Thank you Geoff!

This is helpful, but I will probably have to read it a couple of
times.
:)
Now, will I have to actually display the original image in order to make
this work?
(You said the bitmap object is drawn onto a panel control)

I don't want to display the image until after I have changed it's pixels.

Drew




Hi Drew,

I think all of the code you need is in the sample but since the whitepaper
is still being processed for publishing I will explain it a bit here:

What happens in the sample is a Bitmap object is drawn onto a panel
control.
Then the control is used to create a DIB (device independant bitmap)
section
and the pixels are accessed. This data is then used to construct a .bmp
file which is saved.

It sounds like what you need an understanding of is how the pixels are
accessed, so I will explain that code in some detail - see the
CopyImageSource function for the actual code.

The first step is to access the device context associated with the control
that has the image on it and use that to create a compatible device
context
in memory which will be used to access the pixels. You can get hwnd using
GetCapture or FindWindow - see the FAQ or sample code for more details.

IntPtr hdc = Windows.GetDC(hwnd);
IntPtr hdcComp = Windows.CreateCompatibleDC(hdc);

The next step is to create a BITMAPINFOHEADER that will specify the pixel
data format to CreateDIBSection. The infoHdr.Store function takes
care
of
filling the byte stream with the header info.

byte[] dummyBitmapInfo = new byte[52];
MemoryStream msDummy = new MemoryStream(dummyBitmapInfo);
BinaryWriter bwDummy = new BinaryWriter(msDummy);
infoHdr.Store(bwDummy, true);

The next set of code has to be placed in an unsafe code block
because
we
have a pointer to a pointer that we access.

We access the BITMAPINFOHEADER in the byte stream with a pointer, as well
as
the destination of the pixel data. This is where you could provide your
own
"bytes" array and simply set pPixelDest to &bytes[0] if you are only
interested in the pixel data. In this sample, pPixelDest is offset into
the
.bmp file.

fixed (byte* pBitmapInfo = &dummyBitmapInfo[0], pPixelDest =
&bytes[fileHdr.bfOffBits])

Of course, pPixelSource is the source from which we will get the pixel
data.

byte* pPixelSource;

Now we are going to create a DIB section from our control's device
context.
This will assign pPixelSource to point at the pixel data.

IntPtr hDibSect = Windows.CreateDIBSection(hdc, pBitmapInfo,
Windows.DIB_RGB_COLORS, &pPixelSource, (IntPtr)0, (uint)0);

Select the DIB section into our memory device context.

IntPtr hbmOld = Windows.SelectObject(hdcComp, hDibSect);

Next we copy the pixel data from the control's device context to the newly
created memory device context

Windows.BitBlt(hdcComp, 0, 0, infoHdr.biWidth, infoHdr.biHeight,
hdc,
http://msdn.microsoft.com/mobility/prodtechinfo/devtools/netcf/FAQ/default.aspx
http://msdn.microsoft.com/mobility/prodtechinfo/devtools/netcf/FAQ/default.aspx
http://download.microsoft.com/downl.../prodtechinfo/devtools/netcf/FAQ/default.aspx using
 
Back
Top