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.
Related
I have been tasked with capturing an image, copy it to the clipboard, and paste it to the application below. I must be able to support pretty much any rich text field, and it must preserve transparency. My current solution first renders a white background. Here is my code:
The RenderTargetBitmap contains the image that I wish to copy as a .PNG
public static void CopyImageToClipboard(RenderTargetBitmap b)
{
MemoryStream stream = new MemoryStream();
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(b));
encoder.Save(stream);
Bitmap bmp = new Bitmap(stream);
Bitmap blank = new Bitmap(Convert.ToInt32(b.Width), Convert.ToInt32(b.Height));
Graphics g = Graphics.FromImage(blank);
g.Clear(System.Drawing.Color.White);
System.Drawing.Image img = System.Drawing.Image.FromStream(stream);
g.DrawImage(img, 0, 0, Convert.ToInt32(b.Width), Convert.ToInt32(b.Height));
Bitmap tempImage = new Bitmap(blank);
blank.Dispose();
img.Dispose();
bmp = new Bitmap(tempImage);
tempImage.Dispose();
System.Windows.Forms.Clipboard.SetImage(bmp);
stream.Dispose();
}
Just pick a random color to use it as background, let's say
var background = Color.FromArgb(1, 255, 1, 255);
Erase background to it:
g.Clear(background); // instead of System.Drawing.Color.White
Then make that color transparent:
Bitmap tempImage = new Bitmap(blank);
tempImage.MakeTransparent(background);
Note that also default transparent color works pretty well, no need to pick a magic color (check if you need to Clear() background, it may be - I didn't check - default bitmap background):
g.Clear(Color.Transparent);
// ...
tempImage.MakeTransparent();
EDIT Some older RTF control versions won't handle transparency and there is nothing (AFAIK) you can do for it. A half decent workaround (if you can't detect control class of paste target and read its background color) is to use Color.FromArgb(254, 255, 255, 255). White where transparency isn't supported and...completely transparent (because of MakeTransparent()) where it is.
The Windows clipboard, by default, does not support transparency, but you can put content on the clipboard in many types together to make sure most applications find some type in it that they can use. Generally, if, in addition to the normal nontransparent clipboard Bitmap format, you put the image on the clipboard in both PNG and DIB formats, most applications will be able to use at least one of them to get the image in a format they support as being transparent.
These formats are put on the clipboard in a specific way, though. They need to have their data (for png, that's not the loaded image object but the actual png file's bytes) put in a MemoryStream that is then put on the clipboard.
PNG put on the clipboard like that will be accepted by a multitude of applications, including Gimp and the newer MS Office. And of course, if you implement reading for it too, you can use it in your own application. The (rather dirty) DIB format should take care of most other applications, if they indeed support transparent image pasting at all.
I detailed how to do both the copying and the retrieving in this answer:
https://stackoverflow.com/a/46424800/395685
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.
I'm using SVG# (http://sharpvectors.codeplex.com/), to batch convert SVG files to other formats. The SVG images being converted are black line drawings with no background. I've little experience with WPF or the System.Windows.Media namespace, so please excuse me if this is a basic question.
I'm using a modified version of the ImageSvgConverter from SVG#, which accepts a System.Windows.Media.Drawing object, which is then converted using a System.Windows.Media encoder (BmpBitmapEncoder, PngBitmapEncoder etc) to export to the desired file format.
When I export using either a TiffBitmapEncoderor, PngBitmapEncoder or GifBitmap the images are generated as expected. The generated images all have transparent backgrounds.
However, when I export using the JpegBitmapEncoder or BmpBitmapEncoder, all images are coming out black. As the tif, png and gif all have transparent backgrounds, I think that the jpg / bmp images are being drawn correctly, however, as alpha isn't supported in these file formats, having a black output makes sense as the transparency would be interpreted as nothing / black.
I think this is as described in these SO posts Strange bmp black output from BitmapSource - any ideas? , Convert Transparent PNG to JPG with Non-Black Background Color and Background Turns Black When Saving Bitmap - C#.
However, I cannot see a way of applying the solutions is these posts to my problem. Can anyone point me in the right direction?
I have tried applying a white SolidColorBrush to the DrawingContext's PushOpacityMask method, however, this makes no difference.
Really appreciate any pointers.
private Stream SaveImageFile(Drawing drawing)
{
// black output
BitmapEncoder bitmapEncoder = new BmpBitmapEncoder();
// works
//bitmapEncoder = new PngBitmapEncoder();
// The image parameters...
Rect drawingBounds = drawing.Bounds;
int pixelWidth = (int)drawingBounds.Width;
int pixelHeight = (int)drawingBounds.Height;
double dpiX = 96;
double dpiY = 96;
// The Visual to use as the source of the RenderTargetBitmap.
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
// makes to difference - still black
//drawingContext.PushOpacityMask(new SolidColorBrush(System.Windows.Media.Color.FromRgb(255,255,255)));
drawingContext.DrawDrawing(drawing);
drawingContext.Close();
// The BitmapSource that is rendered with a Visual.
RenderTargetBitmap targetBitmap = new RenderTargetBitmap(pixelWidth, pixelHeight, dpiX, dpiY, PixelFormats.Pbgra32);
targetBitmap.Render(drawingVisual);
// Encoding the RenderBitmapTarget as an image file.
bitmapEncoder.Frames.Add(BitmapFrame.Create(targetBitmap));
MemoryStream stream = new MemoryStream();
bitmapEncoder.Save(stream);
stream.Position = 0;
return stream;
}
You could draw a filled "background" rectangle with an appropriate size prior to the actual drawing object.
using (var drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawRectangle(Brushes.White, null, new Rect(drawingBounds.Size));
drawingContext.DrawDrawing(drawing);
}
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.
I am looking for a solution\software that I can use in order to render buttons in real time.
That is, I have an image and text, and I want them to be an image altogether in realtime.
Thank you
You can dynamically create an image based on text using the System.Drawing namespace.
private Bitmap CreateBitmapImage(string imageText, string imageUrl)
{
Bitmap myBitmap = new Bitmap(imageUrl);
Graphics g = Graphics.FromImage(myBitmap);
g.DrawString(imageText, new Font("Tahoma", 40), Brushes.White, new PointF(0, 0));
return (objBmpImage);
}
Once you have the Bitmap object in memory you can save it to the disk and call it's location from the web.
Bitmap bmp = CreateBitmapImage("my picture", #"C:\myBasePic.bmp");
bmp.Save(#"C:\bla.png", System.Drawing.Imaging.ImageFormat.png);
It would be good if you can specify why such requirement is there. One of such scenario that I had encountered was need of image buttons with different text (round corners with shaded background) - this can easily be achieved using CSS. If you really want to combine an image and text together then you can do that at server side (using say System.Drawing types) and serve the combined image over a handler/web-service.