RadioButtonRenderer with Transparent Background - c#

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);

Related

Apply the opacity of a LinearGradientBrush to an image in winforms

I want to apply the opacity of a linear gradient to an image, but all I have been able to get is the gradient painted on top of the image.
Following this stackoverflow post, I created a user control that inherits from PictureBox and I overrode the OnPaint method
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
LinearGradientBrush linearGradientBrush = new LinearGradientBrush(
this.ClientRectangle,
Color.FromArgb(255, Color.White),
Color.FromArgb(0, Color.White),
0f);
e.Graphics.FillRectangle(linearGradientBrush, this.ClientRectangle);
}
However, that simply paints the linear gradient on top of the image.
How do I apply the opacity of the linear gradient to the image?
I find examples in XAML (), but not for winforms.
It is not necessary to use a user control and override the OnPaint event. Just create a graphics object from a blank image and do your image manipulation and assign the image to a PicturePox.
First draw the linearGradientBrush to the background and afterwards draw the image over it. Always take care about the sequence of your image operations.
FileInfo inputImageFile = new FileInfo(#"C:\Temp\TheSimpsons.png");
Bitmap inputImage = (Bitmap)Bitmap.FromFile(inputImageFile.FullName);
// create blank bitmap with same size
Bitmap combinedImage = new Bitmap(inputImage.Width, inputImage.Height);
// create graphics object on new blank bitmap
Graphics g = Graphics.FromImage(combinedImage);
// also use the same size for the gradient brush and for the FillRectangle function
LinearGradientBrush linearGradientBrush = new LinearGradientBrush(
new Rectangle(0,0,combinedImage.Width, combinedImage.Height),
Color.FromArgb(255, Color.White), //Color.White,
Color.FromArgb(0, Color.White), // Color.Transparent,
0f);
g.FillRectangle(linearGradientBrush, 0, 0, combinedImage.Width, combinedImage.Height);
g.DrawImage(inputImage, 0,0);
previewPictureBox.Image = combinedImage;
Result with black as the forms background color and the example image with transparency.
EDIT:
I may have misunderstood the intention, and either haven't found an easy way like in WPF, but it is not this much difficult.
FileInfo inputImageFile = new FileInfo(#"C:\Temp\TheSimpsons.png");
Bitmap inputImage = (Bitmap)Bitmap.FromFile(inputImageFile.FullName);
// create blank bitmap
Bitmap adjImage = new Bitmap(inputImage.Width, inputImage.Height);
// create graphics object on new blank bitmap
Graphics g = Graphics.FromImage(adjImage);
LinearGradientBrush linearGradientBrush = new LinearGradientBrush(
new Rectangle(0, 0, adjImage.Width, adjImage.Height),
Color.White,
Color.Transparent,
0f);
Rectangle rect = new Rectangle(0, 0, adjImage.Width, adjImage.Height);
g.FillRectangle(linearGradientBrush, rect);
int x;
int y;
for (x = 0; x < adjImage.Width; ++x)
{
for (y = 0; y < adjImage.Height; ++y)
{
Color inputPixelColor = inputImage.GetPixel(x, y);
Color adjPixelColor = adjImage.GetPixel(x, y);
Color newColor = Color.FromArgb(adjPixelColor.A, inputPixelColor.R, inputPixelColor.G, inputPixelColor.B);
adjImage.SetPixel(x, y, newColor);
}
}
previewPictureBox.Image = adjImage;

Generated Bitmap Displays Weirdly in PictureBox

I cannot seem to programmatically create a colored bitmap to display in a PictureBox. The bitmap saves normally as a file, but is faded at the edges when displayed in a PictureBox. Here is simplified code used to create and display the Bitmap (in actual code, the bitmap generation is completely separate from the form, so forcing the bitmap size to match the picturebox size isn't possible):
Bitmap Bmp = new Bitmap(4, 4, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics gfx = Graphics.FromImage(Bmp))
using (SolidBrush brush = new SolidBrush(Color.BlueViolet))
{
gfx.FillRectangle(brush, 0, 0, 4, 4);
}
Then set the Image value on a PictureBox to the generated Bitmap:
pictureBox1.Image = Bmp;
Here is the resulting bitmap displayed in a 300x300 picturebox:
How do I set the Image on the PictureBox so that it displays the colored bitmap properly (full solid)?
EDIT: I am restricted to generating smaller source bitmaps, so upscaling into a PictureBox is unavoidable. The problem appears when the generated source bitmap is 4px or 100px square, so I believe these are relevant cases.
EDIT: The PictureBox scaling should be set to stretch or zoom for the issue to manifest. In this example case the 4x4 source bitmap is stretched to 300x300.
EDIT: The basic problem is PictureBox's inability to upscale small bitmaps into large controls. This is confusing because the Bitmap upscales nicely into a PictureBox.Background image. Unless you have a magic bullet that will fix the image upscaling problem, I think it might be best to go for clear and simple workarounds in your answer.
You are generating a 4x4 bitmap and it's being stretched. Specify the size to match the picture box instead:
int width = pictureBox1.Width;
int height = pictureBox1.Height;
var Bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics gfx = Graphics.FromImage(Bmp))
using (var brush = new SolidBrush(Color.BlueViolet))
{
gfx.FillRectangle(brush, 0, 0, width, height);
}
pictureBox1.Image = Bmp;
You will need to turn anti-aliasing off. Also, since you are using one color for the whole picturebox, why not make the bitmap 1x1? If you need it 4x4, change the int the top of the example from 1 to 4.
int hw = 1;
Bitmap Bmp = new Bitmap(hw, hw,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics gfx = Graphics.FromImage(Bmp))
{
// Turn off anti-aliasing and draw an exact copy
gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
gfx.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
using (SolidBrush brush = new SolidBrush(Color.BlueViolet))
{
gfx.FillRectangle(brush, 0, 0, hw, hw);
}
}
pictureBox1.Image = Bmp;
UPDATE
Since you are still having the same issue by setting the picturebox to the image, you will have to get the graphics object from the picturebox and draw directly on it.
The code is very similar.
using (Graphics gfx = Graphics.FromImage(pictureBox1.Image))
{
// Turn off anti-aliasing and draw an exact copy
gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
gfx.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
using (SolidBrush brush = new SolidBrush(Color.BlueViolet))
{
gfx.FillRectangle(brush, 0, 0,
pictureBox11.Width - 1,
pictureBox11.Height - 1);
}
}
// Force the picturebox to redraw with the new image.
// You could also use pictureBox11.Refresh() to do the redraw.
pictureBox11.Invalidate();
I tried to test your code and the image were properly displayed.
But when i used this code:
Rectangle srcRect = New Rectangle(0, 0, Bmp.Width, Bmp.Height);
Rectangle dstRect = New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height);
g = PictureBox1.CreateGraphics;
g.DrawImage(Bmp, dstRect, srcRect, GraphicsUnit.Pixel);
g.Dispose();
I did get exactly your result. In order to fix it:
Rectangle srcRect = New Rectangle(0, 0, Bmp.Width - 1, Bmp.Height - 1);
Rectangle dstRect = New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height);
g = PictureBox1.CreateGraphics;
g.DrawImage(Bmp, dstRect, srcRect, GraphicsUnit.Pixel);
g.Dispose();
Edit:
So you have the bitmap and you want to stretch it. And the bitmap has ane solid color. Do this insted:
Color pixelColor = Bmp.GetPixel(0, 0);
PictureBox1.BackColor = pixelColor;
valter

Adding Height to Image for Subtitle

i want to add an additonal height to an Image to give it a subtitle.
I do not want to "compres" or resize my original image.
I want to keep it's size and add +40 px to its height on bottom and add a text like this example
The red part is the original image.
The blue part is my addition.
I tried this code but my text appears "outside" the image i think.
Image image = Image.FromFile("D:\\my_sample_image.jpg");
// Create graphics from image
Graphics graphics = Graphics.FromImage(image);
// Create font
Font font = new Font("Times New Roman", 42.0f);
// Create text position
PointF point = new PointF(150, image.Height+40);
// Draw text
graphics.DrawString("Watermark", font, Brushes.Red, point);
// Save image
image.Save("D:\\my_sample_output.jpg");
MessageBox.Show("FINISHED");
// Open generated image file in default image viewer installed in Windows
Process.Start("D:\\my_sample_output.jpg");
Make a new Bitmap, create a Graphics out of it, then draw the old image with room for text at the bottom.
Bitmap image = new Bitmap("path/resource");
Bitmap newImage = new Bitmap(image.Width, image.Height + 40);
using (Graphics g = Graphics.FromImage(newImage))
{
// Draw base image
Rectangle rect = new Rectangle(0, 0, image.Width, image.Height);
g.DrawImageUnscaledAndClipped(image, rect);
//Fill undrawn area
g.FillRectangle(new SolidBrush(Color.Black), 0, image.Height, newImage.Width, 40);
// Create font
Font font = new Font("Times New Roman", 22.0f);
// Create text position (play with positioning)
PointF point = new PointF(0, image.Height);
// Draw text
g.DrawString("Watermark", font, Brushes.Red, point);
}
public Image addSubtitleToImage(string path, int height, string title)
{
Bitmap image = new Bitmap(path);
Bitmap newImage = new Bitmap(image.Width, image.Height + height);
using (Graphics g = Graphics.FromImage(newImage))
{
g.FillRectangle(new SolidBrush(Color.Black), new Rectangle(0, 0, newImage.Width, newImage.Height));
g.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height));
Font font = new Font("Tahoma", 30.0f);
g.DrawString(title, font, Brushes.White, new PointF(image.Width/2 , image.Height+));
}
return newImage;
}

Merge two images for "fade" transition with changing opacity? (C#/PNG)

First of all, I'd like to suggest that it is not a duplicate of THIS question. At least that's my opinion :)
What I want to achieve is a series of frames to "fade" animation.
I choose two PNG files (let' say they are the same size), for example:
Picture 1
Picture 2
I want to "simulate" merging them like layers in graphic editor. I put Pic1 on the top with opacity 255, Pic2 below with opacity 0, so at first I see only Pic1. Then I change their opacity, like this:
Pic1-200, Pic2-150
Pic1-150, Pic2-200
Pic1-100, Pic2-230
Is there any simple way for it?
In a winforms app this can be done pretty easily. Create a user control with a few properties:
public Image FromImage { get; set; }
public Image ToImage { get; set; }
private float opacity = 1;
Now override OnPaint
protected override void OnPaint(PaintEventArgs e)
{
if (FromImage != null && ToImage != null)
{
ColorMatrix matrix1 = new ColorMatrix();
matrix1.Matrix33 = opacity;
ImageAttributes attributes1 = new ImageAttributes();
attributes1.SetColorMatrix(matrix1, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
ColorMatrix matrix2 = new ColorMatrix();
matrix2.Matrix33 = 1 - opacity;
ImageAttributes attributes2 = new ImageAttributes();
attributes2.SetColorMatrix(matrix2, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
e.Graphics.DrawImage(FromImage, new Rectangle(0, 0, this.Width, this.Height), 0, 0, this.Width,
this.Height, GraphicsUnit.Pixel, attributes1);
e.Graphics.DrawImage(ToImage, new Rectangle(0, 0, this.Width, this.Height), 0, 0, this.Width,
this.Height, GraphicsUnit.Pixel, attributes2);
}
base.OnPaint(e);
}
Now drop a timer onto the control, set its to enabled with an elapsed time of something like 100ms. Handle the tick event:
private void timer_Tick(object sender, EventArgs e)
{
if(opacity == 0)
{
this.timer.Stop();
return;
}
this.opacity -= 0.01f;
this.Invalidate();
}
et voila. However, there's one thing to be aware of. This makes quite a flickery transition, which can be alieviated somewhat with this line in the control's constructor:
this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint,true);
Update based on Edit: You could turn this into a utility that takes 2 images and, using much the same code, outputs each step to a new image. Somthing like:
public class ImageUtility
{
private Image image1;
private Image image2;
public ImageUtility(Image image1, Image image2)
{
this.image1 = image1;
this.image2 = image2;
}
public void SaveTransitions(int numSteps, string outDir)
{
var opacityChange = 1.0f/(float) numSteps;
for(float opacity = 1,i=0;opacity>0;opacity-=opacityChange,i++)
{
using(var image = new Bitmap(image1.Width,image2.Width))
{
Graphics g = Graphics.FromImage(image);
ColorMatrix matrix1 = new ColorMatrix();
matrix1.Matrix33 = opacity;
ImageAttributes attributes1 = new ImageAttributes();
attributes1.SetColorMatrix(matrix1, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
ColorMatrix matrix2 = new ColorMatrix();
matrix2.Matrix33 = 1 - opacity;
ImageAttributes attributes2 = new ImageAttributes();
attributes2.SetColorMatrix(matrix2, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
g.DrawImage(image1, new Rectangle(0, 0, image1.Width, image1.Height), 0, 0, image1.Width,
image1.Height, GraphicsUnit.Pixel, attributes1);
g.DrawImage(image2, new Rectangle(0, 0, image2.Width, image2.Height), 0, 0, image2.Width,
image2.Height, GraphicsUnit.Pixel, attributes2);
image.Save(Path.Combine(outDir,"Image" + i + ".png"),ImageFormat.Png);
}
}
}
Usage:
ImageUtility util = new ImageUtility(Image.FromFile(#"C:\path\pic1.png"), Image.FromFile(#"C:\path\pic2.png"));
util.SaveTransitions(100, #"C:\path\output"); // saves 100 images
Using winforms you can use Graphics.DrawImage, using the overload that takes an ImageAttributes parameter. That class can specify manipulation to the colour (and alpha) values.
The example on the ImageAttributes page is nearly what you want. Just draw the original and transformed one in the same place, and change the colour matrix to only change the alpha level.

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);

Categories

Resources