Capture screenshot of control with different DPI - c#

I can capture screenshot of control for normal 100% DPI. But when the DPI changed to 125% then the screenshot is not proper. Please suggest approach so that the screenshot can be captured with any DPI. Following is the code
// Get absolute location on screen of upper left corner of button
System.Windows.Point locationFromScreen = this.sv.PointToScreen(new System.Windows.Point(0, 0));
// Transform screen point to WPF device independent point
PresentationSource source = PresentationSource.FromVisual(this);
System.Windows.Point targetPoints = source.CompositionTarget.TransformFromDevice.Transform(locationFromScreen);
var bmpScreenshot = new Bitmap((int)sv.ActualWidth,
(int)sv.ActualHeight,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
// Create a graphics object from the bitmap.
var gfxScreenshot = Graphics.FromImage(bmpScreenshot);
gfxScreenshot.CopyFromScreen((int)targetPoints.X,
(int)targetPoints.Y,
0,
0,
new System.Drawing.Size((int)sv.ActualWidth, (int)sv.ActualHeight),
CopyPixelOperation.SourceCopy);
byte[] data;
using (var stream = new System.IO.MemoryStream())
{
bmpScreenshot.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
data = stream.ToArray();
}
var result = Convert.ToBase64String(data);
winObj = new Window1();
MemoryStream ms = new MemoryStream();
((System.Drawing.Bitmap)bmpScreenshot).Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
BitmapImage image = new BitmapImage();
image.BeginInit();
ms.Seek(0, SeekOrigin.Begin);
image.StreamSource = ms;
image.EndInit();
winObj.imageViewer.Source = image;
winObj.ShowDialog();
bmpScreenshot.Dispose();

Related

BitmapImage -> Bitmap -> Mat -> Bitmap ->BitmapImage Convert

I'm developing a kind of real-time video chatting and also trying to make a binary image using OpenCV. I'm working on C# WPF and I have to draw images on Canvas. This means I need 'BitmapImage' to draw the screen. But I have to use 'Mat' to make a binary image.
So I tried many solutions found from StackOverflow but never worked for me.
Below is my code.
Mat tempMat = new Mat();
Bitmap tempImage = BitmapImage2Bitmap(tempOriginal);
tempMat = BitmapConverter.ToMat(tempImage);
Converting BitmapImage to Bitmap first, and then convert Bitmap to Mat.
After that, make image binary. Below is the code.
Mat hsv = new Mat();
Mat binary = new Mat();
Cv2.CvtColor(tempMat, hsv, ColorConversionCodes.BGR2HSV);
Cv2.InRange(hsv, new Scalar(minH, minS, minV), new Scalar(maxH, maxS, maxV), binary);
tempMat = binary.Clone();
binary.Release();
hsv.Release();
After this operation, convert the mat back to Bitmap and BitmapImage again.
Below is the code.
tempImage = BitmapConverter.ToBitmap(tempMat);
BitmapImage resultBitmap = Bitmap2BitmapImage(tempImage);
ipWindow.ipView.ImageSource = resultBitmap;
I searched a lot and tried several solutions to change Bitmap to BitmapImage and vice versa.
But never worked. Below codes are solutions I tried.
I'm new to C# and also WPF, so I have no idea how to solve this problem.
Thanks for reading this long question.
Solution1. BitmapImage -> Bitmap
private Bitmap BitmapImage2Bitmap(BitmapImage bitmapImage){
using (MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapImage));
enc.Save(outStream);
Bitmap bitmap = new Bitmap(outStream);
outStream.Close();
return new Bitmap(bitmap);
}
}
Solution1. Bitmap -> BitmapImage
private BitmapImage Bitmap2BitmapImage(Bitmap bitmap){
BitmapSource i = Imaging.CreateBitmapSourceFromHBitmap(
bitmap.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
return (BitmapImage)i;
}
Solution2. Bitmap -> BitmapImage
private BitmapImage Bitmap2BitmapImage(Bitmap inputBitmap){
Bitmap bitmap = new Bitmap(inputBitmap.Width, inputBitmap.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
MemoryStream ms = new MemoryStream();
bitmap.Save(ms, ImageFormat.Bmp);
var bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = ms;
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.EndInit();
return bi;
}
Solution3. Bitmap -> BitmapImage
private BitmapImage Bitmap2BitmapImage(Bitmap inputBitmap){
using (var memory = new MemoryStream())
{
inputBitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
Solution4. Bitmap -> BitmapImage
private BitmapImage Bitmap2BitmapImage(Bitmap inputBitmap){
MemoryStream ms = new MemoryStream();
inputBitmap.Save(ms, ImageFormat.Bmp);
BitmapImage image = new BitmapImage();
image.BeginInit();
ms.Seek(0, SeekOrigin.Begin);
image.StreamSource = ms;
image.EndInit();
return image;
}
I solved. The problems were two.
One was OpenCvSharp and another was Bitmap to BitmapImage.
Actually OpenCvSharp problem was severe so I couldn't find proper solutions between above. But after I uninstall and reinstall the openCvSharp, I found out what solution works for me. The code is below.
private BitmapImage Bitmap2BitmapImage(Bitmap inputBitmap)
{
using (var memory = new MemoryStream())
{
inputBitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
}

WPF image to form picture picturebox [duplicate]

I'm tying together two libraries. One only gives output of type System.Windows.Media.Imaging.BitmapSource, the other only accepts input of type System.Drawing.Image.
How can this conversion be performed?
private System.Drawing.Bitmap BitmapFromSource(BitmapSource bitmapsource)
{
System.Drawing.Bitmap bitmap;
using (MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapsource));
enc.Save(outStream);
bitmap = new System.Drawing.Bitmap(outStream);
}
return bitmap;
}
This is an alternate technique that does the same thing. The accepted answer works, but I ran into problems with images that had alpha channels (even after switching to PngBitmapEncoder). This technique may also be faster since it just does a raw copy of pixels after converting to compatible pixel format.
public Bitmap BitmapFromSource(System.Windows.Media.Imaging.BitmapSource bitmapsource)
{
//convert image format
var src = new System.Windows.Media.Imaging.FormatConvertedBitmap();
src.BeginInit();
src.Source = bitmapsource;
src.DestinationFormat = System.Windows.Media.PixelFormats.Bgra32;
src.EndInit();
//copy to bitmap
Bitmap bitmap = new Bitmap(src.PixelWidth, src.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
var data = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
src.CopyPixels(System.Windows.Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
bitmap.UnlockBits(data);
return bitmap;
}

Convert WriteableBitmap to BitmapImage using BmpBitmapEncoder WPF

I have a problem with Convert WriteableBitmap to BitmapImage using BmpBitmapEncoder.
this is my method:
public BitmapImage ConvertWriteableBitmapToBitmapImage(WriteableBitmap wbm)
{
bmp = new BitmapImage();
using (MemoryStream stream = new MemoryStream())
{
/*PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(wbm));
encoder.Save(stream);*/
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(wbm));
encoder.Save(stream);
bmp.BeginInit();
bmp.UriSource = new Uri(MyImage.Source.ToString());
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.CreateOptions = BitmapCreateOptions.IgnoreImageCache | BitmapCreateOptions.PreservePixelFormat;
bmp.StreamSource = stream;
bmp.EndInit();
bmp.Freeze();
}
return bmp;
}
I'm using BmpBitmapEncoder because this is only way to Save without change size of Image(*.bmp). I want to Save Image with changed table of pixels and the specified format pixel (Bgr24). Using BmpBitmapEncoder forces to set bmp.UriSource and this is a problem. WriteableBitmap doesn't have this Property. Moreover, when I comment line //bmp.UriSource shows me an exception: "System.ArgumentNullException" in bmp.EndInit().
When I change my Method to this:
public BitmapImage ConvertWriteableBitmapToBitmapImage(WriteableBitmap wbm)
{
bmp = new BitmapImage();
using (MemoryStream stream = new MemoryStream())
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(wbm));
encoder.Save(stream);
/*BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(wbm));
encoder.Save(stream);*/
bmp.BeginInit();
//bmp.UriSource = new Uri(MyImage.Source.ToString());
bmp.CacheOption = BitmapCacheOption.OnLoad;
//bmp.CreateOptions = BitmapCreateOptions.IgnoreImageCache | BitmapCreateOptions.PreservePixelFormat;
bmp.StreamSource = stream;
bmp.EndInit();
bmp.Freeze();
}
return bmp;
}
everything works fine but the result is the Image increase size and change pixel format to Bgr32 and this is not the result, what I expect. My method which Save Image is fine because I tested it on unchanged pixels and the result is good - Image don't change format and size. Plz help me with this.
For changing pixel formats WPF has the FormatConvertedBitmap class, which is a BitmapSource:
WriteableBitmap wbm;
...
var bm = new FormatConvertedBitmap(wbm, PixelFormats.Bgr24, null, 0);
It is not a BitmapImage, but you do not really need that anywhere. All WPF methods and properties (e.g. Image.Source) use either ImageSource or the derived BitmapSource as their type. There is no API that explicitly needs a BitmapImage, so conversion to BitmapImage is never necessary.
I resolve this problem. This is a code which Convert WriteableBitmap to BitmapImage using BmpBitmapEncoder. Using this method ensure us, that our Image while saving stay unchanged. Unchanged I mean - size don't increase and Format Pixel stay on Bgr24.
public BitmapImage ConvertWriteableBitmapToBitmapImage(WriteableBitmap wbm)
{
bmp = new BitmapImage();
using (MemoryStream stream = new MemoryStream())
{
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(wbm));
encoder.Save(stream);
bmp.BeginInit();
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
bmp.StreamSource = new MemoryStream(stream.ToArray()); //stream;
bmp.EndInit();
bmp.Freeze();
}
return bmp;
}

Drag Drop Image Transparency In VSTO 2013 Add-In

I have a WPF control in my PowerPoint add-in that hosts an image that I want to be able to drag & drop onto the active slide. I can get the image to appear on the slide, but the transparent areas are rendered in black.
My code to initialize the drag from my attached behavior:
var targetBitmap = new RenderTargetBitmap(
(int) MyWpfControl.ActualWidth,
(int) MyWpfControl.ActualHeight,
96d, 96d, PixelFormats.Default);
targetBitmap.Render(MyWpfControl);
var dataObject = new DataObject(
DataFormats.Bitmap,
targetBitmap);
DragDrop.DoDragDrop(MyWpfControl, dataObject, DragDropEffects.Copy)
Thinking that maybe I needed to pass a System.Drawing.Image, I attempted this modification, which only resulted in the transparent areas being rendered in gray:
var targetBitmap = new RenderTargetBitmap(
(int) MyWpfControl.ActualWidth,
(int) MyWpfControl.ActualHeight,
96d, 96d, PixelFormats.Default);
targetBitmap.Render(MyWpfControl);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(targetBitmap));
var ms = new MemoryStream();
encoder.Save(ms);
var dataObject = new DataObject(DataFormats.Bitmap, Image.FromStream(ms, true))
DragDrop.DoDragDrop(MyWpfControl, dataObject, DragDropEffects.Copy)
I did a test where I replaced the memory stream with a file stream, and the image that was written did indeed have the correct transparency.
So what am I missing here? How can I maintain transparency?
I was able to resolve this by following the instructions in this blog post. The solution was to use the EnhancedMetafile DataFormat in my DataObject.
Edit:
Here’s the code that initiates the drag operation.
private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Bitmap bitmap = ImageToBitmap(e.Source as System.Windows.Controls.Image);
DataObject data = new DataObject(DataFormats.EnhancedMetafile, MakeMetafileStream(bitmap));
DragDrop.DoDragDrop((DependencyObject)e.Source, data, DragDropEffects.Copy);
}
This makes use of a utility function to convert the Image to a Bitmap:
private Bitmap ImageToBitmap(System.Windows.Controls.Image image)
{
RenderTargetBitmap rtBmp = new RenderTargetBitmap((int)image.ActualWidth, (int)image.ActualHeight,
96.0, 96.0, PixelFormats.Pbgra32);
image.Measure(new System.Windows.Size((int)image.ActualWidth, (int)image.ActualHeight));
image.Arrange(new Rect(new System.Windows.Size((int)image.ActualWidth, (int)image.ActualHeight)));
rtBmp.Render(image);
PngBitmapEncoder encoder = new PngBitmapEncoder();
MemoryStream stream = new MemoryStream();
encoder.Frames.Add(BitmapFrame.Create(rtBmp));
// Save to memory stream and create Bitamp from stream
encoder.Save(stream);
return new System.Drawing.Bitmap(stream);
}
This also requires a utility function that converts a Bitmap to a stream containing a Metafile, taken from Stack Overflow.
// From Convert an image into WMF with .NET?
private MemoryStream MakeMetafileStream(Bitmap image)
{
Graphics graphics = null;
Metafile metafile = null;
var stream = new MemoryStream();
try
{
using (graphics = Graphics.FromImage(image))
{
var hdc = graphics.GetHdc();
metafile = new Metafile(stream, hdc);
graphics.ReleaseHdc(hdc);
}
using (graphics = Graphics.FromImage(metafile))
{ graphics.DrawImage(image, 0, 0); }
}
finally
{
if (graphics != null)
{ graphics.Dispose(); }
if (metafile != null)
{ metafile.Dispose(); }
}
return stream;
}

How to crop a tiff image in asp.net

I was looking for a routine by which I can crop tiff image and I got it but it gives many error. Here is the routine:
Bitmap comments = null;
string input = "somepath";
// Open a Stream and decode a TIFF image
using (Stream imageStreamSource = new FileStream(input, FileMode.Open, FileAccess.Read, FileShare.Read))
{
TiffBitmapDecoder decoder = new TiffBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
BitmapSource bitmapSource = decoder.Frames[0];
using (Bitmap b = BitmapFromSource(bitmapSource))
{
Rectangle cropRect = new Rectangle(169, 1092, 567, 200);
comments = new Bitmap(cropRect.Width, cropRect.Height);
//first cropping
using (Graphics g = Graphics.FromImage(comments))
{
g.DrawImage(b, new Rectangle(0, 0, comments.Width, comments.Height),
cropRect,
GraphicsUnit.Pixel);
}
}
}
When I try to compile it, I get an error. I tried adding references to many assemblies searching google but couldn't resolve it. I got this code from this url:
http://snipplr.com/view/63053/
I am looking for advice.
TiffBitmapDecoder class is from Presentation.Core in another words it is from WPF.
BitmapFromSource isn't method of any .net framework class. You can convert BitmapSource to Bitmap using this code.
private Bitmap BitmapFromSource(BitmapSource bitmapsource)
{
Bitmap bitmap;
using (MemoryStream outStream = new MemoryStream())
{
BitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapsource));
encoder.Save(outStream);
bitmap = new Bitmap(outStream);
}
return bitmap;
}

Categories