Custom binary preview
In this final post about the new binary preview feature I'm going to show you how to create your custom preview provider.
A lot of game studios are used to use their own graphics file formats. They are able to edit and work with them using internal tools. This tools are able to read the files and show the user the representative values, so this tools have to do something similar to serialization and deserialization. This is more or less what we need to create our custom preview provider.
For the blog-post example I'll create a new binary file format called .hssff
, yeah "hssff" from the incomparable David Hasselhoff. This new binary file will contain a jpg image and a couple of values that will be the custom binary file atttributes.
What we need
We only need these two things, we'll see that it's very easy using the c# serialization:
- A mechanism to translate a
.hssff
to aHssff
c# object. - A mechanism to translate a
Hssff
c# object to a.hssff
file.
Creating the hssff serializable object
First we need to set the object as serializable and implement the ISerializable interface, quite simple:
[Serializable()] public class Hssff :ISerializable { ... ...
The hssff
object needs two basic methods implemented:
GetObjectData
, this is the method in charge of providing the information to be serialized,Hssff
constructor, this special constructor will build a newHssff
object from the deserialized object information.
This is the implementation of both methods:
public Hssff(SerializationInfo info, StreamingContext ctxt) { this.HssffImage = (Image)info.GetValue("HssffImage", typeof(Image)); this.HowMachoDavidIs = (string)info.GetValue("HowMachoDavidIs", typeof(string)); this.HeartBrakerValue = (int)info.GetValue("HeartBrakerValue", typeof(int)); this.TheBuchananFactor = (int)info.GetValue("TheBuchananFactor", typeof(int)); this.TheKnightRiderFactor = (int)info.GetValue("TheKnightRiderFactor", typeof(int)); } public void GetObjectData(SerializationInfo info, StreamingContext ctxt) { info.AddValue("HssffImage", this.HssffImage); info.AddValue("HowMachoDavidIs", this.HowMachoDavidIs); info.AddValue("HeartBrakerValue", this.HeartBrakerValue); info.AddValue("TheBuchananFactor", this.TheBuchananFactor); info.AddValue("TheKnightRiderFactor", this.TheKnightRiderFactor); }
Serialize and deserialize the c# hssff object
I have an extra object in charge of the serialization and deserialization of the Hssff
object, it's the HssffSerializer
class. Basically, the HssffSerializer
class serializes an Hssff
into an external file and it also deserializes the object from an external file.
public void SerializeObject(string filename, Hssff objToSerialize) { Stream stream = File.Open(filename, FileMode.Create); BinaryFormatter bFormatter = new BinaryFormatter(); bFormatter.Serialize(stream, objToSerialize); stream.Close(); } public Hssff DeSerializeObject(string filename) { Hssff objectToSerialize; Stream stream = File.Open(filename, FileMode.Open); BinaryFormatter bFormatter = new BinaryFormatter(); objectToSerialize = (Hssff)bFormatter.Deserialize(stream); stream.Close(); return objectToSerialize; }
Custom preview tool
Now that we have the ability to "translate" a .hssff
file in both ways, we can create our convert.exe tool needed to generate the preview images for Plastic SCM. Check this blog-post if you don't know what I'm talking about.
Basically, our convert.exe tool has to be able to perform three things:
- Create a small thumbnail from our
hssff
object (used in Plastic SCM preview system). - Create a full size image from our
hssff
object (used in Plastic SCM diff system). - Save both images into a external file to be read by Plastic SCM.
Actually using the HssffSerializer
class we can read the hssff
file and recover a Hssff
object from it. So let's do it by using it:
private static Hssff ReadHssObject(string hssffFilePath) { HssffSerializer serializer = new HssffSerializer(); return serializer.DeSerializeObject(hssffFilePath); }
Now that we have the Hssff
file, we can access to the Image inside it. Let's create a thumbnail from it:
private static void GenerateThumbnail(Hssff deserialHssff, string dstFile) { Size thumbnailSize = GetThumbnailSize(deserialHssff.HssffImage); System.Drawing.Image NewImage = deserialHssff.HssffImage.GetThumbnailImage( thumbnailSize.Width, thumbnailSize.Height, null, IntPtr.Zero); deserialHssff.HssffImage.Dispose(); NewImage.Save(dstFile); } private static Size GetThumbnailSize(Image original) { int originalWidth = original.Width; int originalHeight = original.Height; double factor = 1; if (originalWidth > originalHeight) factor = (double)MAX_THUMNAIL_PIXELS / originalWidth; else factor = (double)MAX_THUMNAIL_PIXELS / originalHeight; Size newSize = new Size( (int)(originalWidth * factor), (int)(originalHeight * factor)); return newSize }
And now a full size image:
private static void GenerateFullImage(Hssff deserialHssff, string dstFile) { deserialHssff.HssffImage.Save(dstFile); }
If our convert.exe program is invoked with the --thumbnail option, we will generate the thumbnail image. If not, we will generate the full size image. Easy :)
Custom attributes tool
The identify.exe tool is even easier. We need it to do the following:
- Read all the text parameters from the
Hssff
object. - Print the parameters using the standard output.
You can use again our ReadHssObject
method inside the HssffSerializer
class in order to "translate" the file into the Hssff
object. Then, we just need to print those values:
static void Main(string[] args) { string hssffFilePath = args[0]; Hssff deserializedHssff = ReadHssObject(hssffFilePath); IdentifyHssff(deserializedHssff); } private static void IdentifyHssff(Hssff deserializedHssff) { Console.WriteLine( string.Format("Heart breaker value: {0}", deserializedHssff.HeartBrakerValue)); Console.WriteLine( string.Format("How Macho David is: {0}", deserializedHssff.HowMachoDavidIs)); Console.WriteLine( string.Format("The Buchananan factor: {0}", deserializedHssff.TheBuchananFactor)); Console.WriteLine( string.Format("The Knight Rider factor: {0}", deserializedHssff.TheKnightRiderFactor)); }
Plastic SCM will read the standard output of our identify.exe program and the values read will be shown on the Properties section in the preview and diff feature.
Adding our custom preview tool
Now that we have all the external tools to provide Plastic SCM with images and properties descriptions, we need to connect them to Plastic SCM.
- Open the Plastic SCM Preferences window.
- Inside the Preview Tools tab select Add.
- Choose the User-defined tool option in the template provider section.
- Type a name for the template.
- Add the full path to the convert.exe tool.
- Set the following line for the thumbail preview command line options: -thumbnail "@src" "@output".
- And this other for the full image size: "@src" "@output"
- Finally, set the full path to the identify tool.
- And configure the command options as follows: "@src"
Testing it
:) Let's give it a try with two revisions of a .hssff
file. This is the first revision of our brand new topSecret.hssff
file:
And this is going to be the second revision:
Let's check the differences before committing the file:
It's awesome how we can now compare the differences of our custom files format, you can extend the complexity with your real custom files, enjoy it!
All the source code used in this blog-post is available here.
0 comentarios: