Click here to Skip to main content
Click here to Skip to main content
Go to top

SlideShowBuilder

, 26 Oct 2007
Rate this:
Please Sign up or sign in to vote.
An application that allows building of slideshows
Screenshot - slideshowbuilder.jpg

Contents

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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Giorgi Dalakishvili
Software Developer
Georgia Georgia
No Biography provided
Follow on   Google+

Comments and Discussions

 
Questionaccess denied Pinmemberali yeganeh7-Jun-13 13:21 
QuestionForm1.temp? PinmemberRudy Schramm27-May-10 4:30 
Questionplz explain the registerextension method brifly? Pinmemberqauaan11-Aug-09 22:55 
GeneralVery Nice! Pinmemberradialronnie15-Mar-08 9:10 
GeneralRe: Very Nice! PinmvpGiorgi Dalakishvili15-Mar-08 10:20 
Generalvb problem PinmemberMember 441027124-Feb-08 12:39 
GeneralGreat! One question Pinmemberoleg_cherkasenko1-Dec-07 1:28 
GeneralI have an issue PinmemberHaydeng18-Aug-07 14:26 
GeneralRe: I have an issue PinmemberHaydeng18-Aug-07 15:37 
GeneralGood one PinmemberRanjan.D26-Jun-07 6:25 
GeneralReally nice :) Pinmemberseq-21-Jun-07 8:34 
GeneralRe: Really nice :) PinmemberGiorgi Dalakishvili21-Jun-07 8:39 
GeneralRe: Really nice :) Pinmemberkasparovthe24-Dec-09 12:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140916.1 | Last Updated 26 Oct 2007
Article Copyright 2007 by Giorgi Dalakishvili
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid