in Winform application, i have a user control; on which shapes like rectangle,circle etc. are drawn.
i am trying to take snapshot of the same by using DrawToBitmap() method.
i have a Bitmap of fixed size(300 x 300) and user control is of size (600 x 800)
so the taken snapshot contains only part of the user control.
how to get the snapshot of entire user control in the bitmap ?
thanks in advance.
You can use the following approach:
static void DrawControlToImage(Control ctrl, Image img) {
Rectangle sourceRect = ctrl.ClientRectangle;
Size targetSize = new Size(img.Width, img.Height);
using(Bitmap tmp = new Bitmap(sourceRect.Width, sourceRect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) {
ctrl.DrawToBitmap(tmp, sourceRect);
using(Graphics g = Graphics.FromImage(img)) {
g.DrawImage(tmp, new Rectangle(Point.Empty, targetSize));
}
}
}
Related
I am searching a solution on how to save the content of a form in a bitmap with C#.
I have already tried to use DrawToBitmap, but it captures all the window with the border.
That is the result of this code:
public static Bitmap TakeDialogScreenshot(Form window)
{
var b = new Bitmap(window.Bounds.X, window.Bounds.Y);
window.DrawToBitmap(b, window.Bounds);
return b;
}
Call is:
TakeDialogScreenshot(this);
Who thought it :D
I have already searched on google, but I did not manage to get it. Thanks!
Edit: While using the ClientArea is key, it isn't quite enough, as DrawToBitmap will always include the title, borders, scrollbars..
So after taking the full screen- or rather 'formshot', we'll have to crop it, using an offset we can get from mapping the origin of the clientarea to the screen coordinates and subtracting these from the form location, which already is in screen coordinates..:
public static Bitmap TakeDialogScreenshot(Form window)
{
var b = new Bitmap(window.Width, window.Height);
window.DrawToBitmap(b, new Rectangle(0, 0, window.Width, window.Height));
Point p = window.PointToScreen(Point.Empty);
Bitmap target = new Bitmap( window.ClientSize.Width, window.ClientSize.Height);
using (Graphics g = Graphics.FromImage(target))
{
g.DrawImage(b, 0, 0,
new Rectangle(p.X - window.Location.X, p.Y - window.Location.Y,
target.Width, target.Height),
GraphicsUnit.Pixel);
}
b.Dispose();
return target;
}
Sorry for the error in my first post!
I have a .png image i wish to overlay on a base image.
My overlay image contains just a red slant line. I need to get the red line overlayed on the base image at the same co-ordinate as it is in overlay image.
The problem is I do not have the co-ordinates location.
I need to find it programmatically with C#. The overlay image will always be transparent or of white background. What code to find the line co-ordinates from overlay image?
You can create new image, render background image first and then render overlay image over it. Since overlay has alpha channel and line is placed where it should be (i mean there is opaque space on top and left side of line) you do not need coordinates. Illustration code:
Image imageBackground = Image.FromFile("bitmap1.png");
Image imageOverlay = Image.FromFile("bitmap2.png");
Image img = new Bitmap(imageBackground.Width, imageBackground.Height);
using (Graphics gr = Graphics.FromImage(img))
{
gr.DrawImage(imageBackground, new Point(0, 0));
gr.DrawImage(imageOverlay, new Point(0, 0));
}
img.Save("output.png", ImageFormat.Png);
If you are using WPF, why not use a path for your overlay instead of an image if it is a simple line? This would allow it to scale to any size, and has methods for manipulating its dimensions.
If you are using Winforms, there are some similar graphics drawing capabilities you might leverage. Getting the dimensions of the image should be easy, assuming you're using a PictureBox, the following properties should suffice:
myPictureBox.Top
myPictureBox.Bottom
myPictureBox.Left
myPictureBox.Right
Similarly, for a WPF Image:
myImage.Margin
I already needed to create a blank space around an image and I used the ImageFactory library to do that.
Here is the code. I guess you are capable to figure out how to adjust to your needs.
public static Image ResizedImage(Image image, int desiredWidth, int desiredHeight)
{
Image res = (Bitmap)image.Clone();
Image resizedImage;
ImageLayer imageLayer = new ImageLayer();
try
{
if (res != null)
{
//white background
res = new Bitmap(desiredWidth, desiredHeight, res.PixelFormat);
//image to handle
using (var imgf = new ImageFactory(true))
{
imgf
.Load(image)
.Resize(new ResizeLayer(new Size(desiredWidth, desiredHeight),
ResizeMode.Max,
AnchorPosition.Center,
false));
resizedImage = (Bitmap)imgf.Image.Clone();
}
//final image
if (resizedImage != null)
{
imageLayer.Image = resizedImage;
imageLayer.Size = new Size(resizedImage.Width, resizedImage.Height);
imageLayer.Opacity = 100;
using (var imgf = new ImageFactory(true))
{
imgf
.Load(res)
.BackgroundColor(Color.White)
.Overlay(imageLayer);
res = (Bitmap)imgf.Image.Clone();
}
}
}
}
catch (Exception ex)
{
ex.Message;
}
return res;
}
I have the following task. Take a base image and overlay on it another one. The base image is 8b png as well as overlay.
Here are the base (left) and overlay (right) images.
Here is a result and how it must look.
The picture in the left is a screenshot when one picture is on top of another (html and positioning) and the second is the result of programmatic merging.
As you can see in the screenshot the borders of the text is darker. Also here are the sizes of the images
Base image 14.9 KB
Overlay image 6.87 KB
Result image 34.8 KB
The size of the resulting image is also huge
Here is my code that I use to merge those pictures
/*...*/
public Stream Concatinate(Stream baseStream, params Stream[] overlayStreams) {
var #base = Image.FromStream(baseStream);
var canvas = new Bitmap(#base.Width, #base.Height);
using (var g = canvas.ToGraphics()) {
g.DrawImage(#base, 0, 0);
foreach (var item in overlayStreams) {
using (var overlayImage = Image.FromStream(item)) {
try {
Overlay(#base as Bitmap, overlayImage as Bitmap, g);
} catch {
}
}
}
}
var ms = new MemoryStream();
canvas.Save(ms, ImageFormat.Png);
canvas.Dispose();
#base.Dispose();
return ms;
}
/*...*/
/*Tograpics extension*/
public static Graphics ToGraphics(this Image image,
CompositingQuality compositingQuality = CompositingQuality.HighQuality,
SmoothingMode smoothingMode = SmoothingMode.HighQuality,
InterpolationMode interpolationMode = InterpolationMode.HighQualityBicubic) {
var g = Graphics.FromImage(image);
g.CompositingQuality = compositingQuality;
g.SmoothingMode = smoothingMode;
g.InterpolationMode = interpolationMode;
return g;
}
private void Overlay(Bitmap source, Bitmap overlay, Graphics g) {
if (source.Width != overlay.Width || source.Height != overlay.Height)
throw new Exception("Source and overlay dimensions do not match");
var area = new Rectangle(0, 0, source.Width, source.Height);
g.DrawImage(overlay, area, area, GraphicsUnit.Pixel);
}
My questions are
What should I do in order to merge images to achieve the result as in the screenshot?
How can I lower the size of the result image?
Is the System.Drawing a suitable tool for this or is there any better tool for working with png for .NET?
The answers to your questions are:
1) Just call method ToGraphics with a argument CompositingQuality.Default instead of using default argument values like in the example:
using (var g = canvas.ToGraphics(compositingQuality: CompositingQuality.Default))
The problem is with CompositingQuality.HighQuality is that it makes a composition of both images into one, but you want to make an overlay, not to make a composition of two images.
2) The size will be similar to the one you specified and that can not be changed, it is due to a image format.
3) If you are programming in c# for desktop, than System.Drawing is the best choice as far as I know.
am using c#
am having a bitmap image like below
i want create a repeated image like below in horizontal position to get repeted continous image for some given width. i meant i like to draw repeated image like below from the above single bitmap (In simple words,in html we can have a image and set repeat X to get the repeated image.like that) how i can do this in c#.
so that i can draw a new bitmap in my application. How to do this.?
//x- integer value represents no. of times images to repeated horizontally
var destImage = new Bitmap(sourceImage.Width * x, sourceImage.Height, PixelFormat.Format32bppArgb);
using (TextureBrush brush = new TextureBrush(sourceImage, WrapMode.Tile))
using (Graphics g = Graphics.FromImage(destImage))
{
// Do your drawing here
g.FillRectangle(brush, 0, 0, destImage.Width, destImage.Height);
destImage.Save(#"C:\sourceImage.png", ImageFormat.Png);
//mention path of image to save, if needed
}
You can do it like this:
Bitmap myImage = new Bitmap(50, 50); //assuming you want you image to be 50,50
Bitmap originalImage = new Bitmap("myPngSource.png"); //original image to copy
using (Graphics g = Graphics.FromImage(myImage))
{
g.DrawImage(originalImage, new Rectangle(0, 0, originalImage.Width, originalImage.Height));
}
MemoryStream ms = new MemoryStream();
myImage.Save(ms, ImageFormat.Png);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = ms;
bi.EndInit();
MyImageControl.Source = bi;
Or something like that, this is untested, and I just ripped it out of a little utility app I made a while ago. I hope it helps... You just need to change the width of the final image and do a loop over the g.DrawImage call incrementing the second parameter by the width of the originalImage. (i.e. if you want 5 repeats, do a for loop 5 times)
HTH
--Mark
you don't need to create other bitmaps. it's a matter of drawing bitmap. in the place you darw the bitmap use
drawImage method few times and increment the X position of the bitmap by its width. say 16 is the width of your image. make sure that bitmap has been initialized.
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(bmp,x,y);
e.Graphics.DrawImage(bmp,x+16,y);
e.Graphics.DrawImage(bmp,x+32,y);
}
I have a problem with the ListView control in a windows forms application.
Even if I create a thumbnail image or resize the real one I get distorted images in the list view.
The image looks like when you zoom in an image very much.
I first thought that the GetThumbnailImage is couseing this but I used a resize code I found here and I have the same result.
I also did not found any bug related to list view control so I gues I'm doing something wrong but I just can't figure out what.
Here is the code I use:
lsvPictures.LargeImageList = m_imagesList;
lsvPictures.LargeImageList.ImageSize = new Size(100, 100);
lsvPictures.View = View.LargeIcon;
lsvPictures.CheckBoxes = true;
for (int i = 0; i < ofd.FileNames.Length; i++)
{
filename = ofd.FileNames[i].ToString();
ListViewItem lvi = new ListViewItem(filename);
m_imagesList.Images.Add(ResizeImage(Image.FromFile(filename), 100, 100));
lvi.ImageIndex = i;
lsvPictures.Items.Add(lvi);
}
And this is the function that resizes images:
public static System.Drawing.Bitmap ResizeImage(System.Drawing.Image image,
int width, int height)
{
//a holder for the result
Bitmap result = new Bitmap(width, height);
//use a graphics object to draw the resized image into the bitmap
using (Graphics graphics = Graphics.FromImage(result))
{
//set the resize quality modes to high quality
graphics.CompositingQuality =
System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graphics.InterpolationMode =
System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode =
System.Drawing.Drawing2D.SmoothingMode.HighQuality;
//draw the image into the target bitmap
graphics.DrawImage(image, 0, 0, result.Width, result.Height);
}
//return the resulting bitmap
return result;
}
Thank you!
Mosu'
I just found the source of the problems:
m_imagesList.ColorDepth = ColorDepth.Depth16Bit;
It seams that, as default, the ColorDepth of the ImageList is 8 bit (or 4 bit, but my guess is 8). If I change this to at least 16 bit everything looks very nice.
To those with similar problems: I changed my Thumbnail method a lot before I realised that the ListView control is not using the color depth the images were having. I put the result of my method on a PictureBox control and saw that the function was working corectly. Atfer this I googled a lot ... and found that silly ColorDepth property.
How did you set the resolution for your image. Also, did what did you set the PixelFormat value to when you created the bitmap? I have a list of images loading into my list view that I am resizing similar to how you are and it is working fine without any distortion in the resulting thumbnail images that are created.
Here is a snippet from my resize method.
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
bitmap.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.Red);
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.DrawImage(image,
new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight),
new Rectangle(sourceX, sourceY, originalWidth, originalHeight),
GraphicsUnit.Pixel);
}
return bitmap;
I was also using a ListView in WinForms to display directories, and had the same problem. I suggest that you check the image file type: icon files (.ico) tend to end up distorted, so try to use an image file with the .png extension. This works for me:
ListView listView = new ListView();
ImageList imageList = new ImageList();
// add image to list:
imageList.Images.Add("image_key", image_path);
// give the listview the imagelist:
listView.SmallImageList = imageList;
// add item to listview:
listView.Items.Add("item_text", "image_key");