GrayScale (by ColorMatrix) causes OutOfMemoryException. Why? - c#

I have 2 forms, A and B. On the Form A, I click a button and an Image is being loaded to a PictureBox located ona the Form B. And, I want to set GrayScale to this image by:
public void SetGrayScale(PictureBox pb)
{
ColorMatrix matrix = new ColorMatrix(new float[][]
{
new float[] {0.299f, 0.299f, 0.299f, 0, 0},
new float[] {0.587f, 0.587f, 0.587f, 0, 0},
new float[] {0.114f, 0.114f, 0.114f, 0, 0},
new float[] { 0, 0, 0, 1, 0},
new float[] { 0, 0, 0, 0, 0}
});
Image image = (Bitmap)pb.Image.Clone();
ImageAttributes attributes = new ImageAttributes();
attributes.SetColorMatrix(matrix);
Graphics graphics = Graphics.FromImage(image);
graphics.DrawImage(image,
new Rectangle(0, 0, image.Width, image.Height),
0,
0,
image.Width,
image.Height,
GraphicsUnit.Pixel,
attributes);
graphics.Dispose();
pb.Image = image;
}
This code works properly when the PictureBox is on the same form (A). But, when it is on the Form B, the OutOfMemoryException is raised. Why ?

More questions/things for you to investigate rather than an actual answer I'm afraid:
As in the comment to your answer - is the Image object correct?
If not then that implies that there's something wrong with the PictureBox object passed into this method, or that you can't access the PictureBox's Image properly.
My first thought was threading, but both forms should be in the UI thread.

Ok, I've Fixed it :)
The solution is, I had to created a Bitmap object from the OpenDialog.FileName, and later set PictureBox.Image = myBitmap
I didn't do it at the beginning, I was just setting PictureBox.Load(OpenDialog.FileName). And that was my mistake.
Ok, thank's for Your cooperation, ChrisF ! :)

Related

Picturebox slider control transparency

I've a PictureBox in my form and load a image in it.
I need this PictureBox to change the transparency (opacity, visibilit..etc), because I need the user to see the image behind this PictureBox better, so when he wants, he just drag the control slider and the image starts to turn invisible, step by step, until he finds its ok, lets say 50% transparency.
I added the control slider but, cant find the way to do the rest. I tried the pictureBox.Opacity, pictureBox.Transparency, nothing works.
In winforms you will have to modify the alpha of the PictureBox.Image.
To do that in a fast way use a ColorMatrix!
Here is an example:
The trackbar code:
Image original = null;
private void trackBar1_Scroll(object sender, EventArgs e)
{
if (original == null) original = (Bitmap) pictureBox1.Image.Clone();
pictureBox1.BackColor = Color.Transparent;
pictureBox1.Image = SetAlpha((Bitmap)original, trackBar1.Value);
}
To use a ColorMatrix we need this using clause:
using System.Drawing.Imaging;
Now for the SetAlpha function; note that it is basically a clone from the MS link..:
static Bitmap SetAlpha(Bitmap bmpIn, int alpha)
{
Bitmap bmpOut = new Bitmap(bmpIn.Width, bmpIn.Height);
float a = alpha / 255f;
Rectangle r = new Rectangle(0, 0, bmpIn.Width, bmpIn.Height);
float[][] matrixItems = {
new float[] {1, 0, 0, 0, 0},
new float[] {0, 1, 0, 0, 0},
new float[] {0, 0, 1, 0, 0},
new float[] {0, 0, 0, a, 0},
new float[] {0, 0, 0, 0, 1}};
ColorMatrix colorMatrix = new ColorMatrix(matrixItems);
ImageAttributes imageAtt = new ImageAttributes();
imageAtt.SetColorMatrix( colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
using (Graphics g = Graphics.FromImage(bmpOut))
g.DrawImage(bmpIn, r, r.X, r.Y, r.Width, r.Height, GraphicsUnit.Pixel, imageAtt);
return bmpOut;
}
Note the the ColorMatrix expects its elements to be be scaling factors with 1 being the identity. The TrackBar.Value goes from 0-255, just like a Bitmap alpha channel..
Also note that the function creates a new Bitmap, which may lead to GDI leaking. Here the PictureBox takes care of it, it seems; at least testing it with the taskmanger ('Details' - turn on GDI-objects column!) shows no problems :-)
Final note: This will work if and only if the PictureBox is nested in the control 'behind' it! If it merely overlaps this will not work!! In my example it sits on a TabPage, which is a Container and anything you drop on it gets nested inside. It would work the same if I had dropped it onto a Panel. But PictureBoxes are no containers. So if you want another PictureBox to show up behind it, then you need code to create the nesting: pboxTop.Parent = pBoxBackground; pboxTop.Location = Point.Empty;

C# sharpGL use texture on SharpGL.SceneGraph.Primitives.Polygon

I'm using SharpGL library for Visual C#. I want to add texture to SharpGL.SceneGraph.Primitives.Polygon.
SharpGL.OpenGL gl = this.openGLControl1.OpenGL;
textureImage = new Bitmap(openDialog.FileName);
gl.Enable(OpenGL.GL_TEXTURE_2D);
gl.GenTextures(1, textures);
gl.BindTexture(OpenGL.GL_TEXTURE_2D, textures[0]);
gl.TexImage2D(OpenGL.GL_TEXTURE_2D, 0, 3, textureImage.Width, textureImage.Height, 0, OpenGL.GL_BGR, OpenGL.GL_UNSIGNED_BYTE, textureImage.LockBits(new Rectangle(0, 0, textureImage.Width, textureImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb).Scan0);
gl.TexParameter(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_MIN_FILTER, OpenGL.GL_LINEAR);
gl.TexParameter(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_MAG_FILTER, OpenGL.GL_LINEAR);
What i need to do before I load image?
I drawing my model by
foreach (Polygon polygon in polygons)
{
polygon.PushObjectSpace(gl);
polygon.Render(gl, SharpGL.SceneGraph.Core.RenderMode.Render);
polygon.PopObjectSpace(gl);
}

RadioButtonRenderer with Transparent Background

I have a situation where I need to render a radio button to an System.Drawing.Image.
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(20,16);
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap))
{
RadioButtonRenderer.DrawRadioButton(g, new Point(2, 2), RadioButtonState.CheckedPressed);
}
return System.Drawing.Image.FromHbitmap(bitmap.GetHbitmap());
This works except that it's drawing the default control-grey as the background. How can I set this the background color to Transparent?
Not sure how your button looks exactly, but using the Bitmap.MakeTransparent Method with the grey color should work.
If it is not to your liking, you can try more complex color transformation using the ColorMatrix Class:
ColorMatrix matrix = new ColorMatrix();
// This will change the image's opacity.
matrix.Matrix33 = 0.5f;
ImageAttributes imgAttrs = new ImageAttributes();
imgAttrs.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
g.DrawImage(img, new Rectangle(0, 0, 50, 50), 0, 0, 50, 50, GraphicsUnit.Pixel, imgAttrs);

how to draw an image on a canvas with transparency/alpha

hy there!
i left out usings etc... just plain code:
var image = Image.FromFile(/* my magic source */);
var bitmap = new Bitmap(image.Width, image.Height);
var canvas = Graphics.FromImage(bitmap);
var brush = new SolidBrush(/* my magic color */);
canvas.FillRectangle(brush, 0, 0, image.Width, image.Height);
canvas.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height));
canvas.Save();
bitmap.Save(/* my magic target */);
i want to draw image with alpha 55% on canvas. image is a .png-file and uses transparency itself. (NOTE: i do not want to make image.MakeTransparent() - it is already transparent, i just need some alpha-effect)
how can i achieve this?
Try ColorMatrix and ImageAttributes:
ColorMatrix cm = new ColorMatrix();
cm.Matrix33 = 0.55f;
ImageAttributes ia = new ImageAttributes();
ia.SetColorMatrix(cm);
canvas.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, ia);

What would be a good TRUE black and white colormatrix?

I want to convert an image from color to B/W (i.e. no grayscale, just black and white). Does anyone have a good colormatrix to achieve this?
I've finally found a solution to my problem:
Transform the image to grayscale, using well a known colormatrix.
Use SetThreshold method of the ImageAttributes class to set the threshold that separates black from white.
Here is the C# code:
using (Graphics gr = Graphics.FromImage(SourceImage)) // SourceImage is a Bitmap object
{
var gray_matrix = new float[][] {
new float[] { 0.299f, 0.299f, 0.299f, 0, 0 },
new float[] { 0.587f, 0.587f, 0.587f, 0, 0 },
new float[] { 0.114f, 0.114f, 0.114f, 0, 0 },
new float[] { 0, 0, 0, 1, 0 },
new float[] { 0, 0, 0, 0, 1 }
};
var ia = new System.Drawing.Imaging.ImageAttributes();
ia.SetColorMatrix(new System.Drawing.Imaging.ColorMatrix(gray_matrix));
ia.SetThreshold(0.8); // Change this threshold as needed
var rc = new Rectangle(0, 0, SourceImage.Width, SourceImage.Height);
gr.DrawImage(SourceImage, rc, 0, 0, SourceImage.Width, SourceImage.Height, GraphicsUnit.Pixel, ia);
}
I've benchmarked this code and it is approximately 40 times faster than pixel by pixel manipulation.
You dont need a color matrix to achive this, just simply change encoding to CCITT! That only Black & White. Result remains correct and result file size is very small. Also much more efficient and faster than System.DrawImage.
This is the perfect solution:
public void toCCITT(string tifURL)
{
byte[] imgBits = File.ReadAllBytes(tifURL);
using (MemoryStream ms = new MemoryStream(imgBits))
{
using (Image i = Image.FromStream(ms))
{
EncoderParameters parms = new EncoderParameters(1);
ImageCodecInfo codec = ImageCodecInfo.GetImageDecoders()
.FirstOrDefault(decoder => decoder.FormatID == ImageFormat.Tiff.Guid);
parms.Param[0] = new EncoderParameter(Encoder.Compression, (long)EncoderValue.CompressionCCITT4);
i.Save(#"c:\test\result.tif", codec, parms);
}
}
}
VB.NET version:
Using gr As Graphics = Graphics.FromImage(SourceImage) 'SourceImage is a Bitmap object'
Dim gray_matrix As Single()() = {
New Single() {0.299F, 0.299F, 0.299F, 0, 0},
New Single() {0.587F, 0.587F, 0.587F, 0, 0},
New Single() {0.114F, 0.114F, 0.114F, 0, 0},
New Single() {0, 0, 0, 1, 0},
New Single() {0, 0, 0, 0, 1}
}
Dim ia As New System.Drawing.Imaging.ImageAttributes
ia.SetColorMatrix(New System.Drawing.Imaging.ColorMatrix(gray_matrix))
ia.SetThreshold(0.8)
Dim rc As New Rectangle(0, 0, SourceImage.Width, SourceImage.Height)
gr.DrawImage(SourceImage, rc, 0, 0, SourceImage.Width, SourceImage.Height, GraphicsUnit.Pixel, ia)
End Using
If you want it to look halfway decent, you'll probably want to apply some form of dithering.
Here's a full discussion, if a bit dated:
http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT

Categories

Resources