question

m0cvo avatar image
0 Votes"
m0cvo asked KipHackman-8296 answered

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

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.

dotnet-csharpwindows-wpfdotnet-wpf-xaml
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Castorix31 avatar image
0 Votes"
Castorix31 answered m0cvo commented

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);                                                                                                   
             }                                                                                                      
         }                                                                                                                       
     }                                                                                                                            
 }     
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thank you, this worked and produced the result I was aiming for.

0 Votes 0 ·
PeterFleischer-3316 avatar image
0 Votes"
PeterFleischer-3316 answered

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));
   }
 }



5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

KipHackman-8296 avatar image
0 Votes"
KipHackman-8296 answered

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



savedialogss.png (386.4 KiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.