CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 5 of 5
  1. #1
    Join Date
    Aug 2008
    Posts
    902

    Image manipulation in WPF

    I want do do some image editing, bluring, levels adjustment and other random effects, and normally this is really slow in C#. I've done it before with GetPixel / SetPixel using System.Drawing.Bitmap, which is easy to implement, but gruesomely slow. Next I tried converting the Bitmap into a byte[] and then manipulating the image as an array, which is much faster than the previous methods.

    I stumbled upon this a while back and messed around with it.

    http://blogs.microsoft.co.il/blogs/t...-tutorial.aspx

    It uses a HLSL shader to do the image manipulation, and is probably 10,000 times faster than anything else you could do in C#. I'm familiar with HLSL, but I have never used WPF before and am at a loss when it comes to how to implement this in my program. I'd like to be able to open an image, apply the filter, and then save the image.

    Here is the code from the link I gave:

    Code:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using Microsoft.Win32;
    using System.IO;
    using System.Diagnostics;
    using System.Windows.Media.Effects;
    
    namespace HLSLTester
    {
        /// <summary>
        /// Interaction logic for Window1.xaml
        /// </summary>
        public partial class Window1 : Window
        {
            public Window1()
            {
                InitializeComponent();
            }
    
           
    
            private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
            {
                OpenFileDialog ofd = new OpenFileDialog();
                ofd.Filter = "Images|*.jpg;*.png;*.bmp;*.gif|All Files|*.*";
                if (ofd.ShowDialog(this) == true)
                {
    
                    img.Source = new BitmapImage(new Uri(ofd.FileName));
                }
            }
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                string path = string.Format("{0}\\tmp",Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData));
                using (FileStream fs = new FileStream(path+".fx", FileMode.Create))
                {
                    byte[] data = Encoding.ASCII.GetBytes(code.Text);
                    fs.Write(data,0,data.Length);
                }
    
    
                ProcessStartInfo psi = new ProcessStartInfo("fxc");
                psi.CreateNoWindow = true;
                psi.UseShellExecute = false;
                
                psi.RedirectStandardError = true;
    
                psi.Arguments = string.Format("/T ps_3_0 /E main /Fo\"{0}.ps\" \"{0}.fx\"",path);
                comp.Text = string.Empty;
                using (Process p = Process.Start(psi))
                {
    
                    StreamReader sr = p.StandardError;
                    comp.Text = sr.ReadToEnd().Replace(path+".fx","Line ");
    
                    p.WaitForExit();
                }
    
                if (comp.Text == string.Empty)
                {
                    PixelShader ps = new PixelShader();
                    ps.UriSource = new Uri(path + ".ps");
                    CustomShaderEffect se = new CustomShaderEffect(ps);
     
                    img.Effect = se;
                }
                
            }
        }
    
        class CustomShaderEffect : ShaderEffect
        {
            public CustomShaderEffect(PixelShader shader)
            {
                PixelShader = shader;
                UpdateShaderValue(InputProperty);
            }
    
            public Brush Input
            {
                get { return (Brush)GetValue(InputProperty); }
                set { SetValue(InputProperty, value); }
            }
    
            public static readonly DependencyProperty InputProperty = ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(CustomShaderEffect), 0);
    
        }
    }
    I get how this works, but I have NO clue how to save the resulting image back to a file. In general, I have very little clue how Image, BitmapImage and other classes work, as I am only familiar with the System.Drawing image and bitmap classes.

    For anyone looking at the code who needs additional explaining, it is taking a .fx file with your pixel shader code and using fxc.exe to compile it into .ps shader file.

    Thanks for any help in advance.
    Last edited by Chris_F; September 29th, 2010 at 01:23 AM.

  2. #2
    Join Date
    Jan 2010
    Posts
    1,133

    Re: Image manipulation in WPF

    Check out the BmpBitmapEncoder class. If you scroll all the way down, you'll find an example.

    The XyzBitmapEncoder classes apparently provide a lot of flexibility, compared to what you had before with Bitmap.Save(...) methods at least.

    You can also try and pull some bitmap data (bitmap bits) based stunt to get an System.Drawing.Bitmap object.

  3. #3
    Join Date
    Aug 2008
    Posts
    902

    Re: Image manipulation in WPF

    Quote Originally Posted by TheGreatCthulhu View Post
    Check out the BmpBitmapEncoder class. If you scroll all the way down, you'll find an example.

    The XyzBitmapEncoder classes apparently provide a lot of flexibility, compared to what you had before with Bitmap.Save(...) methods at least.

    You can also try and pull some bitmap data (bitmap bits) based stunt to get an System.Drawing.Bitmap object.
    Hmm, well I know how to load an image, and display it with a shader effect, and I also know how to load an image and then save it, but I don't know how to load an image, apply an effect and then save it.

  4. #4
    Join Date
    Nov 2010
    Posts
    1

    Re: Image manipulation in WPF

    Quote Originally Posted by Chris_F View Post
    Hmm, well I know how to load an image, and display it with a shader effect, and I also know how to load an image and then save it, but I don't know how to load an image, apply an effect and then save it.
    I have exactly the same problem. I can load a photo to an Image-control, manipulate it with some fancy pixel shaders, but i've failed to save the manipulated photo in original size. I managed to save a jpeg with 800xSomething, but I need it in full size.

    Uncle Google hasn't provided any useful code snippets about the saving thing, so i'm happy about every reply.

    Greetings from Switzerland
    Dani123

  5. #5
    Join Date
    Aug 2008
    Posts
    902

    Re: Image manipulation in WPF

    I guess it can be done using either RenderTargetBitmap or WritableBitmap, but the problem is that if you do this, the pixel shading gets done in software, there is no way to get hardware acceleration. You also can't use multiple shaders or use a multi-pass shader (major disappointment, these seem like huge flaws) so WPF is useless for what I wanted.
    Last edited by Chris_F; November 5th, 2010 at 09:16 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured