SlideShowBuilder






4.79/5 (20 votes)
An application that allows building of slideshows

Contents
- Introduction
- What You Can Do with the Program
- How the Program Works
- Code Behind the Application
- Points of Interest
- History
Introduction
The program presented here allows you to build a slideshow from pictures and add background music. Everything is packed into a single executable file, so you just need to send one file to distribute your slideshow.
What You Can Do with the Program
- Build a slideshow from pictures
- Add background music
- Save project files for future use
- Specify various options
These are the options that you can choose:- Loop the slideshow
- Loop background music
- Stretch images to full screen or leave the original size
- Choose the background color (if the images aren't stretched)
- Disable or Enable the Escape key during the slideshow
- Advance to next slide either after a specified amount of time or on mouse click
- Specify an icon for the generated slideshow
How the Program Works
The program builds the slideshow player program using the CSharpCodeProvider
and CompilerParameters
classes. The images and music that the user has chosen are added as embedded resources. In order to pass options from slideshow builder to slideshow maker, I have created a special class called Settings
, which stores information about the options that are chosen. The class is marked as Serializable
and it is serialized to an XML file using the XmlSerializer
class. The serialized file is also added as an embedded resource in the player application. When it is launched, the player application deserializes it and retrieves the options.
I will talk more below about the source code of the slideshow player application, which is compiled at run time, but I want to mention one important point here: Regardless of the number of pictures and options that the user has chosen, the source code that is compiled is always the same. It gets all the information from the Settings
class at runtime.
Code Behind the Application
The Builder
Registering the Extension
When you launch the program, it associates the *.ssb extension with the program. The project files that you save will have the *.ssb extension, so when you double click them, the SlideShowBuilder will be launched showing the content of the file you have double clicked. The project files have an icon associated with them, too. A command is associated with double click and it passes the name of the file as an argument to the program. All this is accomplished with the code presented below:
private void registerextension()
{
//Create necessary keys
RegistryKey RegKey = Registry.ClassesRoot.CreateSubKey(".ssb");
RegKey.SetValue("", "ssb files");
RegKey.Close();
RegKey = Registry.ClassesRoot.CreateSubKey("ssb files");
RegKey.SetValue("", "Slide Show Maker Files");
RegKey.Close();
//Create open command for ssb files
RegKey = Registry.ClassesRoot.CreateSubKey("ssb files" + "\\" + "Shell"
+ "\\" + "Open");
RegKey = RegKey.CreateSubKey("Command");
//Set the application for handling the open command and pass
//the file path as a parameter
RegKey.SetValue("",
"\"" + Application.ExecutablePath + "\"" + " \"%L\"");
RegKey.Close();
//Associate icon for ssb files
RegKey = Registry.ClassesRoot.CreateSubKey("ssb files" + "\\"
+ "DefaultIcon");
RegKey.SetValue("", Application.StartupPath+"\\icon.ico");
RegKey.Close();
}
When you double click the file, the program gets the path of the file as a command line argument. Then the program opens the file that was double clicked.
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 parent = new Form1();
if (args.Length == 1)
{
parent.createchild(args[0]);
}
Application.Run(parent);
}
Saving and Opening Project Files
In order to save project files for future use, I used serialization again, but this time I used Binary Serialization. The reason is that it is faster and produces smaller files than other serialization techniques. To store information about the project, I have created a class called ssbfile
. This class keeps information about the location of all files in the project and various options that have been selected. After you have created an instance of a serializable class, saving it to a file is very easy. Just create an instance of the BinaryFormatter
class and call the Serialize
method.
public void save(string path)
{
Stream str = File.Open(path, FileMode.Create, FileAccess.Write,
FileShare.None);
BinaryFormatter formatter = new BinaryFormatter();
//the getfile() function returns instance of ssbfile
//class for the current project
formatter.Serialize(str, getfile());
str.Close();
isdirty = false;
}
Deserializing is even easier. You only need to remember to cast the result to a proper type.
Stream str = File.Open(path, FileMode.Open);
ssbfile file = null;
try
{
BinaryFormatter formatter = new BinaryFormatter();
file = formatter.Deserialize(str) as ssbfile;
}
catch (SerializationException)
{
MessageBox.Show("The file can not be opened", "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
finally
{
str.Close();
if (file!=null)
{
this.setsettings(file);
}
this.exists = true;
this.Path = path;
}
Serializing Options
When the build button is clicked, settings are serialized to a temporary file. Using XML serialization is easy, too. The only difference is that you need to specify the type of object you are serializing.
private void Serialize(Settings set)
{
Stream stream= File.Open(Form1.temp+"\\settings.xml", FileMode.Create);
XmlSerializer formatter = new XmlSerializer(typeof(Settings));
formatter.Serialize(stream, set);
stream.Close();
}
After this, all the images are copied to a temp folder and their names are changed to 1.jpg, 2.jpg, etc. The reason for this is that the player application will access them using these names. If the names remained the same, either the source code of the player application would have to be changed dynamically or the names would have to be passed to the player, too. Apart from that, this style of naming makes it very easy to know which image comes after which.
So at this point, all necessary files have been copied to the temp folder. Now it is time for compilation!
Building the Slideshow
As I have already mentioned, to generate an executable file from your program you will need the CSharpCodeProvider
and CompilerParameters
classes. The code snippet below shows all the necessary steps:
private bool compile(string path)
{
bool result = false;
using (CSharpCodeProvider code=new CSharpCodeProvider())
{
// create compiler parameters
CompilerParameters compar = new CompilerParameters();
//Set the icon
string pathtoicon = "";
if( !string.IsNullOrEmpty(iconbox.ImageLocation) &&
File.Exists(iconbox.ImageLocation))
pathtoicon=iconbox.ImageLocation;
compar.CompilerOptions = "/target:winexe" + " " + "/win32icon:"
+ "\"" + pathtoicon + "\"";
compar.GenerateExecutable = true;
compar.IncludeDebugInformation = false;
//Add images, music and settings
for (int i = 1; i < filelistbox.Items.Count+1; i++)
{
compar.EmbeddedResources.Add(Form1.temp + "\\" + i.ToString() + ".jpg");
}
if (this.backmusiccheck.Checked && File.Exists(musicpath.Text))
{
compar.EmbeddedResources.Add(Form1.temp + "\\music.mp3");
}
compar.EmbeddedResources.Add(Form1.temp + "\\settings.xml");
compar.OutputAssembly = path;
compar.GenerateInMemory = false;
//Add references
compar.ReferencedAssemblies.Add("System.dll");
compar.ReferencedAssemblies.Add("System.Data.dll");
compar.ReferencedAssemblies.Add("System.Deployment.dll");
compar.ReferencedAssemblies.Add("System.Drawing.dll");
compar.ReferencedAssemblies.Add("System.Windows.Forms.dll");
compar.ReferencedAssemblies.Add("System.Xml.dll");
compar.TreatWarningsAsErrors = false;
//Finally compile it
CompilerResults res = code.CompileAssemblyFromSource(compar,
Properties.Resources.Program);
if (res.Errors.Count > 0)
{
result = false;
}
else
result = true;
}
return result;
}
This is how to build an executable file from your program. Now let's see how to run the slideshow.
The Player
So we have successfully built the slideshow and we are going to run it. Firstly, I will describe it in general and then go into details.
The player application consists of one form, one picturebox and one button. The button is under the picturebox and is not visible. You might be wondering why we need a button at all. The answer is that we need it for disabling the Escape key. The button is set as CancelButton
of the form, so when the user clicks the Escape key, the application either quits or continues depending on the options that the user has chosen. A little trick.
When you run the generated slideshow, settings are deserialized and various options are set according to it. After that, the slideshow begins.
Deserializing Options
In order to deserialize options, we need a stream that contains the XML document to deserialize. As the XML document is embedded in the application itself, we can retrieve it using classes and methods in the System.Reflection
namespace. Then we will be able to deserialize the XML document. Here are the details:
XmlSerializer ser = new XmlSerializer(typeof(Settings));
Stream st =
Assembly.GetExecutingAssembly().GetManifestResourceStream(
"settings.xml");
set = ser.Deserialize(st) as Settings;
st.Close();
Playing Music
If the user has added background music, then it will be extracted to temp folder.
private string extractmusic()
{
string path = Environment.GetEnvironmentVariable("TEMP") + "\\music.mp3";
//Create stream from the file
Stream musicstream =
Assembly.GetExecutingAssembly().GetManifestResourceStream(
"music.mp3");
//Create necessary streams
BinaryReader read = new BinaryReader(musicstream);
FileStream fs = new FileStream(path, FileMode.Create);
BinaryWriter write = new BinaryWriter(fs);
//Read the file from stream and write to file
byte[] bt = new byte[musicstream.Length];
musicstream.Read(bt, 0, bt.Length);
write.Write(bt);
//don't forget to close the streams
musicstream.Close();
read.Close();
write.Close();
fs.Close();
return path;
}
To play the extracted file, I use this class. It allows you to loop playing very easily.
private void playmusic(string path)
{
MP3Player player = new MP3Player();
player.Open((string)path);
player.Looping = set.Loopmusic;
player.Play();
}
Displaying Images
After retrieving the options and setting them, the first picture is displayed. If the user has chosen to advance to the next image by a mouse click, then the application waits for it. Otherwise, after a specified time interval, the image changes automatically. Images are also retrieved using reflection and they are either stretched to full screen or they are left as they are. When a new image is shown, the application is set as TopMost
.
private void setimage(int index)
{
Image temp =Image.FromStream(
Assembly.GetExecutingAssembly().GetManifestResourceStream(
index.ToString() + ".jpg"));
if (set.Stretchimages)
{
this.pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
}
else
{
if (pictureBox1.Height >= temp.Height && pictureBox1.Width >= temp.Width)
pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;
else
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
}
pictureBox1.Image = temp;
this.TopMost = true;
current = current % set.Count + 1;
}
That's all !!!
Points of Interest
XML serialization is quite powerful and easy to use. It helps you to exchange information between different applications. The ability to embed files in an assembly and retrieve them dynamically from the assembly itself is a powerful feature, too. What I like most about this program is that the compiled source code is the same and doesn't depend on the files and options you have chosen.
History
- June 21, 2007 - Initial Release
- October 26, 2007 - Article updated