saving WPF InkCanvas to a JPG - image is getting cropped - wpf

I have a WPF InkCanvas control I'm using to capture a signature in my application. The control looks like this - it's 700x300
However, when I save it as a JPG, the resulting image looks like this, also 700x300
The code I'm using to save
sigPath = System.IO.Path.GetTempFileName();
MemoryStream ms = new MemoryStream();
FileStream fs = new FileStream(sigPath, FileMode.Create);
RenderTargetBitmap rtb = new RenderTargetBitmap((int)inkSig.Width, (int)inkSig.Height, 96d, 96d, PixelFormats.Default);
rtb.Render(inkSig);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
encoder.Save(fs);
fs.Close();
This is the XAML I'm using:
<Window x:Class="Consent.Client.SigPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Transparent" Topmost="True" AllowsTransparency="True"
Title="SigPanel" Left="0" Top="0" Height="1024" Width="768" WindowStyle ="None" ShowInTaskbar="False" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" >
<Border BorderThickness="1" BorderBrush="Black" Background='#FFFFFFFF' x:Name='DocumentRoot' Width='750' Height='400' CornerRadius='10'>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Name="txtLabel" FontSize="24" HorizontalAlignment="Center" >Label</TextBlock>
<InkCanvas Opacity="1" Background="Beige" Name="inkSig" Width="700" Height="300" />
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
<Button FontSize="24" Margin="10" Width="150" Name="btnSave" Click="btnSave_Click">Save</Button>
<Button FontSize="24" Margin="10" Width="150" Name="btnCancel" Click="btnCancel_Click">Cancel</Button>
<Button FontSize="24" Margin="10" Width="150" Name="btnClear" Click="btnClear_Click">Clear</Button>
</StackPanel>
</StackPanel>
</Border>
In the past this worked perfectly. I can't figure out what changed that is causing the image to shift when it is saved.

I had same problem i did this way.. It worked here..
private void Button_Click(object sender, RoutedEventArgs e)
{
double width = inkSig.ActualWidth;
double height = inkSig.ActualHeight;
RenderTargetBitmap bmpCopied = new RenderTargetBitmap((int)Math.Round(width), (int)Math.Round(height), 96, 96, PixelFormats.Default);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext dc = dv.RenderOpen())
{
VisualBrush vb = new VisualBrush(inkSig);
dc.DrawRectangle(vb, null, new Rect(new System.Windows.Point(), new System.Windows.Size(width, height)));
}
bmpCopied.Render(dv);
System.Drawing.Bitmap bitmap;
using (MemoryStream outStream = new MemoryStream())
{
// from System.Media.BitmapImage to System.Drawing.Bitmap
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bmpCopied));
enc.Save(outStream);
bitmap = new System.Drawing.Bitmap(outStream);
}
EncoderParameter qualityParam =
new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 85L);
// Jpeg image codec
ImageCodecInfo jpegCodec = getEncoderInfo("image/jpeg");
if (jpegCodec == null)
return;
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
Bitmap btm = new Bitmap(bitmap);
bitmap.Dispose();
btm.Save("C:\\Users\\Pd\\Desktop\\dfe12.jpg", jpegCodec, encoderParams);
btm.Dispose();
}
private ImageCodecInfo getEncoderInfo(string mimeType)
{
// Get image codecs for all image formats
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
// Find the correct image codec
for (int i = 0; i < codecs.Length; i++)
if (codecs[i].MimeType == mimeType)
return codecs[i];
return null;
}

Aha! The problem is the TextBlock txtLabel that is directly above the InkCanvas. When you remove that the black line disappears.
As for why that is happening, I'm not entirely sure yet.

My class save image
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
public void ExportToJpeg(String path, InkCanvas surface)
{
double
x1 = surface.Margin.Left,
x2 = surface.Margin.Top,
x3 = surface.Margin.Right,
x4 = surface.Margin.Bottom;
if (path == null) return;
surface.Margin = new Thickness(0, 0, 0, 0);
Size size = new Size(surface.Width, surface.Height);
surface.Measure(size);
surface.Arrange(new Rect(size));
RenderTargetBitmap renderBitmap =
new RenderTargetBitmap(
(int)size.Width,
(int)size.Height,
96,
96,
PixelFormats.Default);
renderBitmap.Render(surface);
using (FileStream fs = File.Open(path, FileMode.Create))
{
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
encoder.Save(fs);
}
surface.Margin = new Thickness(x1, x2, x3, x4);
}

and
surface.Margin = new Thickness(55,40,96,5);
http://img519.imageshack.us/img519/7499/mynewimage.png

Jason, I solved this problem.
Sorry my English. I am Russian.
You need set property inkCanvas.Margin at 0,0,0,0
with:
surface.Margin = new Thickness(0, 0, 0, 0);
after saving set margin at your position.
example:
http://img189.imageshack.us/img189/7499/mynewimage.png

var size = new Size(inkCanvas.ActualWidth, inkCanvas.ActualHeight);
inkCanvas.Margin = new Thickness(0, 0, 0, 0);
inkCanvas.Measure(size);
inkCanvas.Arrange(new Rect(size));
var encoder = new PngBitmapEncoder();
var bitmapTarget = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96, 96, PixelFormats.Default);
bitmapTarget.Render(inkCanvas);
encoder.Frames.Add(BitmapFrame.Create(bitmapTarget));
encoder.Save(ms);

I've been looking all over the net for an answer to this problem and tried most opinions without any joy. Then I tried this and it worked!
<Canvas x:Name="editCanvas" Background="Transparent" ClipToBounds="True">
<InkCanvas EditingMode="Select" x:Name="inkCanvas" Background="Transparent" Height="562" Width="866">
</InkCanvas>
</Canvas>

Related

WPF Screen Capture doesn't include title bar

I implemented the code in the first answer to this question and it works great except that it doesn't include the title bar, which is a must for my needs. Does anybody have any idea what I'm doing wrong?
I've updated my example to show all the other commented out attempts that failed.
Here's my code:
Window shellView = Application.Current.MainWindow;
Rect bounds = VisualTreeHelper.GetDescendantBounds(shellView);
//Rect bounds = new Rect(new Size(shellView.ActualWidth, shellView.ActualHeight));
//Rect bounds = shellView.RestoreBounds;
//Rect bounds = VisualTreeHelper.GetContentBounds(shellView);
//Rect bounds = new Rect(new Size(VisualTreeHelperEx.FindDescendantByType<Window>(shellView).ActualWidth,
// VisualTreeHelperEx.FindDescendantByType<Window>(shellView).ActualHeight));
RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)bounds.Width, (int)bounds.Height, 96, 96, PixelFormats.Pbgra32);
DrawingVisual visual = new DrawingVisual();
string fileName = $#"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\Screen_Capture.png";
if (_dialogService.ShowSaveFileDialog(ref fileName, "PNG Files | *.png"))
{
using (DrawingContext context = visual.RenderOpen())
{
VisualBrush visualBrush = new VisualBrush(shellView);
context.DrawRectangle(visualBrush, null, new Rect(new Point(), bounds.Size));
}
renderTarget.Render(visual);
PngBitmapEncoder bitmapEncoder = new PngBitmapEncoder();
bitmapEncoder.Frames.Add(BitmapFrame.Create(renderTarget));
using (Stream stm = File.Create(fileName))
{
bitmapEncoder.Save(stm);
}
}
And at XAMIMAX's request, what I can share of the XAML with names changed:
<Window x:Class="MyProject.Shell.Views.Shell.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ap="clr-namespace:MyProject.Common.Support.AttachedProperties;assembly=MyProject.Common.Support"
xmlns:controls="clr-namespace:MyProject.Common.Support.Controls;assembly=MyProject.Common.Support"
xmlns:converters="clr-namespace:MyProject.Common.Support.Converters;assembly=MyProject.Common.Support"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:dts="clr-namespace:MyProject.Common.Support.DataTemplateSelectors;assembly=MyProject.Common.Support"
xmlns:enums="clr-namespace:MyProject.Shell.Enums"
xmlns:enums1="clr-namespace:MyProject.Common.Support.Enums;assembly=MyProject.Common.Support"
xmlns:ikriv="clr-namespace:MyProject.Common.Support.AttachedProperties;assembly=MyProject.Common.Support"
xmlns:intr="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:m="clr-namespace:MyProject.Common.Support.MarkupExtensions;assembly=MyProject.Common.Support"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:resources="clr-namespace:MyProject.Shell.Views.Shell.Resources"
xmlns:ss="clr-namespace:MyProject.Common.Support.StyleSelectors;assembly=MyProject.Common.Support"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:views="clr-namespace:MyProject.NotificationModule.Client.Views;assembly=MyProject.NotificationModule.Client"
xmlns:constants="clr-namespace:MyProject.Shell"
x:Name="shell"
Title="{Binding MyProjectApplicationTitle}"
Width="1024"
Height="768"
MinWidth="800"
MinHeight="600"
Background="{DynamicResource PrimarySolidColorBrush}"
Icon="/Resources/Embedded/MyProject.ico"
mc:Ignorable="d">
<controls:LocalizationScope.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.Children>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding NavigationBarWidth, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
MinWidth="38"
MaxWidth="400" />
</Grid>
</Grid.Children>
</Grid>
</controls:LocalizationScope.Content>
</Window>
I hope that's enough of the XAML to help. I also tried the example at this link Generating a screenshot of a WPF window, but got the same results: no title bar.
Thanks to the link that #Clemens sent me to, I was able to use some of the code on that page to come up with this working method. It grabs a few pixels more that the active window, but that works for me!
private void TakeScreenshot()
{
var rect = new Rect();
GetWindowRect(GetForegroundWindow(), ref rect);
var bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
var result = new Bitmap(bounds.Width, bounds.Height);
using (var graphics = Graphics.FromImage(result))
{
graphics.CopyFromScreen(new System.Drawing.Point(bounds.Left, bounds.Top), System.Drawing.Point.Empty, bounds.Size);
}
string fileName = $#"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\Screen_Capture.png";
if (_dialogService.ShowSaveFileDialog(ref fileName, "PNG Files | *.png"))
{
result.Save(fileName, ImageFormat.Png);
_dialogService.ShowInfoDialog(_localizationService["Shell.Views.Shell.HelpMenu.ScreenshotSaved"] + $"{fileName}");
}
}

Extract image from wpf image control and save it to a png file on my local PCc#

i have a image control in wpf c#.
<Image x:Name="icon01" MouseDown="icon_MouseDown" Cursor="Hand" Source="FavIcon\01.png" Height="48" Width="48" Margin="10"/>
How can I save the image (FavIcon\01.png) to file on my PC? i use c# .net 4.0.
use the icon01.Source(ImageSource) to create a FileStream via the PngBitmapEncoder, here an example using a SaveFileDialog
private void icon_MouseDown(object sender, MouseButtonEventArgs e)
{
try
{
var saveFileDialog = new SaveFileDialog()
{
Filter = "Image Files (*.bmp, *.png, *.jpg)|*.bmp;*.png;*.jpg"
};
if (saveFileDialog.ShowDialog() == true)
{
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create((BitmapSource)icon01.Source));
using (FileStream stream = new FileStream(saveFileDialog.FileName, FileMode.Create))
encoder.Save(stream);
}
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
}
}
and the Xaml is the Same :
<Grid>
<Image x:Name="icon01" MouseDown="icon_MouseDown" Cursor="Hand" Source="FavIcon\01.png" Height="48" Width="48" Margin="10"/>
</Grid>

Is it possible to change caret width for TextBox in silverlight when overwrite mode?

I have the TextBox in silverlight 4 in 2 modes: insert and overwrite.
Can anyone help me? If I press the overwrite mode, I want to make the caret blinking size bigger.
I have used to CaretBrush, but it can change the color of caret only.
Many thanks if you have suggestion or the sample code.
At the time looking someone can help, I tried this solution for myself, It's abit complex, but I hope someone can use my code and customize yourself. Someone can get this code for trying if you have this case
The MainPage.xaml code:
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.micros`enter code here`oft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid Name="LayoutRoot">
<Canvas x:Name="canvasDataView" VerticalAlignment="Top" Background="White" HorizontalAlignment="Left">
<TextBox HorizontalAlignment="Left" Canvas.Left="50" VerticalAlignment="Top" x:Name="positionTextBox" Canvas.ZIndex="2" Text="position" Canvas.Top="25" Visibility="Collapsed" Width="100" Height="25"></TextBox>
<TextBox x:Name="textBox1" Text="asdfasdfasd asda asdf as adfasdfads adf asdf adfasdf" SelectionForeground="AliceBlue" KeyDown="textBox1_KeyDown" KeyUp="textBox1_KeyUp" TextWrapping="NoWrap" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Visible" AcceptsReturn="True" Height="25" Width="500" />
<TextBox x:Name="shadowTextBox" Canvas.ZIndex="-1" Canvas.Left="350" Height="20" Width="20" HorizontalScrollBarVisibility="Visible" AcceptsReturn="True" VerticalScrollBarVisibility="Visible" Visibility="Visible" TextWrapping="NoWrap"/>
</Canvas>
</Grid>
</UserControl>
The code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Expression.Interactivity;
using System.Windows.Controls.Primitives;
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
Duration duration = new Duration(TimeSpan.FromSeconds(0.5));
Storyboard storybroad = new Storyboard();
Rectangle myRectangle = null;
ScrollViewer sv;
public MainPage()
{
InitializeComponent();
textBox1.KeyUp += new KeyEventHandler(textBox1_KeyUp);
textBox1.TextChanged += new TextChangedEventHandler(textBox1_TextChanged);
textBox1.CaretBrush = new SolidColorBrush(Colors.Transparent);
}
void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
shadowTextBox.Text = textBox1.Text;
shadowTextBox.SelectionStart = textBox1.SelectionStart;
Point p = getCaretPosition(textBox1, shadowTextBox);
MoveCaret(p);
}
void textBox1_KeyDown(object sender, KeyEventArgs e)
{
shadowTextBox.Text = textBox1.Text;
shadowTextBox.SelectionStart = textBox1.SelectionStart;
}
void textBox1_KeyUp(object sender, KeyEventArgs e)
{
shadowTextBox.Text = textBox1.Text;
shadowTextBox.SelectionStart = textBox1.SelectionStart;
// get caret position
Point p = getCaretPosition(textBox1,shadowTextBox);
MoveCaret(p);
}
private Point getCaretPosition(TextBox textBox, TextBox shadowTextBox)
{
Point _point = new Point();
// get main textbox's scroll offset, if any
getScrollBar(textBox);
double initVerticalOffset = sv.VerticalOffset;
double initHorizontalOffset = sv.HorizontalOffset;
// get shadow box scroll offset
getScrollBar(shadowTextBox);
double vOffset = sv.VerticalOffset;
double hOffset = sv.HorizontalOffset;
// caret position is scroll offset of shadaw minus scroll offset of main (if any)
_point.Y = vOffset - initVerticalOffset;
_point.X = hOffset - initHorizontalOffset;
return _point;
}
private void getScrollBar(UIElement src)
{
// walk visual tree for this object until we get the scrollviewer
if (src.GetType().ToString() == "System.Windows.Controls.ScrollViewer")
sv = src as ScrollViewer;
else
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(src); i++)
{
UIElement elem = (UIElement)VisualTreeHelper.GetChild(src, i);
getScrollBar(elem);
}
}
}
void MoveCaret(Point point)
{
if (storybroad == null)
storybroad = new Storyboard();
storybroad.Stop();
if (point != new Point(0, 0))
{
if (myRectangle != null && canvasDataView.Children.Contains(myRectangle))
{
canvasDataView.Children.Remove(myRectangle);
}
myRectangle = new Rectangle();
myRectangle.SetValue(Canvas.TopProperty, point.Y);
myRectangle.SetValue(Canvas.LeftProperty, point.X);
myRectangle.Width = 5;
myRectangle.Height = 16;
myRectangle.Fill = new SolidColorBrush();
storybroad.BeginTime = new TimeSpan(0, 0, 0, 0, 0);
storybroad.RepeatBehavior = RepeatBehavior.Forever;
ColorAnimation color = new ColorAnimation();
canvasDataView.Children.Add(myRectangle);
color.From = Colors.Transparent;
color.To = Colors.Green;
color.Duration = duration;
storybroad.Children.Add(color);
Storyboard.SetTarget(color, myRectangle);
Storyboard.SetTargetProperty(color, new PropertyPath("(Fill).(SolidColorBrush.Color)"));
storybroad.Begin();
}
}
}
}

Wpf dynamic design with Grid and data binding

I am creating dynamic UI using from code.I am adding grid to the Page using for loop,in multiple rows and 4 columns,so it takes time to load UI on Page.I want to load each child Grid lazily, I don't know how to do it, please help.
here is XAML file
<ScrollViewer Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" CanContentScroll="True" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Margin="0 0 0 0">
<Grid x:Name="mainGrid" HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="10" Width="Auto">
</Grid>
</ScrollViewer>
and this is pseudo code from .cs file
for (int column = 0; column < dsMacDtls.Tables[0].Rows.Count; column++)
{
grid = new Grid();
grid.Width = 108;
grid.Height = 108;
if (column % 4 == 0)
{
mainGrid.RowDefinitions.Add(new RowDefinition());
}
else
{
mainGrid.RowDefinitions.Add(new RowDefinition());
}
box = new CheckBox();
TextBlock tb = new TextBlock();
tb.Text = "abcd";
box.Content = tb;
grid.Children.Add(box);
ImageBrush myBrush = new ImageBrush();
image = new Image();
image.Source = new BitmapImage(new Uri("abcd.png"));
grid.Background = myBrush;
Grid.SetColumn(grid, 0);
Grid.SetRow(grid, i);
Border br = new Border();
br.BorderThickness = new Thickness(1);
br.BorderBrush = new SolidColorBrush(Colors.Gray);
Grid.SetColumn(br, 0);
Grid.SetRow(br, rowNumberofMachine);
br.Width = 108;
br.Height = 108;
grid.Children.Add(br);
mainGrid.Children.Add(grid);
}

How to set multiple canvas in scroll viewer in wpf?

I want to set an image in a canvas control and have 20 canvases that I am creating by using a loop. The problem is that when I want to add all those canvas items in to a scroll viewer it does not work. Here is my code:
private void CreateAndShowCanvas()
{
List<Canvas> list = new List<Canvas>();
for (int i = 0; i < 20; i++)
{
Canvas myCanvas1 = new Canvas();
myCanvas1.Background = new SolidColorBrush(Colors.Transparent);
myCanvas1.Height = 235;
myCanvas1.Width = 626;
//Canvas.SetZIndex(myCanvas1, 4);
Image MainImage = new Image();
MainImage.Width = 275;
MainImage.Height = 235;
BitmapImage mi = new BitmapImage(new Uri("select_1.png", UriKind.Relative));
MainImage.Source = mi;
Canvas.SetTop(MainImage, 0);
Canvas.SetLeft(MainImage, 0);
myCanvas1.Children.Add(MainImage);
Image SeparatorImage = new Image();
BitmapImage si = new BitmapImage(new Uri("Sentre Seprator.png", UriKind.Relative));
SeparatorImage.Height = 270;
SeparatorImage.Source = si;
Canvas.SetTop(SeparatorImage, -5);
Canvas.SetLeft(SeparatorImage, 310);
myCanvas1.Children.Add(SeparatorImage);
Image SecondImage = new Image();
SecondImage.Width = 275;
SecondImage.Height = 235;
BitmapImage sci = new BitmapImage(new Uri("select_2.png", UriKind.Relative));
SecondImage.Source = sci;
Canvas.SetTop(SecondImage, 0);
Canvas.SetLeft(SecondImage, 350);
myCanvas1.Children.Add(SecondImage);
list.Add(myCanvas1);
}
scv.Content = list;
}
and in XML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ScrollViewer Name="scv" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled" Margin="60,40,59,46" Opacity="99" Background="Transparent" />
</Grid>
</Window>
and when I run it, it only shows ("Collection"). Please help me out, thanks in advance...
Should you not just be using a ListBox with an ItemTemplate that has Canvases inside it instead? There must be an easier way to do whatever you are trying to achieve than creating 20 canvases manually.
Here's some reading to do with ListBoxes.
A ScrollViewer can hold just a single child, so you need another panel type like a Grid or StackPanel which holds your canvases.
<Grid>
<ScrollViewer Name="scv" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled" Margin="60,40,59,46" Opacity="99" Background="Transparent">
<StackPanel Name="stp" />
</ScrollViewer>
</Grid>
Add canvases to stp instead.

Resources