Academic Students Projects | Software School Projects | Free Source Codes | College
Projects By LANGUAGE
Libraries
Articles & seminars
Source Code
Embedding an image in a textfile
For a long time we are trying to embed an image within a textfile, which seems like a strange thing to do,but does have it's uses.For example I wanted users of my system to be able to save their files with a descriptive icon that they could design within the program,so that when it loaded they (and other users) had a graphical representation of what their saved file does (the system controls medical machines, and the file contains routines for these machines to run).Firstly, we should create a class that we will use for all manipulation of files:
CODE
public class MyFileType
{
}
We will give this class one field to start with, which will contain the data to embed as a string:
/// <summary>
/// My file type, used for manipulating custom data
/// </summary>
public class MyFileType
{
/// <summary>
/// The jpeg data to embed to a file
/// </summary>
private String jpegDataToEmbed;
}
This class will need to use some simple IO for inputting and outputting data. This requires the System.IO namespace,so add this to the top along with the other references.We will also need to use the BinaryFormatter class,so add the System.Runtime.Serialization.Formatters.Binary reference as well,and System.Drawing for all imaging references.Should look like this:.
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Drawing;
Ok,coding time!What will we need? Well the first thing to do is read the file that we want to embed in the text,and output it as a string.So we will create a private method called "imageToString" which will take one argument of type Image,imageToEmbed,which will be the image we want to embed:
private String imageToString(Image imageToEmbed)
{
}
Right,so now we will do the code that will take this image, use a BinaryFormatter to serialize the data to a MemoryStream and then convert this to a Base64 string - a type of encoding that,again for reasons unknown to me,stops the image getting corrupted in translation.The encoded string is what we will return and what will be embedded in the file.
private String imageToString(Image imageToEmbed)
{
   // create a new binary formatter
   BinaryFormatter binaryFormatter = new BinaryFormatter();
   // create a memory stream. This is where the data will be stored
   MemoryStream retrievedStream = new MemoryStream();
   // seralize the data from the image to the memory stream
   binaryFormatter.Serialize(retrievedStream, imageToEmbed);
   // return a string in base64 from the memorystream
   return Convert.ToBase64String(retrievedStream.ToArray());
}
So we have this method that can take an image and convert it to a base 64 string,so we need a way of using this to create our file.We will create a public method that takes an image and a path to save to as arguments,and from this we will make our text file containing the embedded data:
public void EmbedImageToFile(String path, Image imageToEmbed)
{
   // ok convert image to string and save in my private field
   this.jpegDataToEmbed = this.imageToString(imageToEmbed);
   // now write the file to the provided path
   using (StreamWriter writer = new StreamWriter(path))
   {
      // write the data string
      writer.Write(this.jpegDataToEmbed);
   }
}
Congratulations you now have the code to embed an image in a textfile!However what if we want some other data to be included in the file?How will we know where our image data is?What we do is to create 2 values that will delimit the start of where our data is embedded in the file,and where the data ends,sandwedge the data in between these,and then when we read this data back we can look up where it is with ease.Create a static string for the class for both the start of and end of values within the general class declarations:
private static String jpegLeadIn = "BOJPEGEMBED";
private static String jpegLeadOut = "EOJPEGEMBED";
And then modify the EmbedImageToFile method to write the lead in as a prefix before the embedded data,and the lead out as a postfix after the data:
public void EmbedImageToFile(String path, Image imageToEmbed)
{
   // ok convert image to string and save in my private field
   this.jpegDataToEmbed = this.imageToString(imageToEmbed);
   // now write the file to the provided path
   using (StreamWriter writer = new StreamWriter(path))
   {
      // write lead in
      writer.Write(MyFileType.jpegLeadIn);
      // write the data string
      writer.Write(this.jpegDataToEmbed);
      // write lead out
      writer.Write(MyFileType.jpegLeadOut);
   }
}
So now we have an image embedded in a file,we want to be able to retrieve it right?Well we should do 'cus what good is an image displayed as base64?!So create a private method with return type Image,lets call it stringToImage,and give it a string argument "inputString":
private Image stringToImage(String inputString)
{
   // create an memorystream derived from base64 stream to byte array
   MemoryStream ourImageData=new MemoryStream
                                                    (Convert.FromBase64String(inputString));
   // create a binary formatter to deserialze the memorystream
   BinaryFormatter binaryFormatter = new BinaryFormatter();
   // create an image object to return on deserialized memory stream
   Image ourRecoveredImage = 
                                      (Image)binaryFormatter.Deserialize(ourImageData);
   // return image
   return ourRecoveredImage;
}
So we will get the image back,but how will anything else access this outside the class?Create a public Image variable in the declarations for the class:
public Image FilesImage;
So now we need a method which can be accessed publicly which can load the contents of the file and store it in the instance of the class.This method will need to extract the image data from the file, stripping the prefix and postfix ,and assign this to the image field.We would also derive any other data the file contains here, if there was any.
public void LoadFile(String path)
{
   // variable to hold file contents
   String dataFromFile;
   // firstly we will load the file at the given path
   using (StreamReader reader = new StreamReader(path))
   {
   // put contents of file to variable
   dataFromFile = reader.ReadToEnd();
   }
   String imageData= dataFromFile.Substring
   (dataFromFile.IndexOf(MyFileType.jpegLeadIn),
                                      dataFromFile.IndexOf(MyFileType.jpegLeadOut) -
   dataFromFile.IndexOf(MyFileType.jpegLeadIn));
   imageData = imageData.Replace(MyFileType.jpegLeadIn, "");
   imageData = imageData.Replace(MyFileType.jpegLeadOut, "");
   this.FilesImage = this.stringToImage(imageData);
}
And that should get you your image back out.Lets throw something else into the mixer - lets also put some notes in the file to prove it works.Create a public string field in the declarations called "Notes" - populate it with a simple test message:
public String Notes = "Here is some file notes"
And modify the EmbedImageToFile methhod
public void EmbedImageToFile(String path,Image imageToEmbed)
{
   this.jpegDataToEmbed = this.imageToString(imageToEmbed);
   using (StreamWriter writer = new StreamWriter(path))
   {
      // write notes
      writer.Write(this.Notes);
      // write lead in
      writer.Write(MyFileType.jpegLeadIn);
      // write the data string
      writer.Write(this.jpegDataToEmbed);
      // write lead out
      writer.Write(MyFileType.jpegLeadOut);
   }
}
And also modify the LoadFile method so that it sets the Notes field from the file.In this example we are just saying that Notes is anything before the image prefix,but in reality we should have a notes prefix and postfix to indentify where in the file these are.
this.Notes=
      dataFromFile.Substring(0,dataFromFile.IndexOf
                                        (MyFileType.jpegLeadIn));
String imageData = dataFromFile.Substring
                             (dataFromFile.IndexOf(MyFileType.jpegLeadIn),
dataFromFile.IndexOf(MyFileType.jpegLeadOut) -
dataFromFile.IndexOf(MyFileType.jpegLeadIn));
imageData = imageData.Replace(MyFileType.jpegLeadIn, "");
imageData = imageData.Replace(MyFileType.jpegLeadOut, "");
this.FilesImage = this.stringToImage(imageData);
}
If your project is not already a Windows Forms Application then start one now,and add the class we have just created to it.Then add a text box to the form and call it "notesTextBox".Also add a picture box and call it "displayPictureBox".In the forms load method add the following code:
String textFilePath = 
"C:\\DocumentsandSettings\\Administrator\\Desktop\\EmbeddedTextFile.txt";
String imageFilePath = 
"C:\\DocumentsandSettings\\Administrator\\Desktop\\Test.jpg";
MyFileType TestFile = new MyFileType();
TestFile.EmbedImageToFile(textFilePath, Image.FromFile(imageFilePath));
MyFileType readFile = new MyFileType();
readFile.LoadFile(textFilePath);
displayPictureBox.Image = readFile.FilesImage;
notesTextBox.Text = readFile.Notes;