This seems like it should be simple, but I can't seem to find any way to do it. I have a custom WinForms control that has an overridden paint method that does some custom drawing.
I have a Bitmap in memory, and all I want to do is paint over the whole thing with a HashBrush, but preserve the alpha channel, so that the transparent parts of the bitmap don't get painted.
The bitmap in memory is not a simple shape, so it will not be feasible to define it as a set of paths or anything.
EDIT: In response to showing the code, there is a lot of code in the paint routine, so I'm only including a relevant snippet, which is the method in question. This method gets called from the main paint override. It accepts a list of images which are black transparency masks and combines them into one, then it uses a ColorMatrix to change the color of the combined image it created, allowing it to be overlayed on top of the background. All I want to accomplish is being able to also paint hashmarks on top of it.
private void PaintSurface(PaintEventArgs e, Image imgParent, List<Image> surfImgs, Rectangle destRect, ToothSurfaceMaterial material)
{
using (Bitmap bmp = new Bitmap(imgParent.Width, imgParent.Height,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb))
{
using (Graphics g = Graphics.FromImage(bmp))
{
foreach (Image img in surfImgs)
{
g.DrawImage(img, System.Drawing.Point.Empty);
}
}
ColorMatrix matrix = new ColorMatrix(
new float[][] {
new float[] { 0, 0, 0, 0, 0},
new float[] { 0, 0, 0, 0, 0},
new float[] { 0, 0, 0, 0, 0},
new float[] { 0, 0, 0, 0.7f, 0},
new float[] { material.R / 255.0f,
material.G / 255.0f,
material.B / 255.0f,
0, 1}
});
ImageAttributes imageAttr = new ImageAttributes();
imageAttr.SetColorMatrix(matrix);
Rectangle r = GetSizedRect(imgParent, destRect);
e.Graphics.DrawImage(bmp,
r,
0,
0,
bmp.Width,
bmp.Height,
GraphicsUnit.Pixel, imageAttr);
}
}
The solution I ended up using was the following method. First I combine the individual masks into one, then create a new Bitmap and paint the whole thing with the HatchBrush, finally iterate through the mask and set the alpha values on the newly generated bitmap based on the mask.
private Bitmap GenerateSurface(Image imgParent, List<Image> surfImgs, ToothSurfaceMaterial material)
{
Bitmap mask = new Bitmap(imgParent.Width, imgParent.Height,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
using (Graphics g = Graphics.FromImage(mask))
{
foreach (Image img in surfImgs)
{
g.DrawImage(img, System.Drawing.Point.Empty);
}
}
Bitmap output = new Bitmap(mask.Width, mask.Height,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
using (Graphics g = Graphics.FromImage(output))
{
if (material.HatchStyle != null)
{
HatchBrush hb = new HatchBrush((HatchStyle)material.HatchStyle, material.FgColor, material.BgColor);
g.FillRectangle(hb, new Rectangle(0, 0, output.Width, output.Height));
}
else
{
SolidBrush sb = new SolidBrush(material.FgColor);
g.FillRectangle(sb, new Rectangle(0, 0, output.Width, output.Height));
}
}
var rect = new Rectangle(0, 0, output.Width, output.Height);
var bitsMask = mask.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
var bitsOutput = output.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
int offset = 0;
for (int y = 0; y < mask.Height; y++)
{
byte* ptrMask = (byte*)bitsMask.Scan0 + y * bitsMask.Stride;
byte* ptrOutput = (byte*)bitsOutput.Scan0 + y * bitsOutput.Stride;
for (int x = 0; x < mask.Width; x++)
{
offset = 4 * x + 3;
ptrOutput[offset] = (byte)(ptrMask[offset] * 0.7);
}
}
}
mask.UnlockBits(bitsMask);
output.UnlockBits(bitsOutput);
return output;
}
I think you don't need any ColorMatrix which is overkill, you just need a ColorMap, here is the code which may not suit your requirement but should give you the idea. That's because I possibly don't understand your problem well, if you have any problem, just leave some comment and I'll try to improve the answer:
ImageAttributes imgA = new ImageAttributes();
ColorMap cm = new ColorMap();
cm.OldColor = Color.Black
cm.NewColor = Color.FromArgb((byte)(0.7*255), Color.Green);
imgA.SetRemapTable(new ColorMap[] {cm });
GraphicsUnit gu = GraphicsUnit.Pixel;
g.DrawImage(imageToDraw,new Point[]{Point.Empty,
new Point(backImage.Width/2,0),
new Point(0,backImage.Height/2)},
Rectangle.Round(imageToDraw.GetBounds(ref gu)),
GraphicsUnit.Pixel, imgA);
the new Point[] is an array of 3 Points used to locate the destination Rectangle.
The code above is used to Draw the imageToDraw on top of the backImage and convert and color of Black to the color Green with Opacity = 70%. That's what you want to fulfill your code.
UPDATE
This may be what you want, in fact your code doesn't show what you want, it just shows what you have which doesn't implement anything related to your problem now. I deduce this from your very first description in your question. The input is an image with background color (which will be made partially transparent later) being Black. Now the output you want is an image with all the non-Black region being painted with a HatchBrush. This output will then be processed to turn the Black background to a partially transparent background.
public void PaintHatchBrush(Bitmap input, HatchBrush brush){
using(Graphics g = Graphics.FromImage(input)){
g.Clip = GetForegroundRegion(input, Color.Black);
GraphicsUnit gu = GraphicsUnit.Pixel;
g.FillRectangle(brush, input.GetBounds(ref gu));
}
}
//This is implemented using `GetPixel` which is not fast, but it gives you the idea.
public Region GetForegroundRegion(Bitmap input, Color backColor){
GraphicsPath gp = new GraphicsPath();
Rectangle rect = Rectangle.Empty;
bool jumpedIn = false;
for (int i = 0; i < bm.Height; i++) {
for (int j = 0; j < bm.Width; j++) {
Color c = bm.GetPixel(j, i);
if (c != backColor&&!jumpedIn) {
rect = new Rectangle(j, i, 1, 1);
jumpedIn = true;
}
if (jumpedIn && (c == backColor || j == bm.Width - 1)) {
rect.Width = j - rect.Left;
gp.AddRectangle(rect);
jumpedIn = false;
}
}
}
return new Region(gp);
}
//Usage
HatchBrush brush = new HatchBrush(HatchStyle.Percent30, Color.Green, Color.Yellow);
PaintHatchBrush(yourImage, brush);
//then yourImage will have HatchBrush painted on the surface leaving the Black background intact.
//This image will be used in the next process to turn the Black background into 70%
//opacity background as you did using ColorMatrix (or more simply using ColorMap as I posted previously)
Related
I'm trying to make an image cropping tool.
I am following this https://www.codeproject.com/Articles/703519/Cropping-Particular-Region-In-Image-Using-Csharp
But since it's a bit old and the plugin/DLL's it uses have changed I have been trying to adapt his code from OpenCvSharp 2.0 to OpenCvSharp 2.4
When I'm converting the bitmaps to IplImages and using Cv.Mul() it gives me this error:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt
I have never used OpenCvSharp other ways of creating the IplImage even reading the IplImage from a written image.
Code:
public static IplImage BitmapToIplImage(Bitmap bitmap)
{
IplImage tmp, tmp2;
System.Drawing.Rectangle bRect = new System.Drawing.Rectangle(new System.Drawing.Point(0, 0), new System.Drawing.Size((int)bitmap.Width, (int)bitmap.Height));
BitmapData bmData = bitmap.LockBits(bRect, ImageLockMode.ReadWrite, bitmap.PixelFormat);
tmp = Cv.CreateImage(Cv.Size(bitmap.Width, bitmap.Height), BitDepth.U8, 3);
tmp2 = Cv.CreateImage(Cv.Size(bitmap.Width, bitmap.Height), BitDepth.U8, 1);
byte[] data = new byte[Math.Abs(bmData.Stride * bmData.Height)];
tmp.SetData(bmData.Scan0, data.Length);
bitmap.UnlockBits(bmData);
// Cv.CvtColor(tmp, tmp2, ColorConversion.RgbToGray);
return tmp;
}
private void CropImage()
{
IplImage ipl = Cv.CreateImage(new CvSize(curBmp.Width, curBmp.Height), BitDepth.U8, 3);
Graphics ga = Graphics.FromImage(curBmp);
ga.FillRectangle(new SolidBrush(System.Drawing.Color.Black), new System.Drawing.Rectangle(0, 0, curBmp.Width, curBmp.Height));
SolidBrush brush = new SolidBrush(System.Drawing.Color.FromArgb(1, 1, 1));
curGraphics.FillClosedCurve(brush, imagePoints.ToArray());
Cv.Mul(BitmapToIplImage(curOgBmp), BitmapToIplImage(curBmp), ipl, 1);
ComputeCrop();
Stream s = null;
ipl.ToStream(s, ".png", null);
curBmp = new Bitmap(s);
RefreshImageViewer();
}
-----------------------------EDIT-----------------------------------------
I tried to follow what Markus posted, and I got it to work without any errors in the code.
Although the image cropped is a bit strange here are the methods I use, plus the RefreshImageViewer that is how I put the bitmap in the image control.
I have been trying to see if I missed something for hours, but I think not.
Output example: Imgur image link
Code:
public void RefreshImageViewer()
{
bmpSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
curBmp.GetHbitmap(),
IntPtr.Zero,
System.Windows.Int32Rect.Empty,
BitmapSizeOptions.FromWidthAndHeight(curBmp.Width, curBmp.Height));
imageViewer.Source = bmpSource;
curGraphics = Graphics.FromImage(curBmp);
}
private void CropImage()
{
Graphics Ga = Graphics.FromImage(curBmp);
//the black image
Ga.FillRectangle(new SolidBrush(System.Drawing.Color.Black), new System.Drawing.Rectangle(0, 0, curBmp.Width, curBmp.Height));
//draw from the last point to first point
Ga.DrawLine(new System.Drawing.Pen(System.Drawing.Color.Red, 3), imagePoints[imagePoints.Count - 1], imagePoints[0]);
//all of the rgb values are being set 1 inside the polygon
SolidBrush Brush = new SolidBrush(System.Drawing.Color.FromArgb(1, 1, 1));
//we have to prepare one mask of Multiplying operation for cropping region
curGraphics.FillPolygon(Brush, imagePoints.ToArray());
Mat accc = (BitmapToMat(curOgBmp).Mul(BitmapToMat(curBmp))).ToMat();
System.Drawing.Rectangle r = ComputeCrop();
curBmp = accc.ToBitmap().Clone(r, curOgBmp.PixelFormat);
RefreshImageViewer();
}
private System.Drawing.Rectangle ComputeCrop()
{
int smallestX = curBmp.Width, biggestX = 0, biggestY = 0, smallestY = curBmp.Height;
for (int i = 0; i < imagePoints.Count; i++)
{
biggestX = Math.Max(biggestX, imagePoints[i].X);
smallestX = Math.Min(smallestX, imagePoints[i].X);
biggestY = Math.Max(biggestY, imagePoints[i].Y);
smallestY = Math.Min(smallestY, imagePoints[i].Y);
}
System.Drawing.Rectangle rectCrop = new System.Drawing.Rectangle(smallestX, smallestY, biggestX - smallestX, biggestY - smallestY);
return rectCrop;
}
public static Mat BitmapToMat(Bitmap bitmap)
{
Mat tmp, tmp2;
System.Drawing.Rectangle bRect = new System.Drawing.Rectangle(new System.Drawing.Point(0, 0), new System.Drawing.Size((int)bitmap.Width, (int)bitmap.Height));
BitmapData bmData = bitmap.LockBits(bRect, ImageLockMode.ReadWrite, bitmap.PixelFormat);
tmp2 = new Mat(new OpenCvSharp.Size(bitmap.Width, bitmap.Height), MatType.CV_8U);
tmp = new Mat(bitmap.Height, bitmap.Width, MatType.CV_8UC3, bmData.Scan0);
bitmap.UnlockBits(bmData);
return tmp;
}
“IplImage” ist the old image container from OpenCv 1. As Andreas already mentioned, today you should use “Mat” instead. Have also a look here : Difference between cvMat, Mat and IpImage
Unfortunately, your code sample is not complete, hence I corrected the two methods from the original project ( https://www.codeproject.com/Articles/703519/Cropping-Particular-Region-In-Image-Using-Csharp).
The following methods are tested and work as intended in the original project in combination with the latest OpenCVSharp version (v4.x) . It should be very simple now to convert the changes to your code.
public static Mat BitmapToIplImage(Bitmap bitmap)
{
Mat tmp, tmp2;
Rectangle bRect = new Rectangle(new System.Drawing.Point(0, 0), new System.Drawing.Size((int)bitmap.Width, (int)bitmap.Height));
BitmapData bmData = bitmap.LockBits(bRect, ImageLockMode.ReadWrite, bitmap.PixelFormat);
tmp2 = new Mat(new Size(bitmap.Width, bitmap.Height), MatType.CV_8U);
tmp = new Mat(bitmap.Height, bitmap.Width, MatType.CV_8UC3, bmData.Scan0);
bitmap.UnlockBits(bmData);
return tmp;
}
private void crop()
{
timer1.Stop();
Graphics Ga = Graphics.FromImage(bmp);
//the black image
Ga.FillRectangle(new SolidBrush(Color.Black), new Rectangle(0, 0, bmp.Width, bmp.Height));
//draw from the last point to first point
Ga.DrawLine(new Pen(Color.Red, 3), polygonPoints[polygonPoints.Count - 1], polygonPoints[0]);
//all of the rgb values are being set 1 inside the polygon
SolidBrush Brush = new SolidBrush(Color.FromArgb(1, 1, 1));
//we have to prepare one mask of Multiplying operation for cropping region
G.FillClosedCurve(Brush, polygonPoints.ToArray());
var accc= (BitmapToIplImage(Source).Mul(BitmapToIplImage(bmp))).ToMat();
computecrop();
croplast = accc.ToBitmap().Clone(rectcrop, Source.PixelFormat);//just show cropped region part of image
pictureBox2.Image = croplast; // crop region of image
}
I had an error come up:
A Graphics Object cannot be Created from an Image that has an Indexed Pixel Format
So I implemented this code into my method: Solution for "A Graphics Object cannot be Created from an Image that has an Indexed Pixel Format"
But now my watermark doesnt want to draw on my image.
Please can anyone assist.
Code:
private Image AddWaterMark(Image original)
{
Image waterMark = Image.FromFile(ConfigurationManager.AppSettings["GalleryFolder"] + #"\watermark.png");
Bitmap bm = (Bitmap)original;
Size waterMarkResize = ResizeFit(new Size(original.Width, original.Height));
using (Image watermarkImage = new Bitmap(waterMark, waterMarkResize))
using (Graphics imageGraphics = Graphics.FromImage(new Bitmap(bm.Width, bm.Height)))
{
imageGraphics.DrawImage(bm, new Rectangle(0, 0, bm.Width, bm.Height), 0, 0, bm.Width, bm.Height, GraphicsUnit.Pixel);
using (TextureBrush watermarkBrush = new TextureBrush(watermarkImage))
{
int x = (original.Width / 2 - watermarkImage.Width / 2);
int y = (original.Height / 2 - watermarkImage.Height / 2);
watermarkBrush.TranslateTransform(x, y);
imageGraphics.FillRectangle(watermarkBrush, new Rectangle(new Point(x, y), new Size(watermarkImage.Width + 1, watermarkImage.Height)));
}
}
return bm;
}
You're creating a new Bitmap to pass to Graphics.FromImage then returning the uneditted original Bitmap. Create the new Bitmap independently, pass it to FromImage then return the new Bitmap.
var edit = new Bitmap(bm.Width, bm.Height);
// ...
using (Graphics imagesGraphics = Graphics.FromImage(edit))
{
// draw original
// draw watermark
}
return edit;
Good day
i don't know if my title is correct. sorry for my bad english
How to overlay two picturebox using c# inoder to achieve the image below, and change the opacity of upper picture box on runtime.
what i need to achieve is something like this. i have two images and i need to overlay them
first image:
enter image description here
and i have second image with a text of: Another Text on image.
and the location of the text is lower than the text location of the first image
(i can't upload more than two image because i don't have 10 reputation yet.)
i need to do like on the image below, but using two picturebox and can change the opacity in order for the second picturebox below the first one to be seen
and the output of the two image:
enter image description here
i created the output image using java. i know that i can run the jar file using c#. but the user required to changed the opacity on run time. so how can i do this?
this is the java code i used
BufferedImage biInner = ImageIO.read(inner);
BufferedImage biOutter = ImageIO.read(outter);
System.out.println(biInner);
System.out.println(biOutter);
Graphics2D g = biOutter.createGraphics();
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
int x = (biOutter.getWidth() - biInner.getWidth()) / 2;
int y = (biOutter.getHeight() - biInner.getHeight()) / 2;
System.out.println(x + "x" + y);
g.drawImage(biInner, x, y, null);
g.dispose();
ImageIO.write(biOutter, "PNG", new File(output));
i hope my question is understandable. thank you
Here you go, just a sample, but blueBox is transparent (0.5):
public sealed partial class Form1 : Form
{
private readonly Bitmap m_BlueBox;
private readonly Bitmap m_YellowBox;
public Form1()
{
InitializeComponent();
DoubleBuffered = true;
m_YellowBox = CreateBox(Color.Yellow);
m_BlueBox = CreateBox(Color.Blue);
m_BlueBox = ChangeOpacity(m_BlueBox, 0.5f);
}
public static Bitmap ChangeOpacity(Image img, float opacityvalue)
{
var bmp = new Bitmap(img.Width, img.Height);
using (var graphics = Graphics.FromImage(bmp))
{
var colormatrix = new ColorMatrix();
colormatrix.Matrix33 = opacityvalue;
var imgAttribute = new ImageAttributes();
imgAttribute.SetColorMatrix(colormatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
graphics.DrawImage(img, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, img.Width, img.Height,
GraphicsUnit.Pixel, imgAttribute);
}
return bmp;
}
private static Bitmap CreateBox(Color color)
{
var bmp = new Bitmap(200, 200);
for (var x = 0; x < bmp.Width; x++)
{
for (var y = 0; y < bmp.Height; y++)
{
bmp.SetPixel(x, y, color);
}
}
return bmp;
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(m_YellowBox, new Point(10, 10));
e.Graphics.DrawImage(m_BlueBox, new Point(70, 70));
}
}
My code:
private void CreateAnimatedGif(List<string> GifsFilesRadar , List<string> GifsFilesSatellite)//string FileName1 , string FileName2)
{
Bitmap bitmap = null;
DirectoryInfo inf = new DirectoryInfo(tempGifFiles);
FileInfo[] fi = inf.GetFiles("*.gif");
for (int i = 0; i < fi.Length; i++)
{
Bitmap file1 = new Bitmap(GifsFilesRadar[i]);
Bitmap file2 = new Bitmap(GifsFilesSatellite[i]);
//calculate the new width proportionally to the new height it will have
int newWidth = file1.Width + file1.Width / (file2.Height / (file2.Height - file1.Height));
bitmap = new Bitmap(newWidth + file2.Width, Math.Max(file1.Height, file2.Height));
using (Graphics g = Graphics.FromImage(bitmap))
{
//high quality rendering and interpolation mode
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
//resize the left image
g.DrawImage(file1, new Rectangle(0, 0, newWidth, file2.Height));
g.DrawImage(file2, newWidth, 0);
string t = #"d:\GifsForAnimations" + "\\" + i.ToString("D6") + ".Gif";
bitmap.Save(t, System.Drawing.Imaging.ImageFormat.Gif);
if (i == 4)
{
break;
}
}
}
List<string> gif = new List<string>();
DirectoryInfo info = new DirectoryInfo(#"d:\GifsForAnimations");
FileInfo[] finfo = info.GetFiles();
for (int i = 0; i < finfo.Length; i++)
{
gif.Add(finfo[i].FullName);
}
newFile.MakeGIF(gif, #"d:\newGifAnim.gif", 80, true);
}
In the end I have new animated gif file.
Now I have the border and these are the locations:
Bottom left corner: 232.0,408.0
Top left corner: 232.0,211.0
Top right corner: 524.0,211.0
Bottom right corner: 524.0,408.0
I want to add on each image a frame around it to mark the border around. Let's say the border will be in Red and the border line size will be 5 pixels.
How can I create the rectangle around existing bitmap or gif file ?
It doesn't have to be connected to my example code here but how do I create the frame/border around the image with the locations I have ?
You could add this line after g.DrawImage(file2, newWidth, 0);
g.DrawRectangle(new Pen(Brushes.Red, 5), new Rectangle(0, 0, newWidth, file2.Height));
Here is a small test method so you can see it working
private void button1_Click(object sender, EventArgs e)
{
Bitmap bitmap = new Bitmap(#"C:\avatar63.jpg");
using (Graphics g = Graphics.FromImage(bitmap))
{
g.DrawRectangle(new Pen(Brushes.Red, 5), new Rectangle(0, 0, bitmap.Width, bitmap.Height));
}
bitmap.Save(#"C:\avatar63New.jpg");
}
Before: After:
You can add the rectagle anywhere you want, tou jst need to supply the X,Y,Width,Height
g.DrawRectangle(new Pen(Brushes.LimeGreen, 5), new Rectangle(50, 50, 100, 100));
Using your 4 point structure this should work
Point topLeft = new Point(232,211 );
Point topRightr = new Point(232, 408);
Point bottomLeft = new Point(524, 211);
Point bottomRight = new Point(524, 408);
g.DrawRectangle(new Pen(Brushes.LimeGreen, 5), new Rectangle(topLeft, new Size(topRightr.X - topLeft.X, bottomLeft.Y - topLeft.Y)));
// TopLeft = rectangle location
// TopRight.X - TopLeft.X = Width of rectangle
// BottomLeft.Y - TopLeft.Y = height of rectangle
I have two Bitmaps, named largeBmp and smallBmp. I want to draw smallBmp onto largeBmp, then draw the result onto the screen. SmallBmp's white pixels should be transparent. Here is the code I'm using:
public Bitmap Superimpose(Bitmap largeBmp, Bitmap smallBmp) {
Graphics g = Graphics.FromImage(largeBmp);
g.CompositingMode = CompositingMode.SourceCopy;
smallBmp.MakeTransparent();
int margin = 5;
int x = largeBmp.Width - smallBmp.Width - margin;
int y = largeBmp.Height - smallBmp.Height - margin;
g.DrawImage(smallBmp, new Point(x, y));
return largeBmp;
}
The problem is that the result winds up transparent wherever smallBmp was transparent! I just want to see through to largeBmp, not to what's behind it.
CompositingMode.SourceCopy is the problem here. You want CompositingMode.SourceOver to get alpha blending.
Specify the transparency color of your small bitmap. e.g.
Bitmap largeImage = new Bitmap();
Bitmap smallImage = new Bitmap();
--> smallImage.MakeTransparent(Color.White);
Graphics g = Graphics.FromImage(largeImage);
g.DrawImage(smallImage, new Point(10,10);
Winform copy image on top of another
private void timerFFTp_Tick(object sender, EventArgs e)
{
if (drawBitmap)
{
Bitmap bitmap = new Bitmap(_fftControl.Width, _fftControl.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
_fftControl.DrawToBitmap(bitmap, new Rectangle(0, 0, _fftControl.Width, _fftControl.Height));
if (!fDraw)
{
bitmap.MakeTransparent();
Bitmap fftFormBitmap = new Bitmap(_fftForm.BackgroundImage);
Graphics g = Graphics.FromImage(fftFormBitmap);
g.DrawImage(bitmap, 0, 0);
_fftForm.BackgroundImage = fftFormBitmap;
}
else
{
fDraw = false;
_fftForm.Width = bitmap.Width + 16;
_fftForm.Height = bitmap.Height + 48;
_fftForm.BackgroundImage = bitmap;
}
}
}