saving WPF InkCanvas to a JPG - image is getting cropped
Asked Answered
M

7

5

I have a WPF InkCanvas control I'm using to capture a signature in my application. The control looks like this - it's 700x300

alt text

However, when I save it as a JPG, the resulting image looks like this, also 700x300

alt text

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.

Monolithic answered 5/8, 2009 at 16:52 Comment(1)
I made a small sample for this and used your exact code to save a .jpg. I made a variety of images and not once could I reproduce this problem! It must be somewhere else- can you post your XAML and anything else that could be relevant?Crissum
C
4

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.

Crissum answered 5/8, 2009 at 19:40 Comment(3)
thanks! - that seemed to do the trick. Wish I understood why too. I guess I'll remove the TextBlock for now and try it again later when I have more time to delve into this.Monolithic
It's doing this because you're using a StackPanel. The various layout panels do some sneaky stuff to your controls... in your case you're most likely seeing an offset transform being applied to your InkCanvas. I think you can get around it by putting your InkCanvas in a Border. See this link for more info: blogs.msdn.com/jaimer/archive/2009/07/03/…Entourage
Adding a border around the InkCanvas does help. Just make sure your border and canvas have equal dimensions.Rocambole
L
6

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;
    } 
Liberec answered 2/1, 2011 at 1:2 Comment(0)
C
4

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.

Crissum answered 5/8, 2009 at 19:40 Comment(3)
thanks! - that seemed to do the trick. Wish I understood why too. I guess I'll remove the TextBlock for now and try it again later when I have more time to delve into this.Monolithic
It's doing this because you're using a StackPanel. The various layout panels do some sneaky stuff to your controls... in your case you're most likely seeing an offset transform being applied to your InkCanvas. I think you can get around it by putting your InkCanvas in a Border. See this link for more info: blogs.msdn.com/jaimer/archive/2009/07/03/…Entourage
Adding a border around the InkCanvas does help. Just make sure your border and canvas have equal dimensions.Rocambole
B
3

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);
    }
Bulgar answered 31/12, 2009 at 8:51 Comment(0)
B
1

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

Bulgar answered 31/12, 2009 at 8:17 Comment(0)
B
1

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

Bulgar answered 31/12, 2009 at 8:21 Comment(0)
T
0
  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); 
Tortoni answered 14/10, 2014 at 6:16 Comment(1)
From above code the inkCanvas border problem may removed. Try this.Tortoni
G
0

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>
Glossa answered 2/6, 2015 at 9:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.