
Adding frames to a Multi-Frame TIFFMulti-page TIFF images are not directly editable inasmuch as you cannot open one up, slap a new image into it and then save it. You have to go through the process of opening the image, extracting the frames, creating a new TIFF image and saving all the frames back into it again. The frames in a TIFF file can be selected using the SelectActiveFrame method and the contents of the successive frames extracted to separate bitmaps. A new multi-frame TIFF is then created and the images saved in-order to the new image. The following application shown in Figure 1 and listed in C# and VB shows how to append or insert frames into an existing TIFF image.
Figure 1. The MultiTiffManager application
Here's how it works.
Show me code in C# using System; using System.IO; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data;
namespace MultiTiffManager { /// <summary> /// A simple Multi-page TIFF file editor. /// </summary> public class Form1 : System.Windows.Forms.Form { private System.Windows.Forms.ListBox listBox1; private System.Windows.Forms.Button button1; private System.Windows.Forms.Button button2; private System.Windows.Forms.NumericUpDown numericUpDown1; private System.Windows.Forms.Button button3; private System.Windows.Forms.Button button4; private System.Windows.Forms.Button button5; private System.Windows.Forms.Button button6; /// <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.listBox1 = new System.Windows.Forms.ListBox(); this.button1 = new System.Windows.Forms.Button(); this.button2 = new System.Windows.Forms.Button(); this.numericUpDown1 = new System.Windows.Forms.NumericUpDown(); this.button3 = new System.Windows.Forms.Button(); this.button4 = new System.Windows.Forms.Button(); this.button5 = new System.Windows.Forms.Button(); this.button6 = new System.Windows.Forms.Button(); ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit(); this.SuspendLayout(); // // listBox1 // this.listBox1.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawVariable; this.listBox1.IntegralHeight = false; this.listBox1.Location = new System.Drawing.Point(8, 8); this.listBox1.Name = "listBox1"; this.listBox1.Size = new System.Drawing.Size(200, 256); this.listBox1.TabIndex = 0; this.listBox1.MeasureItem += new System.Windows.Forms.MeasureItemEventHandler(this.listBox1_MeasureItem); this.listBox1.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.listBox1_DrawItem); this.listBox1.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged); // // button1 // this.button1.Location = new System.Drawing.Point(280, 16); this.button1.Name = "button1"; this.button1.TabIndex = 1; this.button1.Text = "Load"; this.button1.Click += new System.EventHandler(this.button1_Click); // // button2 // this.button2.Location = new System.Drawing.Point(280, 48); this.button2.Name = "button2"; this.button2.TabIndex = 2; this.button2.Text = "Append"; this.button2.Click += new System.EventHandler(this.button2_Click); // // numericUpDown1 // this.numericUpDown1.Enabled = false; this.numericUpDown1.Location = new System.Drawing.Point(224, 104); this.numericUpDown1.Maximum = new System.Decimal(new int[] { 10000, 0, 0, 0}); this.numericUpDown1.Name = "numericUpDown1"; this.numericUpDown1.Size = new System.Drawing.Size(64, 20); this.numericUpDown1.TabIndex = 3; this.numericUpDown1.ValueChanged += new System.EventHandler(this.numericUpDown1_ValueChanged); // // button3 // this.button3.Enabled = false; this.button3.Location = new System.Drawing.Point(320, 80); this.button3.Name = "button3"; this.button3.TabIndex = 2; this.button3.Text = "Insert"; this.button3.Click += new System.EventHandler(this.button3_Click); // // button4 // this.button4.Location = new System.Drawing.Point(280, 168); this.button4.Name = "button4"; this.button4.TabIndex = 2; this.button4.Text = "Done"; this.button4.Click += new System.EventHandler(this.button4_Click); // // button5 // this.button5.Location = new System.Drawing.Point(280, 216); this.button5.Name = "button5"; this.button5.TabIndex = 2; this.button5.Text = "Cancel"; this.button5.Click += new System.EventHandler(this.button5_Click); // // button6 // this.button6.Enabled = false; this.button6.Location = new System.Drawing.Point(320, 120); this.button6.Name = "button6"; this.button6.TabIndex = 2; this.button6.Text = "Remove"; this.button6.Click += new System.EventHandler(this.button6_Click); // // Form1 // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(408, 269); this.Controls.Add(this.numericUpDown1); this.Controls.Add(this.button2); this.Controls.Add(this.button1); this.Controls.Add(this.listBox1); this.Controls.Add(this.button3); this.Controls.Add(this.button4); this.Controls.Add(this.button5); this.Controls.Add(this.button6); this.Name = "Form1"; this.Text = "Form1"; ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit(); this.ResumeLayout(false);
} #endregion
/// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.Run(new Form1()); }
/// <summary> /// Saves the TIFF file with any changes such as added or removed pages. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button4_Click(object sender, System.EventArgs e) { //saves a new TIFF file with all of the items in the list. if(this.listBox1.Items.Count==0) return;
SaveFileDialog dlg=new SaveFileDialog(); dlg.Filter="TIFF files|*.tiff"; dlg.FileName=this.Text; if(dlg.ShowDialog()==DialogResult.OK) {
if(this.listBox1.Items.Count>1) { //the first item in the list is the master frame. ImageItem ii=(ImageItem)this.listBox1.Items[0]; Bitmap MasterBitmap=(Bitmap)ii.Image;
//Select the image encoder Encoder enc=Encoder.SaveFlag; ImageCodecInfo info=null;
foreach(ImageCodecInfo ice in ImageCodecInfo.GetImageEncoders()) if(ice.MimeType=="image/tiff") info=ice;
EncoderParameters ep=new EncoderParameters(1);
ep.Param[0]=new EncoderParameter(enc,(long)EncoderValue.MultiFrame);
//Save the master bitmap MasterBitmap.Save(dlg.FileName,info,ep);
ep.Param[0]=new EncoderParameter(enc,(long)EncoderValue.FrameDimensionPage);
//add all images from index 1 to n for(int i=1; i<this.listBox1.Items.Count;i++) { ii=(ImageItem)this.listBox1.Items[i]; MasterBitmap.SaveAdd(ii.Image,ep); } ep.Param[0]=new EncoderParameter(enc,(long)EncoderValue.Flush); //close out the file. MasterBitmap.SaveAdd(ep); } else { //do a simple save... ((ImageItem)this.listBox1.Items[0]).Image.Save(dlg.FileName,ImageFormat.Tiff); }
this.Text=dlg.FileName;
}
}
/// <summary> /// Loads the selected image file /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, System.EventArgs e) { OpenFileDialog dlg=new OpenFileDialog(); dlg.Filter="Image files|*.bmp;*.tiff;*.jpg;*.gif"; if(dlg.ShowDialog()==DialogResult.OK) DoOpen(dlg.FileName); }
/// <summary> /// Opens a TIFF image and extracts the frames /// </summary> /// <param name="filename">The filename</param> private void DoOpen(string filename) { ClearItems(); //Open the image using a file stream in case the user wants to save //the image back to the same file. FileStream fs=File.Open(filename,FileMode.Open,FileAccess.Read); Bitmap bm=(Bitmap)Bitmap.FromStream(fs);
if(bm.GetFrameCount(FrameDimension.Page)>1) { for(int i=0; i<bm.GetFrameCount(FrameDimension.Page); i++) { bm.SelectActiveFrame(FrameDimension.Page, i); Bitmap temp=new Bitmap(bm.Width,bm.Height); Graphics g=Graphics.FromImage(temp); g.InterpolationMode=InterpolationMode.NearestNeighbor; g.DrawImageUnscaled(bm,0,0); g.Dispose(); AddFrameToList(temp,-1); } } else AddFrameToList(bm,0);
fs.Close(); bm.Dispose(); this.Text=filename; }
/// <summary> /// Removes all items from the list /// </summary> private void ClearItems() { for(int i=0; i<this.listBox1.Items.Count; i++) { ImageItem item=(ImageItem)this.listBox1.Items[i]; item.Image.Dispose(); } this.listBox1.Items.Clear(); }
/// <summary> /// Adds a frame to the list. /// </summary> /// <param name="i"></param> /// <param name="pos"></param> private void AddFrameToList(Image i, int pos) { if(pos==-1) this.listBox1.Items.Add(new ImageItem(i)); else this.listBox1.Items.Insert(pos,new ImageItem(i));
this.numericUpDown1.Enabled=true; this.button3.Enabled=true; this.button6.Enabled=true; }
/// <summary> /// Measures the ListBox items /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void listBox1_MeasureItem(object sender, System.Windows.Forms.MeasureItemEventArgs e) { ImageItem item=(ImageItem)this.listBox1.Items[e.Index]; float r=this.listBox1.ClientSize.Width; r/=item.Image.Width;
e.ItemHeight=(int)(r*item.Image.Height); e.ItemWidth=(int)(r*item.Image.Width); }
/// <summary> /// Draws the ListBox items /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void listBox1_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e) { if(this.listBox1.Items.Count<1) return; ImageItem i=(ImageItem)this.listBox1.Items[e.Index]; e.Graphics.DrawImage(i.Image,e.Bounds,0,0,i.Image.Width,i.Image.Width,GraphicsUnit.Pixel); }
/// <summary> /// Handles the Append commmand /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button2_Click(object sender, System.EventArgs e) { //Append an image to the list. OpenFileDialog dlg=new OpenFileDialog(); dlg.Filter="Image files|*.bmp;*.jpg;*.gif;*.tif;*.png"; if(dlg.ShowDialog()==DialogResult.OK) { Bitmap toAppend=(Bitmap)Image.FromFile(dlg.FileName); this.AddFrameToList(toAppend,-1); } }
private void numericUpDown1_ValueChanged(object sender, System.EventArgs e) { if(this.numericUpDown1.Value>=this.listBox1.Items.Count) this.numericUpDown1.Value=this.listBox1.Items.Count-1; }
/// <summary> /// Handles the "insert" click /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button3_Click(object sender, System.EventArgs e) { //inserts an image at the index specified by the numeric up-down control. OpenFileDialog dlg=new OpenFileDialog(); dlg.Filter="Image files|*.bmp;*.jpg;*.gif;*.tif;*.png"; if(dlg.ShowDialog()==DialogResult.OK) { Bitmap toAppend=(Bitmap)Image.FromFile(dlg.FileName); this.AddFrameToList(toAppend,(int)this.numericUpDown1.Value); } }
/// <summary> /// handles the "Remove" command /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button6_Click(object sender, System.EventArgs e) { this.listBox1.Items.RemoveAt((int)this.numericUpDown1.Value); if(this.listBox1.Items.Count==0) { this.numericUpDown1.Enabled=false; this.button3.Enabled=false; this.button6.Enabled=false; return; } if(this.numericUpDown1.Value>=this.listBox1.Items.Count) this.numericUpDown1.Value=this.listBox1.Items.Count-1; }
/// <summary> /// Exits the program with a little sanity check /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button5_Click(object sender, System.EventArgs e) { if(MessageBox.Show("Are you sure you want to quit?","Exit TiffManager",MessageBoxButtons.YesNo)==DialogResult.Yes) Application.Exit(); }
/// <summary> /// updates the numeric up-down with the image number for inserts or deletes /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void listBox1_SelectedIndexChanged(object sender, System.EventArgs e) { if(this.listBox1.SelectedIndex==-1) return; this.numericUpDown1.Value=this.listBox1.SelectedIndex; }
}
/// <summary> /// Holds an image for the ListBox /// </summary> public class ImageItem { Bitmap _image; public Bitmap Image { get{return _image;} }
protected ImageItem() { }
public ImageItem(Image i) { this._image=(Bitmap)i; } } }
Show me code in VB
Imports System Imports System.IO Imports System.Drawing Imports System.Drawing.Drawing2D Imports System.Drawing.Imaging Imports System.Collections Imports System.ComponentModel Imports System.Windows.Forms |