Can I create Icons on the fly in WPF? - c#

Since I am not getting anywhere with my previous question, I would like to know, are there any ways I can create icons on the fly on WPF?

You don't need WPF.
Usign GDI+ (System.Drawing.dll), you can create a 16x16 Bitmap, then call Icon.FromHandle(bitmap.GetHicon()).

You can use WritableBitmap for this.

You can use Taskbar icon progress bar...Sure U have seen, most of the application if doing any scanning or progress things, it displays progress actions on Icon.
Do this in your main form where u included the Icon
<Window x:Class="CCTrayHelper.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Icon="/CCTrayHelper;component/Images/CCTrayHelperIcon.png">
<Window.TaskbarItemInfo>
<TaskbarItemInfo />
</Window.TaskbarItemInfo>
Trig it from code behind
private void OnProgress(object sender, EventArgs args)
{
Dispatcher.Invoke(DispatcherPriority.Send, (Action)delegate() { TaskbarItemInfo.ProgressState = TaskbarItemProgressState.None; });
// Use here your progress type
}

This is what I ended up doing, I don't fully understand the details, if you find anything that can be improved, please do comment. Thanks for all the answers and comments.
public static ImageSource GetIconWithText(int digit)
{
BitmapImage myBitmapImage = new BitmapImage(new Uri(#"Images\PomoDomo.ico",
UriKind.RelativeOrAbsolute));
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
// Draw image
drawingContext.DrawImage(myBitmapImage, new Rect(0, 0, myBitmapImage.Width,
myBitmapImage.Height));
var typeFace = new Typeface(new FontFamily("Verdana"), FontStyles.Normal,
FontWeights.ExtraBold, FontStretches.UltraCondensed);
var formatedText = new FormattedText(digit.ToString(),
CultureInfo.InvariantCulture,
FlowDirection.LeftToRight,
typeFace,
40,
System.Windows.Media.Brushes.White);
//Center the text on Image
int pointY = (int)(myBitmapImage.Height - formatedText.Height) / 2;
int pointX = (int)(myBitmapImage.Width - formatedText.Width) / 2;
drawingContext.DrawText(formatedText, new Point(pointX, pointY));
}
RenderTargetBitmap finalBitmap = new RenderTargetBitmap((int)myBitmapImage.Width,
(int)myBitmapImage.Height, myBitmapImage.DpiX, myBitmapImage.DpiY,
PixelFormats.Pbgra32);
finalBitmap.Render(drawingVisual);
return finalBitmap;
}
private static void SaveImage(RenderTargetBitmap returnBitmap, string pngFileName)
{
string fileName = string.Format("{0}.png", pngFileName)
PngBitmapEncoder image = new PngBitmapEncoder();
image.Frames.Add(BitmapFrame.Create(returnBitmap));
using (Stream fs = File.Create(fileName))
{
image.Save(fs);
}
}

You can find a method here and here to render text on writeablebitmap

Related

How to save bmp (image) to file

I want to Video File thumbnail. Get Video path and convert to Image. Then convert to bmp, and save the bmp as an image file. If this is possible, please show me a way.
private void add_Video_Image(string sFullname_Path_of_Video)
{
//*create mediaplayer in memory and jump to position
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.MediaOpened += new EventHandler(mediaplayer_OpenMedia);
mediaPlayer.ScrubbingEnabled = true;
mediaPlayer.Open(new Uri(sFullname_Path_of_Video));
mediaPlayer.Position = TimeSpan.FromSeconds(0);
}
private void mediaplayer_OpenMedia(object sender, EventArgs e)
{
MediaPlayer mediaPlayer = sender as MediaPlayer;
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
drawingContext.DrawVideo(mediaPlayer, new Rect(0, 0, 160, 100));
drawingContext.Close();
double dpiX = 1 / 200;
double dpiY = 1 / 200;
RenderTargetBitmap bmp = new RenderTargetBitmap(160, 100, dpiX, dpiY, PixelFormats.Pbgra32);
bmp.Render(drawingVisual);
Image newImage = new Image();
newImage.Source = bmp;
newImage.Stretch = Stretch.Uniform;
newImage.Height = 100;
//save bmp to image
}
Please check this link. It holds the answer to your question: Easiest way of saving wpf Image control to a file
You can do the save prior to setting the 'RenderTargetBitmap' to the 'Image Control'.

Transparency issue: Some softwares can't see properly my WPF "printscreen" in .jpg

I would like some help with my images. I just want to save my screen and gladly I could. But some softwares can't properly see them. For example:
If I put my image (.jpg) in facebook, or open it with Paint, it will be like this:
but if I open the same image (the exactly same image) with the default Windows Program or some, it will appear like this:
So, I was doing this "printscreen" in my WPF application, here is my code:
private void btSalvar_Click_1(object sender, RoutedEventArgs e)
{
BitmapSource bmp = VisualToBitmap.Render(gridSalvar);
Microsoft.Win32.SaveFileDialog dialog = new Microsoft.Win32.SaveFileDialog();
dialog.Filter = "Imagem JPG(*.jpg)|*.jpg";
if (dialog.ShowDialog() == true)
{
System.Windows.Media.Imaging.PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bmp));
System.IO.FileStream fs = new System.IO.FileStream(dialog.FileName, System.IO.FileMode.Create);
encoder.Save(fs);
fs.Close();
}
And the class created to do so:
class VisualToBitmap
{
public static System.Windows.Media.Imaging.BitmapSource Render(System.Windows.Media.Visual Visual, int Resolution = 96)
{
System.Windows.Media.Imaging.RenderTargetBitmap render;
double width, height;
int pixelWidth, pixelHeight;
width = (double)Visual.GetValue(System.Windows.FrameworkElement.ActualWidthProperty);
height = (double)Visual.GetValue(System.Windows.FrameworkElement.ActualHeightProperty);
pixelWidth = Convert.ToInt32((width / 96) * Resolution);
pixelHeight = Convert.ToInt32((height / 96) * Resolution);
render = new System.Windows.Media.Imaging.RenderTargetBitmap(
pixelWidth, pixelHeight, Resolution, Resolution,
System.Windows.Media.PixelFormats.Pbgra32);
render.Render(Visual);
return render;
}
}
can someone please help me fix this?
Thanks guys!
Alright, so like Peter Duniho suggested, It was a rookie mistake. Just adding a background into an grid made the trick.

win2D uwp won't save a highlight stroke in an inkcanvas

I'm desperately trying to save a highlight stroke as a png. I'm using win2d for UWP to make this work.
It works well for strokes with 100% opacity, but when I set DrawAsHighlighter = true;, the saved png is empty, fully transparent.
Here's my code :
private void SetHighLight()
{
InkDrawingAttributes attributes = new InkDrawingAttributes();
attributes.DrawAsHighlighter = true;
attributes.PenTip = PenTipShape.Rectangle;
attributes.Size = new Size(4, 10);
attributes.Color = currentColor;
SetAttribute(attributes);
}
private void GetCanvasRender(out CanvasRenderTarget renderTarget)
{
CanvasDevice device = CanvasDevice.GetSharedDevice();
renderTarget = new CanvasRenderTarget(device, (int)ink.ActualWidth, (int)ink.ActualHeight, 96);
using (var ds = renderTarget.CreateDrawingSession())
{
ds.Clear(Colors.Transparent); //I already tried to delete this but it doesn't change anything
ds.DrawInk(ink.InkPresenter.StrokeContainer.GetStrokes());
}
}
private async void SavePicture()
{
CanvasRenderTarget renderTarget;
Image img = new Image();
GetCanvasRender(out renderTarget);
StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
StorageFile noteFile = await storageFolder.CreateFileAsync(i.ToString() + ".png", CreationCollisionOption.ReplaceExisting);
using (var fileStream = await noteFile.OpenAsync(FileAccessMode.ReadWrite))
await renderTarget.SaveAsync(fileStream, CanvasBitmapFileFormat.Png, 1f);
img.Source = new BitmapImage(new Uri(storageFolder.Path + "/" + i++ + ".png"));
img.VerticalAlignment = VerticalAlignment.Stretch;
ContainerCanvas.Children.Add(img);
Canvas.SetTop(img, ScrollViewerContainer.VerticalOffset);
Canvas.SetZIndex(img, 5);
}
I've read it might be because of the highlight not being present in the visual tree but I'm really not sure about it.
By the way when I try to change the opacity of a color(attributes.Color = Color.FromArgb(128, 255, 0, 0)), the inkcanvas doesn't apply the alpha, why ? Am I missing something ?
You can't save DrawAsHighlighter ink to a bitmap format like .png - that's just fundamentally not a meaningful operation to be attempting.
Regular non-highlighter ink is drawn using standard alpha blending, so it is reasonable to write just these ink shapes into a bitmap format. You can later blend that bitmap over some other background image, and get the same result as if the ink had been drawn directly over that background.
For highlighter ink, however, the "blend over background" is a more complex operation, not just standard sourceover blending. So there is no such thing as a bitmap image that contains just this ink - you also have to provide a background in order for the appropriate blend to be carried out.
You have three options here:
Don't use highligher ink mode.
Instead of saving out your ink as a bitmap image, save the original ink stroke data, and use inking APIs to later blend these strokes directly to their final location.
Include the background as well as the ink strokes in the same bitmap.
Try clearing the background of the canvas with:
ds.Clear(Colors.White);
The highlighter isn't visible on transparent backgrounds as it seems to multiply its value with the background color.
I finally figured out how to make it work.
I simply added a new layer before calling DrawInk and gave it an opacity, and got rid of the attributes.DrawAsHighlighter = true;. Instead, I've made 1 inkCanvas with 0.5 opacity specially for the highlighter, looking like you're using a highlighter.
Here's the code :
private void SetHighLight()
{
InkDrawingAttributes attributes = new InkDrawingAttributes();
attributes.PenTip = PenTipShape.Rectangle;
attributes.Size = new Size(4, 10);
attributes.Color = currentColor;
SetAttribute(attributes);
}
private void GetCanvasRender(out CanvasRenderTarget renderTarget, float opacity)
{
CanvasDevice device = CanvasDevice.GetSharedDevice();
renderTarget = new CanvasRenderTarget(device, (int)ink.ActualWidth, (int)ink.ActualHeight, 96);
using (var ds = renderTarget.CreateDrawingSession())
{
ds.Clear(Colors.Transparent);
using (ds.CreateLayer(opacity))
{
ds.DrawInk(ink.InkPresenter.StrokeContainer.GetStrokes());
}
}
}
private async void SavePicture(float opacity)
{
CanvasRenderTarget renderTarget;
Image img = new Image();
GetCanvasRender(out renderTarget, opacity);
StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
StorageFile noteFile = await storageFolder.CreateFileAsync(i.ToString() + ".png", CreationCollisionOption.ReplaceExisting);
using (var fileStream = await noteFile.OpenAsync(FileAccessMode.ReadWrite))
await renderTarget.SaveAsync(fileStream, CanvasBitmapFileFormat.Png, 1f);
img.Source = new BitmapImage(new Uri(storageFolder.Path + "/" + i++ + ".png"));
img.VerticalAlignment = VerticalAlignment.Stretch;
ContainerCanvas.Children.Add(img);
Canvas.SetTop(img, ScrollViewerContainer.VerticalOffset);
Canvas.SetZIndex(img, 5);
}

Server-side rendering of WPF UserControl

I am writing a server side console app in C#/.Net 4.5 that gets some data and creates static chart images that are saved to be displayed by a web server.
I am mostly using the method described here:
http://lordzoltan.blogspot.com/2010/09/using-wpf-to-render-bitmaps.html
However, I added a mainContainer.UpdateLayout(); after the Arrange() so that the databindings would update and be visible in the rendered image, as well as a Measure() before it for good... ah, I'm not gonna go there.
Here is the method that does the rendering:
void RenderAndSave(UIElement target, string filename, int width, int height)
{
var mainContainer = new Grid
{
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch
};
mainContainer.Children.Add(target);
mainContainer.Measure(new Size(width, height));
mainContainer.Arrange(new Rect(0, 0, width, height));
mainContainer.UpdateLayout();
var encoder = new PngBitmapEncoder();
var render = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
render.Render(mainContainer);
encoder.Frames.Add(BitmapFrame.Create(render));
using (var s = File.Open(filename, FileMode.Create))
{
encoder.Save(s);
}
}
The target parameter to the method will be an instance of a WPF/XAML UserControl I made - fairly simple at this point, just a grid with some text databinding to a ViewModel object that I assigned to the DataContext.
The saved image on disk looks good EXCEPT for the OxyPlot Plot object - it is entirely white.
Now, when I am in the designer in Visual Studio 2013, I can see it. I have added a design-time DataContext which is the same object that I use at runtime (this is a spike I am doing - the viewmodel is not in its final form yet, just having a bunch of default data while I work out the kinks). In the designer I see the chart as OxyPlot paints it.
Is there anything special I need to do in order to get my rendering to also contain this OxyPlot chart? It is more or less the point of the exercise so it would be awesome to actually get it to show up!
Thanks in advance for any insights and suggestions!
If you're correctly binding data at runtime as well, then it should work.
[STAThread]
static void Main(string[] args)
{
string filename = "wpfimg.png";
RenderAndSave(new UserControl1(), filename, 300, 300);
PictureBox pb = new PictureBox();
pb.Width = 350;
pb.Height = 350;
pb.Image = System.Drawing.Image.FromFile(filename);
Form f = new Form();
f.Width = 375;
f.Height = 375;
f.Controls.Add(pb);
f.ShowDialog();
}
XAML:
<UserControl x:Class="WpfApp92.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:oxy="http://oxyplot.org/wpf"
xmlns:local="clr-namespace:WpfApp92"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<oxy:PlotView Model="{Binding Model}"/>
</Grid>
</UserControl>
CS:
public partial class UserControl1 : UserControl
{
public PlotModel Model { get; set; }
public UserControl1()
{
InitializeComponent();
Model = new PlotModel();
Model.LegendBorderThickness = 0;
Model.LegendOrientation = LegendOrientation.Horizontal;
Model.LegendPlacement = LegendPlacement.Outside;
Model.LegendPosition = LegendPosition.BottomCenter;
Model.Title = "Simple model";
var categoryAxis1 = new CategoryAxis();
categoryAxis1.MinorStep = 1;
categoryAxis1.ActualLabels.Add("Category A");
categoryAxis1.ActualLabels.Add("Category B");
categoryAxis1.ActualLabels.Add("Category C");
categoryAxis1.ActualLabels.Add("Category D");
Model.Axes.Add(categoryAxis1);
var linearAxis1 = new LinearAxis();
linearAxis1.AbsoluteMinimum = 0;
linearAxis1.MaximumPadding = 0.06;
linearAxis1.MinimumPadding = 0;
Model.Axes.Add(linearAxis1);
var columnSeries1 = new ColumnSeries();
columnSeries1.StrokeThickness = 1;
columnSeries1.Title = "Series 1";
columnSeries1.Items.Add(new ColumnItem(25, -1));
columnSeries1.Items.Add(new ColumnItem(137, -1));
columnSeries1.Items.Add(new ColumnItem(18, -1));
columnSeries1.Items.Add(new ColumnItem(40, -1));
Model.Series.Add(columnSeries1);
var columnSeries2 = new ColumnSeries();
columnSeries2.StrokeThickness = 1;
columnSeries2.Title = "Series 2";
columnSeries2.Items.Add(new ColumnItem(12, -1));
columnSeries2.Items.Add(new ColumnItem(14, -1));
columnSeries2.Items.Add(new ColumnItem(120, -1));
columnSeries2.Items.Add(new ColumnItem(26, -1));
Model.Series.Add(columnSeries2);
DataContext = this;
}
}
I don't know anything about this OxyPlat, but I do know that most charts are often rendered using hardware APIs. Hardware acceleration is usually error-prone when working outside the expected environment (i.e. a client showing a visible Desktop window).
On application initialization, try disabling hardware acceleration:
RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
Another possible tweak is to call DoEvents() before you render your bitmap. Possibly with priority set to SystemIdle. This will make sure your DataContext has been successfully bound.
public static void DoEvents(
DispatcherPriority priority = DispatcherPriority.Background)
{
Dispatcher.CurrentDispatcher.Invoke(new Action(delegate { }), priority);
}

How do I print an Image from a Uri?

I am attempting to print a JPEG file that I reference using a Uri object and am having some difficulties. I found that while the image was printing, it was cropped slightly and was flipped and mirrored. I'm guessing that the crop was caused by a size not being set properly but have no idea why it's being flipped and rotated. Assuming that this was a natural oddity, I attempted to resolve the issue by applying a transform to the drawingContext object but this results a blank page being printed. Here is my code:
public void Print(List<Uri> ListToBePrinted)
{
XpsDocumentWriter writer =
PrintQueue.CreateXpsDocumentWriter(this.SelectedPrinter.PrintQueue);
PrintCapabilities printerCapabilities =
this.SelectedPrinter.PrintQueue.GetPrintCapabilities();
Size PageSize =
new Size(printerCapabilities.PageImageableArea.ExtentWidth,
printerCapabilities.PageImageableArea.ExtentHeight);
foreach (Uri aUri in ListToBePrinted)
{
BitmapImage anImage = new BitmapImage(aUri);
//create new visual which would be initialized by image
DrawingVisual drawingVisual = new DrawingVisual();
//create a drawing context so that image can be rendered to print
DrawingContext drawingContext = drawingVisual.RenderOpen();
// Flips along X and Y axis (flips and mirrors)
drawingContext.PushTransform(new ScaleTransform(-1, -1));
drawingContext.DrawImage(anImage, new Rect(PageSize));
drawingContext.Close();
writer.Write(drawingVisual);
}
}
Any help would be greatly appreciated - thank you!
Here's what I ended up with:
public void Print(List<Uri> ListToBePrinted)
{
XpsDocumentWriter writer =
PrintQueue.CreateXpsDocumentWriter(this.SelectedPrinter.PrintQueue);
PrintCapabilities printerCapabilities =
this.SelectedPrinter.PrintQueue.GetPrintCapabilities();
Size PrintableImageSize =
new Size(printerCapabilities.PageImageableArea.ExtentWidth,
printerCapabilities.PageImageableArea.ExtentHeight);
foreach (Uri aUri in ListToBePrinted)
{
DrawingVisual drawVisual = new DrawingVisual();
ImageBrush imageBrush = new ImageBrush();
imageBrush.ImageSource = new BitmapImage(aUri);
imageBrush.Stretch = Stretch.Fill;
imageBrush.TileMode = TileMode.None;
imageBrush.AlignmentX = AlignmentX.Center;
imageBrush.AlignmentY = AlignmentY.Center;
using (DrawingContext drawingContext = drawVisual.RenderOpen())
{
// Flips along X and Y axis (flips and mirrors)
drawingContext.PushTransform(new ScaleTransform(-1, 1, PrintableImageSize.Width / 2, PrintableImageSize.Height / 2));
drawingContext.PushTransform(new RotateTransform(180, PrintableImageSize.Width / 2, PrintableImageSize.Height / 2)); // Rotates 180 degree
drawingContext.DrawRectangle(imageBrush, null, new Rect(25, -25, PrintableImageSize.Width, PrintableImageSize.Height));
}
writer.Write(drawVisual);
}
}
The image is a little fuzzy but is certainly acceptable. I'm still not sure why my image needed to be flipped or mirrored.
Could you do something like:
BitmapImage anImage = new BitmapImage(aUri);
Image image = new Image();
image.BeginInit();
image.Source = anImage;
image.EndInit();
image.Measure(PageSize);
image.InvalidateVisual();
Then just print the Image object since it derives from Visual...
You need to call InvalidateVisual so that OnRender will be called, if you didn't it would result in a blank image...

Categories

Resources