Saving an Image from a WPF Desktop app to disc using NET5.0

Nigel 271 Reputation points
2021-09-15T15:58:14.563+00:00

I am creating a WPF Desktop application in XAML and C# (.NET 5.0). The idea is to load an image file from disc and change the image format i.e. from JPEG to BMP to save space. Loading the file is easy enough:

private void LoadBtn_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog open = new OpenFileDialog();
            open.Title = "Open Picture";
            open.Multiselect = false;
            open.Filter = "Image Files(*.jpg; *.jpeg; *.gif; *.bmp)|*.jpg; *.jpeg; *.gif; *.bmp";

            if(open.ShowDialog()==true)
            {
                try
                {
                    PicBox.Source = new BitmapImage(new Uri(open.FileName));
                    image.Source = PicBox.Source;
                }
                catch (System.Exception c) { Console.Write("Exception" +c); }
            }

        }

but when it comes to saving the image to disc I run into a brick wall. I have tried SaveFileDialog() but this seems more for text files - I have used it successfully in text editors, etc but with image files I cannot get my head round it:

private void SaveBtn_Click(object sender, RoutedEventArgs e)
        {
            SaveFileDialog save = new SaveFileDialog();
            save.Title = "Save picture as ";
            save.Filter = "Image Files(*.jpg; *.jpeg; *.gif; *.bmp)|*.jpg; *.jpeg; *.gif; *.bmp";
            if (image != null)
            {
                if (save.ShowDialog() == true) 
                //what goes here??
            }
        }

image in both code snippets is a global variable of type Image.

I have tried to search for an answer to this but have had no luck.

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,762 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,855 questions
XAML
XAML
A language based on Extensible Markup Language (XML) that enables developers to specify a hierarchy of objects with a set of properties and logic.
805 questions
0 comments No comments
{count} votes

Accepted answer
  1. Castorix31 84,546 Reputation points
    2021-09-15T17:10:52.003+00:00

    You can do for example =>

    BitmapImage bi = null; // Global
    
    private void LoadBtn_Click(object sender, RoutedEventArgs e)
    {
        OpenFileDialog open = new OpenFileDialog();
        open.Title = "Open Picture";
        open.Multiselect = false;
        open.Filter = "Image Files(*.jpg; *.jpeg; *.gif; *.bmp)|*.jpg; *.jpeg; *.gif; *.bmp";
    
        if (open.ShowDialog() == true)
        {
            try
            {                   
                bi = new BitmapImage();
                bi.BeginInit();
                bi.UriSource = new Uri(open.FileName, UriKind.RelativeOrAbsolute);
                bi.EndInit();                   
    
                PicBox.Source = bi;
            }
            catch (System.Exception c) { Console.Write("Exception" + c); }
        }
    }
    
    
    private void SaveBtn_Click(object sender, RoutedEventArgs e)
    {                                                                                                                                      
        SaveFileDialog save = new SaveFileDialog();                                                                                  
        save.Title = "Save picture as ";                                                                                                                                         
        save.Filter = "Image Files(*.jpg; *.jpeg; *.gif; *.bmp)|*.jpg; *.jpeg; *.gif; *.bmp";                                        
        if (bi != null)                                                                                                              
        {                                                                                                                            
            if (save.ShowDialog() == true)                                                                                           
            {                                                                          
                JpegBitmapEncoder jpg = new JpegBitmapEncoder();                                                                     
                jpg.Frames.Add(BitmapFrame.Create(bi));                                                                              
                using (Stream stm = File.Create(save.FileName))                                                                      
                {                                                                                                                    
                    jpg.Save(stm);                                                                                                   
                }                                                                                                      
            }                                                                                                                       
        }                                                                                                                            
    }     
    

2 additional answers

Sort by: Most helpful
  1. Peter Fleischer (former MVP) 19,321 Reputation points
    2021-09-15T17:16:07.723+00:00

    Hi,
    try following demo:

    XAML:

    <Window x:Class="WpfApp1.Window005"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp005"
            mc:Ignorable="d"
            Title="Load picture / save bmp" Height="450" Width="800">
      <Window.DataContext>
        <local:ViewModel/>
      </Window.DataContext>
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition/>
          <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <Image Source="{Binding Picture}"/>
        <StackPanel Grid.Row="1" Orientation="Horizontal">
          <Button Content="Load" Margin="5" Command="{Binding}" CommandParameter="Load"/>
          <Button Content="Save" Margin="5" Command="{Binding}" CommandParameter="Save"/>
        </StackPanel>
      </Grid>
    </Window>
    

    ViewModel:

    using Microsoft.Win32;
    using System;
    using System.ComponentModel;
    using System.IO;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Media.Imaging;
    
    namespace WpfApp005
    {
      public class ViewModel : ICommand, INotifyPropertyChanged
      {
        public BitmapImage Picture { get; set; }
    
        public void Execute(object parameter)
        {
          switch (parameter.ToString())
          {
            case "Load":
              LoadBtn_Click(null, null);
              break;
            case "Save":
              SaveBtn_Click(null, null);
              break;
            default:
              break;
          }
        }
        private void LoadBtn_Click(object sender, RoutedEventArgs e)
        {
          OpenFileDialog open = new OpenFileDialog();
          open.Title = "Open Picture";
          open.Multiselect = false;
          open.Filter = "Image Files(*.jpg; *.jpeg; *.gif; *.bmp)|*.jpg; *.jpeg; *.gif; *.bmp";
    
          if (open.ShowDialog() == true)
          {
            try
            {
              Picture = new BitmapImage(new Uri(open.FileName));
              OnPropertyChanged(nameof(Picture));
            }
            catch (System.Exception c) { Console.Write("Exception" + c); }
          }
    
        }
    
        private void SaveBtn_Click(object sender, RoutedEventArgs e)
        {
          if (Picture == null) return;
          SaveFileDialog save = new SaveFileDialog();
          save.Title = "Save picture as ";
          save.Filter = "Image File(*.bmp)|*.bmp";
          if (save.ShowDialog() == true)
          {
            BitmapEncoder encoder = new BmpBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(Picture));
            using (var fileStream = new FileStream(save.FileName, FileMode.Create))
              encoder.Save(fileStream);
          }
        }
    
        public event EventHandler CanExecuteChanged;
        public bool CanExecute(object parameter) => true;
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
      }
    }
    
    0 comments No comments

  2. Anonymous
    2021-11-12T15:50:36.937+00:00

    Hello, just so you know converting your JPEG to BMP will not decrease the data size. BMP is a format developed by Microsoft and it does not have any compression or data loss. This means that the quality is very high but also leads to large file size. If you are wanting to decrease the file size you will need to look into using a different JPEG compression type.

    JPEG supports various compression quality levels called QFactor that you can use to pick the right level of compression that works for your use-case. The higher the QFactor, the smaller the image but the more data lost during the compression.

    I downloaded a sample BMP image that is around 329KB and converted it to JPEG using various QFactors. Below shows the size and quality differences.

    • BMP image - 329KB
    • JPEG image with 20 QFactor - 28KB
    • JPEG image with 100 QFactor - 14KB
    • JPEG image with 150 QFactor - 10KB
    • JPEG image with 200 QFactor - 8KB
    • JPEG image with 250 QFactor - 6KB

    As you can see, the higher the quality – the smaller the size, but you might be able to see the data loss once the Qfactor gets higher.

    You can read more about this here:
    https://www.leadtools.com/help/sdk/v22/dh/to/file-formats-jpeg-and-lead-compressed-jpg-j2k-jpx-jp2-jls-cmp-cmw.html
    https://www.leadtools.com/help/sdk/v22/dh/to/compression-quality-factors.html

    Disclaimer: I work for LEADTOOLS

    All that being said, you can use LEADTOOLS Imaging SDK technology in your application to choose a different compression algorithm or set the QFactor
    https://www.leadtools.com/sdk/engine/imaging

    You can leverage the ImageViewer, RasterCodecs, RasterImage, and RasterSaveDialog class. The RasterSaveDialog class displays a save dialog box and allows you to gather the options from it to export to your desired file path, format, and compression. https://www.leadtools.com/help/sdk/v22/dh/wf/rastersavedialog-ctor.html

    148914-savedialogss.png

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.