System.Drawing.Image from ImageSource in Resources - c#

My question is very similar to this one: wpf image resources and changing image in wpf control at runtime, but with a slight twist.
Here is my ResourceDictionary.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ImageSource x:Key="DisconnectedIcon">Images/disconnect.png</ImageSource>
<ImageSource x:Key="Synced">Images/tick.png</ImageSource>
<ImageSource x:Key="NotSynced">Images/x.png</ImageSource>
As for the C# code behind, I am able to load the ImageSource from the resources with the following. In which, I am able to see the metadata and the image name, but can't figure out how to get it into a System.Drawings.Image.
var imageSource = (ImageSource)Application.Current.FindResource("Synced");
System.Drawing.Image img = Image.FromFile(???)
The reason I am trying to convert it to a System.Drawing.Image is to send it to a printer.
Thanks!

In WPF, every UI element extends the Visual Class which Provides rendering support in WPF. There is also a RenderTargetBitmap Class that has a Render Method that takes a Visual object as an input parameter. So you could set your ImageSource as the Source property of an Image and simply render the Image to a Bitmap image:
Image yourImageObject = new Image();
yourImageObject.Source = yourImageSource;
RenderTargetBitmap renderTargetBitmap =
new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Default);
renderTargetBitmap.Render(yourImageObject);
// Save to .png file
PngBitmapEncoder pngBitmapEncoder = new PngBitmapEncoder();
pngBitmapEncoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
using (Stream stream = File.Create(filepath))
{
pngBitmapEncoder.Save(stream);
}
As this is well documented on the internet, I won't bother to repeat the whole story here. To find out the full story, please see the How to Render Bitmap or to Print a Visual in WPF page from the Dot NET Tricks website, which will also help you with your printing requirement.

Related

How to resize a BitmapImage from another BitmapImage in memory and not on filesystem

This is the continuation of
Datacontract serialization/serialization with images
so now I have a BitmapImage coming from a stream. In short a BitmapImage
I want to resize it to a desired size.
I have found tons of code on how to resize from an image on file system but none on how to resize from an already existing BitmapImage
EDIT:
You may use a TransformedBitmap with an appropriate ScaleTransform:
BitmapImage sourceBitmap = ...
var targetBitmap = new TransformedBitmap(sourceBitmap, new ScaleTransform(0.5, 0.5));
The result is a TransformedBitmap, not a BitmapImage. However, this shouldn't matter, because in your application there should be no need to deal only with BitmapImages. It should be sufficient to do all image-related stuff with the base classes BitmapSource or even ImageSource, which is the type of the Source property of the Image control.

Is there a workaround for overlaying transparent images from resources?

Right now I have a form with a PictureBox on the form. I'm using two partially transparent images and trying to put one on top of the other.
sideMenuWide = rounded rectangle with transparent background (.png) [Bottom image]
labelPointer = triangle with transparent background (.png) [Top image]
Here is my approach:
// METHOD #1 //
Image img1 = Image.FromFile(#"C:\sideMenuWide.png");
Image img2 = Image.FromFile(#"C:\labelPointer.png");
picBox.Image = CombineImages(img1, img2);
// METHOD #2 //
Image imgA = RBS.Properties.Resources.sideMenuWide;
Image imgB = RBS.Properties.Resources.labelPointer;
picBox.Image = CombineImages(imgA, imgB);
And the CombineImage function: (I did not write this function, only modified)
public static Bitmap CombineImages(Image imgA, Image imgB)
{
//a holder for the result (By default, use the first image as the main size)
Bitmap result = new Bitmap(imgA.Size.Width, imgA.Size.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 images into the target bitmap
graphics.DrawImage(imgA, 0, 0, imgA.Width, imgA.Height);
graphics.DrawImage(imgB, 100, 70, imgB.Width, imgB.Height);
}
return result;
}
Method #1 DOES work how I want it to, displays imgB perfectly on top of imgA.
Method #2 however shows imgA just fine but imgB is really faint.
Any ideas on how to overcome this? I would like to be able to do this using Resources instead of having to pull from a file.
If the files work when loaded, but the resources don't, then it sounds like the resx build process or the ResourceManager is doing something undesirable. I'd try embedding the files and reading them directly from a stream rather than relying on the ResourceManager to do it for you.
In your Solution Explorer, Add Existing File to add the file to your project. Get properties on the added file and set it to Embedded Resource=. (Don't add it to a resx file)
In your code, you can now get a stream containing the file's data:
Stream instream = Assembly.GetExecutingAssembly().
GetManifestResourceStream("RBS.labelPointer.png"));
(Hint: The compiler generates an obtuse name for the embedded resource, so after adding the files you can add temporary code to call Assembly.GetExecutingAssembly().GetManifestResourceNames() to get a list of them all and find the file you're interested in)
Load your bitmap/image from the stream:
Image img2 = new Bitmap(inStream);

IO.Stream to Image in WPF

I am trying to read an image from a resource only DLL file. I am able to read the image name and image bytes, but How do I set the Image control to stream buffer? In windows form, I know I can use this :
pictureBox1.Image=new System.Drawing.Bitmap(IOStream);
since there is no Drawing namespace in wpf, how can I achieve the same thing?
In WPF, you can set the Source property of an Image, as in this example:
Image image = new Image();
using (MemoryStream stream = new MemoryStream(byteArray))
{
image.Source = BitmapFrame.Create(stream,
BitmapCreateOptions.None,
BitmapCacheOption.OnLoad);
}
Where byteArray is the array of bytes with the source of the image.
In WPF you probably have an Image element in your xaml. The Source can be any BitmapImage. You can bind a BitmapImage from your ViewModel, where you can create an instance from a Stream like this.

How to make my image transparent?

I know how to make an image control transparent in C#, but is there a way to make the image (the .jpeg file, not the image control) transparent?
Or, is there a way, when I make the image control transparent, to create new image, save it in some path and give it the other image control's content?
The JPEG file cannot be transparent. However, if you save it as a PNG image it will have a transparency channel.
GIFS also support transparency, but only either completely opaque or completely transparent. Nothing in between.
PNG is your best bet here IMO.
You can set the Image-Controls's Opacity-Property to view it with transparence.
But to get an image-file with transparency, you'll have to render it into a new file.
Here's an example how you can do it.
Image image = new Image(); //or however you get this
image.Opacity = 0.5;
RenderTargetBitmap bmp = new RenderTargetBitmap(image.Source.Width, image.Source.Height, 96, 96, PixelFormats.Pbgra32);
bmp.Render(image);
PngBitmapEncoder png = new PngBitmapEncoder();
png.Frames.Add(BitmapFrame.Create(bmp));
using (Stream fs= File.Create("test.png"))
{
png.Save(fs);
}
There is property transparencycolor. That is what you need if you want to display image on control.

Using RenderTargetBitmap to save a portion of the displayed images

I have a simple WPF application where I display one very large image (9000x2875) and on top of it, many small images (64x64).
To do this, I have a Canvas with one Image, then I programatically add the small images as they arrive.
Now I am trying to save portions of the composite image as png files. I thought I would use a RenderTargetBitmap to render the portion of the Canvas that I wanted. My problem is that I cannot find a good way to save the right portion of the image. Here is a my current hack:
private static void SaveImage(Canvas canvas, string file, int x, int y, int width, int height)
{
//changing 0,0 on the canvas so RenderTargetBitmap works as expected.
canvas.RenderTransform = new MatrixTransform(1d, 0d, 0d, 1d, -x, -y);
canvas.UpdateLayout();
RenderTargetBitmap bmp = new RenderTargetBitmap(width, height, 96d, 96d, Pixelformats.Pbgra32);
bmp.Render(canvas);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bmp));
using(Stream s = File.Create(file))
{
encoder.Save(s);
}
}
The obvious problem with this is that the display will change due to the RenderTransform. It also makes the application slower. I did try to do a RenderTargetBitmap of the entire canvas, but that was much slower than doing this.
So my questions are:
Is there an easier way to save just a portion of the viewed image?
If not, does someone have a suggestion for a better way to go about this? (I already tried a single WriteableBitmap, but that was about as slow as doing the RenderTargetBitmap of the entire canvas.
What you want to use is a CroppedBitmap, which will allow you to save a cropped portion of your image.
// (BitmapSource bmps)
CroppedBitmap crop = new CroppedBitmap(bmps, new Int32Rect(selRect.X, selRect.Y, selRect.Width, selRect.Height));
Edit: Since there seems to be no way to get this to perform the way you want in WPF I would suggest pre-cropping the large image using GDI+ (without displaying it) and loading the region of it you want onto a smaller canvas.

Categories