.
GDI+ FAQ
Skip Navigation LinksWelcome : GDI+ FAQ : Modifying an image and writing it back to the same filename

Writing a modified image to the original filename

A question that pops up all the time is:

"I want to open an image file and then save that same file in a different format or back to the same filename after making modifications and I keep getting A generic error occurred in GDI"

This problem arises because GDI+ tries to be IO efficient by reading in only the headers of an image, so that you can see its width, height, colour depth etc. It leaves the file open and locked so that it can go get the actual bits when you want to look at them.

The file remains locked even after you've read all the bits in, for the lifetime of the Image object in fact, and therefore you cannot write back to that file with a modified version of the image.

To have access to the file for writing, you must dispose of the original image, which makes it difficult to save it afterwards.

The trick is to do the following:

  1. Open the image file
  2. create a temporary in-memory image the same size as the original
  3. obtain a Graphics object for the temporary image
  4. Draw the original image onto the temporary one
  5. dispose of the original
  6. do any drawing you'd like on the image using the Graphics you have
  7. Dispose of the Graphics
  8. Write the temporary file to any filename and any format you please including the same name and format if you wish.

The following application combines a file-format converter with a picture time-stamper that shows off this technique.

  • Click "Choose files" to select one or more image files.
  • Choose the output format in the dropdown
  • Decide whether you want a timestamp or not and click "Convert"
  • If you choose jpeg files as input, a timestamp and jpeg files as output you will open the files, stamp them and write them back to the same filename again (Don't do this with files that you want to keep pristine!)

The following listing shows how. All the hard work is done in the button2_click handler.

using System;

using System.IO;

using System.Drawing;

using System.Drawing.Imaging;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

 

namespace FormatConvertor

{

  /// <summary>

  /// Summary description for Form1.

  /// </summary>

  public class Form1 : System.Windows.Forms.Form

  {

    private System.Windows.Forms.Button button1;

    private System.Windows.Forms.ComboBox comboBox1;

    private System.Windows.Forms.Button button2;

    private System.Windows.Forms.Label label1;

    private System.Windows.Forms.CheckBox checkBox1;

    /// <summary>

    /// Required designer variable.

    /// </summary>

    private System.ComponentModel.Container components = null;

 

    public Form1()

    {

      //

      // Required for Windows Form Designer support

      //

      InitializeComponent();

 

      //

      // TODO: Add any constructor code after InitializeComponent call

      //

    }

 

    /// <summary>

    /// Clean up any resources being used.

    /// </summary>

    protected override void Dispose( bool disposing )

    {

      if( disposing )

      {

        if (components != null)

        {

          components.Dispose();

        }

      }

      base.Dispose( disposing );

    }

 

    #region Windows Form Designer generated code

    /// <summary>

    /// Required method for Designer support - do not modify

    /// the contents of this method with the code editor.

    /// </summary>

    private void InitializeComponent()

    {

      this.button1 = new System.Windows.Forms.Button();

      this.comboBox1 = new System.Windows.Forms.ComboBox();

      this.button2 = new System.Windows.Forms.Button();

      this.label1 = new System.Windows.Forms.Label();

      this.checkBox1 = new System.Windows.Forms.CheckBox();

      this.SuspendLayout();

      //

      // button1

      //

      this.button1.Location = new System.Drawing.Point(8, 24);

      this.button1.Name = "button1";

      this.button1.TabIndex = 0;

      this.button1.Text = "Choose files";

      this.button1.Click += new System.EventHandler(this.button1_Click);

      //

      // comboBox1

      //

      this.comboBox1.Items.AddRange(new object[] {

                               "GIF",

                               "JPG",

                               "JPEG",

                               "BMP",

                               "PNG"});

      this.comboBox1.Location = new System.Drawing.Point(96, 24);

      this.comboBox1.Name = "comboBox1";

      this.comboBox1.Size = new System.Drawing.Size(121, 21);

      this.comboBox1.TabIndex = 1;

      //

      // button2

      //

      this.button2.Location = new System.Drawing.Point(232, 24);

      this.button2.Name = "button2";

      this.button2.TabIndex = 0;

      this.button2.Text = "Convert";

      this.button2.Click += new System.EventHandler(this.button2_Click);

      //

      // label1

      //

      this.label1.Location = new System.Drawing.Point(96, 8);

      this.label1.Name = "label1";

      this.label1.Size = new System.Drawing.Size(100, 16);

      this.label1.TabIndex = 2;

      this.label1.Text = "Output format";

      //

      // checkBox1

      //

      this.checkBox1.Location = new System.Drawing.Point(8, 64);

      this.checkBox1.Name = "checkBox1";

      this.checkBox1.Size = new System.Drawing.Size(208, 24);

      this.checkBox1.TabIndex = 3;

      this.checkBox1.Text = "Time stamp the image.";

      //

      // Form1

      //

      this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

      this.ClientSize = new System.Drawing.Size(312, 93);

      this.Controls.AddRange(new System.Windows.Forms.Control[] {

                                      this.checkBox1,

                                      this.label1,

                                      this.comboBox1,

                                      this.button1,

                                      this.button2});

      this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;

      this.Name = "Form1";

      this.Text = "Image Format Converter";

      this.ResumeLayout(false);

 

    }

    #endregion

 

    /// <summary>

    /// The main entry point for the application.

    /// </summary>

    [STAThread]

    static void Main()

    {

      Application.Run(new Form1());

    }

 

    string[] names;

    bool chosen=false;

 

    private void button1_Click(object sender, System.EventArgs e)

    {

      OpenFileDialog dlg = new OpenFileDialog();

      dlg.Filter="Image files (*.jpg,*.jpeg,*.bmp,*.gif,*.png)|*.BMP;*.PNG;*.JPG;*.JPEG;*.PNG";

      dlg.Multiselect=true;

      if(dlg.ShowDialog()==DialogResult.OK)

      {

        chosen=true;

        names=dlg.FileNames;

      }

    }

 

    private void button2_Click(object sender, System.EventArgs e)

    {

       if(chosen && this.comboBox1.Text!="")

      {

        chosen=false;

        foreach(string s in names)

        {

          //open the file

          Image i = Image.FromFile(s);

          //create temporary

          Image t=new Bitmap(i.Width,i.Height);

          //get graphics

          Graphics g=Graphics.FromImage(t);

          //copy original

          g.DrawImage(i,0,0);

          //close original

          i.Dispose();

          if(this.checkBox1.Checked==true)

          {

            //draw on temporary

            Font f = new Font("Verdana",30);

            g.DrawString(DateTime.Now.ToShortDateString()+":"+DateTime.Now.ToShortTimeString(),

              f,

              Brushes.Red,

              10,10,

              StringFormat.GenericTypographic);

            f.Dispose();

          }

          g.Dispose();

          ImageFormat fmt = ImageFormat.Bmp;

          switch(this.comboBox1.Text)

          {

            case "JPG":

            case "JPEG":

              fmt=ImageFormat.Jpeg;

              break;

            case "GIF":

              fmt=ImageFormat.Gif;

              break;

            case "PNG":

              fmt=ImageFormat.Png;

              break;

          }

          //save the file. Even if its the same filename

          t.Save(Path.GetFileNameWithoutExtension(s)+"."+this.comboBox1.Text,fmt); 

        }

      }

    }

  }

}

 

Back to the GDI+ FAQ
Copyright Robert W. Powell 2003. All rights reserved.

 

Sponsored By
DaraizeTechnologies.com
Bob Powell

Create your badge

Copyright © Bob Powell 2000-2012.  All rights reserved.