Google Earth has a full XML API called KML, or Keyhole Markup Language. KMZ files are compressed KML files. Creating KML files is a no-brainer but out of the box .NET 2.0 does not have the API necessary to create KMZ files. .NET 2.0 includes GZIP libraries but KMZ files are Zip files using the PKZip algorithm. #ziplib is a good open source library that supports PKZip and GZIP. This blog covers the basics of creating an in-memory zip file using #ziplib and serving that as a Google Earth KMZ HTTP Response.
This blog doesn't cover creating the KML since there are already a ton of resources available to do that.
Using in-memory streams is not always the best approach for creating KMZ files - your scenario may require an alternative approach that is not as memory intensive such as file system based .zip files. The in-memory approach works well for quick and dirty KMZ files.
Server MIME Types
You should set your server MIME types as follows:
- application/vnd.google-earth.kml+xml kml
- application/vnd.google-earth.kmz kmz
#ziplib is an open source zip library that works well for this application. Download the latest version and include references to the DLL that it comes with in your application.
Code to create Google Earth KMZ file
This code is not the cleanest so use at your own peril ;)
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Checksums;
...
this.Response.Clear();
this.Response.AppendHeader("Content-Disposition",
"filename=\"Google Earth Download.kmz\"");
this.Response.ContentType = "application/kmz";
this.Response.AppendHeader("Content-Encoding", "kmz");
byte[] bytes = null;
MemoryStream memStream = new MemoryStream();
XmlTextWriter xmlTW = new XmlTextWriter(memStream,
Encoding.UTF8);
xmlTW.WriteStartDocument();
// ...
// Write rest of xml doc...
// ...
xmlTW.WriteEndDocument(); // kml
xmlTW.Close();
bytes = memStream.ToArray(); // vs .GetBuffer();
MemoryStream memStream2 = new MemoryStream();
using (ZipOutputStream gzOs = new ZipOutputStream(memStream2))
{
ZipEntry entry = new ZipEntry("Google Earth Download.kml");
gzOs.SetLevel(9);
gzOs.PutNextEntry(entry);
gzOs.Write(bytes, 0, bytes.Length);
gzOs.CloseEntry();
gzOs.Close();
}
this.Response.Clear();
this.Response.BinaryWrite(memStream2.ToArray());
this.Response.End();
That's the quick and dirty intro. We're simply streaming a .zip file back as the HTTP response. With #ziplib you have to encapsulate the KML in a ZipEntry in order for the compression library to work. Providing you've set your MIME types properly & your HTTP response headers, all should be good to go.
Feel free to experiment with other stream APIs to do the same thing and let me know your thoughts & comments!
6 comments:
Shan, this is just super!
Thanks a lot for your posting. This is exactly what I needed for my application as I create KML/KMZ based on the current language and also based on the current state of the entities used. So, your dynamic solution fits perfectly my scenario.
Andreas
Glad that it came in handy Andreas.
Thanks for this post. Can you point me in the right direction? I'd like my ASP.NET app to READ a KMZ file, and extract the info from it. Does #ziplib have this ability?
Thank You!
Great Post! Just what I needed.
Shan,
Thank you so much for this post! It was awesome! Short, straight to point, and a great sample. Just what I needed. Definitely 4 stars.
Thanks,
Steve
Post a Comment