Sunday, 21 September 2008

SilverlightEarth updated for rc0

If you have been updating your Silverlight 2.0 beta 2 for Release Candidate 0, you will probably be familiar with this error "Failed to load the application. It was built with an obsolete version of Silverlight":

Even if your code is 100% RC0 'compatible', you need to re-compile your Silverlight assemblies with the RC0 Silverlight Tools for Visual Studio.

For example, SilverlightEarth.com/2 is updated for RC0, and SilverlightEarth.com/2b2 still hosts the beta2 bits. Although no code changes were required (or made), there a minor visual differences that I have yet to correct (the height of the radio-button StackPanels, for example).

SilverlightEarth.com hosting OpenStreetMap with the Google StreetView overlay

Slightly OT: GIS in XML blog posted recently about
Virtual Earth - DeepEarth - Deep Pockets. Basically it calculates a cost of approx. $1.25 per viewer if licensing Microsoft's Virtual Earth tiles for use in DeepEarth (Silverlight 2.0 map tile client)... although Microsoft can't be too concerned since they have it listed in their Community Gallery!

Luckily silverlightearth.com/2 offers OpenStreetMaps and NASA Blue Marble imagery...

Way OT: the Deep Zoom Tag Cloud example also updated for RC0

Wednesday, 27 August 2008

GeoData Visualization: Geoquery v. SQL Server 2008

Came across this post today - GeoData Visualization vs. Analysis - and thought it would be fun to try in Geoquery.

The dataset (au_sumg.e00) can be found at USGS and imported into SQL Server 2008 using Shape2Sql (by Morten). Among other statistics it contains data on known oil reserves (outside the USA, as of 2000).

The simplest query - SELECT * FROM au_sumg - looks like this in SQL Server 2008 Management Studio and Geoquery 2008 respectively:



Management Studio's Dundas graphic sure looks nice - but a little difficult to interpret in isolation. Geoquery's Shape tab looks worse without even the funky pastel colors.

However, the Map tab in Geoquery starts to make up for the green-ness by giving the shapes some context.


But that's not all - using the same 'scale' as this image and the [Fill] and [Thickness] 'special columns' that Geoquery supports we can write this:
select * ,
CASE
WHEN KWN_OIL < -6238 THEN '#FFF2ECB0'
WHEN KWN_OIL < 15769 THEN '#FFF3CE75'
WHEN KWN_OIL < 37775 THEN '#FFEA944B'
WHEN KWN_OIL < 59781 THEN '#FFB16B3A'
ELSE '#FF864E37'
END AS [Fill]
, 0 AS [Thickness]
FROM au_sumg
to produce this result:


Of course, viewing these results on the globe offers absolutely no advantage; but I'll include an obligatory screenshot anyway...

Sunday, 24 August 2008

DeepZoom "Publisher" (alpha)

The website for DeepZoomPublisher.com is now 'live', although Publisher itself isn't quite finished yet. In the interim, I've uploaded Tag Updater which is a much simpler tool to extract metadata from JPGs and make it 'accessible' within a Silverlight 2.0/Deep Zoom application.

Tag Updater is based on this Filtering by Tag Sample and these previous posts. An example of the 'output' from Tag Updater can be viewed here

Also, Deep Zoom Composer can now stitch panoramas!.

In unrelated news, Geoquery 2008 examples have also been updated.

Friday, 22 August 2008

My first Photosynth...

Photosynth is live; and after the site was "overloaded" yesterday I was able to upload my first effort today. It's only 50% synthy but at it's a start... check out my Punakha Dzong (Bhutan) Photosynth!
UPDATE 1: scroll down for my second 66% synthy Thimphu Dzong (Bhutan) Photosynth!
UPDATE 2: scroll down some more for my third 40% synthy Sydney (Australia) Photosynth!



I love how it DeepZooms into the detail




which is no surprise, incidentally, since Photosynth seems to be using DeepZoom files (.dzc and .dzi) as part of it's file structure. Here's a Photosynth message from yesterday:

and the DeepZoom-related files it references (note the xmlns="http://schemas.microsoft.com/deepzoom/2008"):


So there is a single .dzc (DeepZoom Collection) file that appears to define each of the 'photos' in the synth(?) and a .dzi (DeepZoom Image) file for each of them. There must be much more information to support the Photosynth renderer (the 'dots', the 3D 'position' of the images, etc) but given the shared heritage with the Silverlight 2.0 MultiScaleImage control I wouldn't be surprised to see a Photosynth 'viewer' in RTM version of Silverlight 2.0 (or certainly a future version after that).

UPDATE: my second attempt - Thimphu Dzong (Bhutan) Photosynth - is online. Click to enlarge the black-ish image: it shows the 'dots' that tie the photos together. You can zoom "past" a small 'rotunda' to the right of center to see this doorway and flowerbed...



UPDATE: my second attempt - Sydney (Australia) Photosynth - is online now. Not sure why it's only 40% synthy tho'



Keep an eye out for more Photosynths.

Wednesday, 20 August 2008

Geoquery 2008 v0.73 (for SQL Server 2008 RTM)

v0.72 of Geoquery2008 has been recompiled against Microsoft.NET Framework 3.5 SP1 and updated for the RTM of SQL Server 2008. It also has a new home, at

Geoquery2008.com!

It is now aware of the geography coordinate order swap and only requires the Client Profile portion of Microsoft.NET Framework 3.5 Service Pack 1 and the System CLR Types to run.

The next 'major' version - 0.8 - is still a work-in-progress - but will never be designed to compete with the 'built-in' Spatial Results Tab in Management Studio.

Monday, 18 August 2008

SilverlightEarth gets OpenStreetView, Hotmap layers

SilverlightEarth.com now has some additional map tile layers to view:OpenStreetMap with Google StreetView overlay


Hotmap overlaid on Virtual Earth

Thursday, 24 July 2008

DeepZoom Composer Tag "Generator" MkIII



A comment on a previous post says Because WebClient has a dependency on a web server running, the version I wrote won't be added as a project template into Deep Zoom Composer, which sounds like a shame and got me wondering how to get around the 'WebClient' problem.

The 'WebClient' problem is actually related to security and the sandbox. Kirupa's Tag Sample needs to load Metadata.xml into Silverlight/c#, and it uses WebClient to trigger an asynchronous download...

but you can't do that if you Silverlight control is hosted in a web page off your local disk!

It turned out to be pretty easy to get around - firstly here's a screenshot: the page has simply been double-clicked off the hard-drive, yet it is still able to load *some metadata* to enable tagging & description display.


Ah-ha - so you notice I said "some metadata" and not Metadata.xml. Since it is so hard to 'load' Xml off the filesystem (thanks to the Silverlight sandbox), and since my Tag Generator is parsing and re-writing Metadata.xml anyway, we just write another (JSON) file - Metadata.xml.js then go around the sandbox and load as JSON via Javascript Interop.

It took a little experimenting to get right, but the basic changes to make it work are:

1) Tag Generator emits JSON


2) Tag Generator saves "Metadata.xml.js"


3) Html page references "Metadata.xml.js"


4) Declare 'matching' C#/Silverlight class (to JSON), and a method to Deserialize to it


5) THE MAGIC Javascript Eval turns our string into JSON, replacing the LoadXMLData() at the start of the post


6) Update xmlClient_DownloadStringCompleted to walk the JSON object array instead of Xml, and the rest of the code 'just works'!

You'll want to add a couple of assembly references to your Silverlight (System.Json, System.ServiceModel.Web) and namespaces (System.IO, System.Text, System.Json, System.Runtime.Serializatin.Json) to get everything working. This post on Consum(ing) a JSON object in Silverlight set me on the right track, and the Silverlight and JavaScript Interop Basics filled in the gaps.

The Javascript Interop is capable of much more: HtmlPage.Window.Invoke for going to Javascript, and the [Scriptable*] attributes to expose managed code for Javascript to use; but a simple Eval was all I need for this little experiment.

p.s. I did wonder whether it's possible to "include" an .XML file in the HTML for DOM access... I vaguely remember IE supporting 'XML data islands' or something along those lines. However JSON definitely seems like the 'modern' way to approach the problem IMO, and without getting into x-browser compatibility stuff...

Monday, 21 July 2008

OpenSearch [in your browser]

Scott Hanselman blogged today about adding OpenSearch to a website; he made it sound so easy that I had to update Searcharoo.net and SilverlightEarth.com.

You can now access both "search" functions direct from your browser, then you can search:

Searcharoo for 'new york'


SilverligthEarth for 'new york'


and of course SilverligthEarth (2.0 beta) for 'new york'



In order to get it to 'look right' I had to rustle up a couple of favicons... I think they look okay for a few minutes work :-)

Sunday, 20 July 2008

DeepZoom Composer Tag "Generator"

If you've read the previous two posts, they're about using the new Tag input of Deep Zoom Composer, you'll know that the tags you type in DZC can be used to filter your Deep Zoom Collection like this.


HOWEVER, you probably already add metadata to your photos (using a program like iTag), right?


Rather than RE-type into Composer, the attached project TagUpdater will 'post-parse' your Metadata.xml (after you've finished laying out your photos in DeepZoom Componser) and extract your Title, Description, Keywords (Tags) and Rating, which it will then save back to the XML.

Simply type this:
TagUpdater.exe "C:\...\ClientBin\GeneratedImages\Metadata.xml"

See this:


And it does this:


Then deep zoom away (use this post as a guide).

Note that TagUpdater currently extracts more metadata fields than Silverlight DeepZoom Tag Cloud example displays, but it's trivial to add more (such as the Title and Rating). Further, TagUpdater could be tweaked to extract camera data, GPS location and any other information to be saved in Metadata.xml for use in Silverlight.

DOWNLOAD TagUpdater.zip (24Kb)

Note: I borrowed the jpeg parser from Searcharoo, parts of which were originally written by Asim Goheer and Omar Shahine. It could be updated to use WIC.

Saturday, 19 July 2008

DeepZoom Composer Tag "Cloud" Mk II



Adding tags within the latest Deep Zoom Composer is a neat way to navigate DeepZoom 'Collections'.

But if we are going to introduce a new file (Metadata.xml) why not really leverage it?

To that end, I've added a Description element to the Metadata.xml file and typed my own descriptions for each image in my collection. There are two new TextBlocks in the Silverlight control to show the data, and whenever your mouse is over an image, its Tag and Description are displayed. Try it out (beta 2) (or RC0).



The code to match extract the description is a simple extension of the Tag sample.


Then we need to add some code to the MouseMove event to see what SubImage we're over:


which uses SubImageHitTest() from ProjectSilverlight to determine the index of the image to show Tag/Description for.



Finally, you'll notice the 'browse by tag' is now a very basic "cloud". To accomplish that I replaced the ListBox with WrapPanel for Silverlight 2.0 off CodeProject, replaced the items with Buttons and added this ControlTemplate:


The updated files are Page.xaml.cs and Page.xaml.

Wednesday, 9 July 2008

DeepZoom Composer Tag "Cloud"



One of the Deep Zoom Composer team recently posted a Filtering by Tag Sample that takes advantage of the new "Tag" input in the latest Deep Zoom Composer release.

Kirupa says specifically "A major limitation in the current version is that if you have multiple tags separated by commas, the application doesn’t break them up and allow you to filter by them.That means, your images can only have one tag associated with them. Don’t worry – I will fix that shortly"...

Turns out you can enable multiple tags with relatively few changes to the example code (and a bit of inspiration from Kosta's Tag Cloud example).

The result looks like this (click to view larger image; notice the tags are scaled according to frequency), or try it here (beta2) (or RC0. The Metadata.xml shows how the source data looks.



The only changes to Kirupa's sample were in the xmlClient_DownloadStringCompleted handler, which is called when the Metadata.xml has been retrieved. To try out the multiple-tag-"cloud" you should follow his instructions to get it running, then update xmlClient_DownloadStringCompleted with this code. Don't forget to seperate your tags with commas or semicolons!

The major changes to enable multiple tags were:

1. split and trim the tag string/s


2. use the uniqueTags Dictionary to store the 'count' of tag occurances


3. loop through all the tags to build a unique list, rather than assume just one is attached to the image


4. 'hardcode' the relative font sizes


There are many areas where this code to be improved - the tag handling is case sensitive (so "monastery" and "Monastery" would be listed seperately), the font size could be calculated (logarithmically?) rather than hardcoded , the tag-list could be more 'cloud like' rather than being hosted in a ListBox and much more. They may be addressed in future posts... or attempted by the reader.

Tuesday, 24 June 2008

Silverlight(DeepZoom)Earth (beta 3)

SilverlightEarth.com 2.0 beta (DeepZoom) now includes a new 'row' of functionality: latitude/longitude display, DeepZoom "zoom" factor display and a geocoding search:



It's not the most "full featured" search function - if zoom factor is less than '40' it will zoom to that level, otherwise it will preserve any higher 'power' of zoom. It might occasionally take you somewhere unexpected, as disambiguation isn't supported (yet).

You can also trigger a search from the querystring, so you can 'bookmark' a search, like this:

silverlightearth.com/2b2/?q=Golden Gate Bridge

or with zoom specified as well (note it's "DeepZoom Zoom Factor" and not your usual VE 1..18 range)

silverlightearth.com/2b2/?q=Seattle Space Needle&z=8000

"Reset" zooms back to the starting viewpoint. It seems I've broken the overlay with these changes - fix to come...

OT: this is one case where it's actually easier not to use DeepZoom - check out how much faster the Silverlight 1.0 version loads
silverlightearth.com/?q=Seattle Space Needle&z=16

UPDATE (25-Jun): Accepts both "Zoom Factor" AND "Tile Level"... if z < 18, z^2 is used as the "Zoom Factor", eg.
silverlightearth.com/?q=Sydney&z=16

Map selection is also supported from the URL, for example
silverlightearth.com/?q=Sydney&z=15&m=earthgt
The map 'codes' are backward compatible with Silverlight Earth 1.0.

Mapm=
Virtual Earth (road)earth
Virtual Earth (shade) earth2
Virtual Earth (satellite)earths
Virtual Earth (hybrid)earthh
Google (road) earthgr
Google (satellite) earthgs
Google (topo)earthgt
Yahoo (satellite)earthy
Blue Marbleearthbm
Moonmoon
Marsmars
The "q"uery can also be a simple latitude/longitude point, like this silverlightearth.com/2b2/?q=51.500151,-0.126236&z=12&m=earthg (or in SilverlightEarth 1.0).

Saturday, 14 June 2008

Silverlight(DeepZoom)Earth (beta 2)

After reading these posts on using new Silverlight 2.0 beta 2 Deep Zoom functionality to utilise external tile pyramids (such as Virtual Earth) I decided to give it a go...

The sample code was pretty complete, I just added the Geoquery MapSources, and away it goes...

silverlightearth.com/2b2 (requires Silverlight 2.0 beta 2)


(screenshot a bit stylized to show the different map possibilities)

Okay, there's no searching/geocoding or other map niceties; and the DeepZoom shading (which works great for most things) is a little screwy on text-layers - you'll see what that means if you try it out. But it does work nicely, and puts my (still not finished) Silverlight 1.0 code to shame!

Monday, 9 June 2008

Latest Searcharoo.net - images and geocoding

Searcharoo.net has been updated to version 6; which includes Jpeg image parsing, Gps latitude/longitude metadata and integration with Google Earth and Maps.



There's still a final round of testing to do before the article goes onto CodeProject, but it seems to work pretty well so far. Now, back to DeepZoom Publisher...

UPDATE 11-Jun-08: Image and Location Search(aroo) article now on CodeProject.

Wednesday, 28 May 2008

Thursday, 15 May 2008

Whither Geoquery?

If you were reading this blog earlier in the year, you may have seen these posts on Geoquery for SQL Server 2008.

Since my last post (in March) a few things have happened to stall development:
1) Running. I was injured over summer (that's Dec-Feb down here) and couldn't train - all that extra free time went into developing Geoquery. Now I'm back in training.
2) Holidays. Spent a few weeks in Thailand and Bhutan.
3) Job. It's busier now.
4) I was using the demo version Visual Studio 2008. It's expired. The Express versions just don't cut it for "real" work.
5) I can't help thinking Microsoft is going to release something similar themselves. It was great fun building it up to v0.72, but now real hard work is required to get the functionality "to the next level". That's a lot of effort for "nothing", less fun and more sweat.

I saw today that Google Maps now has a Flash API (and demos), something Yahoo has had for a while. I might get back to playing with silverlightearth.com and deepzoompublisher.com in Silverlight 2.0.

There may yet be a way to tie them all together: converting silverlightearth.com to Silverlight 2.0 will result in a whole pile of C# and Xaml that would then plug right into Geoquery 2008. Will see how things develop... ;-)

DeepZoom "Publisher" with Xps (part 1)

Further to this post about turning a PDF document into a Silverlight 2.0 DeepZoom image, here is some code to parse an XPS document into individual PNG images which can then be turned into DeepZoom content. It's slightly updated from this MSDN forum post: How to convert xps documents to other formats, for example bmp.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Documents;
using System.Windows.Xps.Packaging;
using System.Windows.Media.Imaging;
using System.Windows.Media;
// class definition...
static public void SaveXpsToPng(string xpsFileName)
{
XpsDocument xpsDoc = new XpsDocument(xpsFileName, System.IO.FileAccess.Read);
FixedDocumentSequence docSeq = xpsDoc.GetFixedDocumentSequence();
Dictionary<string, string> docPageText = new Dictionary<string, string>();
string txtPage;

for (int pageNum = 0; pageNum < docSeq.DocumentPaginator.PageCount; pageNum++)
{
DocumentPage docPage = docSeq.DocumentPaginator.GetPage(pageNum);
txtPage = string.Empty;

foreach (System.Windows.UIElement uie in ((FixedPage)docPage.Visual).Children)
{
if (uie is System.Windows.Documents.Glyphs)
{
txtPage += ((System.Windows.Documents.Glyphs)uie).UnicodeString;
}
}

BitmapImage bitmap = new BitmapImage();
RenderTargetBitmap renderTarget =
new RenderTargetBitmap((int)(docPage.Size.Width * 300/96),
(int)(docPage.Size.Height * 300/96),
300,
300,
PixelFormats.Pbgra32);
renderTarget.Render(docPage.Visual);

BitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderTarget));
string filename = xpsFileName + ".Page" + pageNum;
FileStream pageOutStream = new FileStream(filename+".png", FileMode.Create, FileAccess.Write);
encoder.Save(pageOutStream);
pageOutStream.Close();
// oh, and save the text too
System.IO.File.WriteAllText(filename + ".txt", txtPage);
}
}

The output files look like this. Two things to note:
1) the PNGs are between 1 and 3Mb in size (around 300dpi I think)
2) there is a .txt file for each image (look carefully in the code above).



Here is one of the images and its associated .txt file



Why output a text file you ask? For indexing and searching! It's debateable whether it makes sense to use DeepZoom as a mechanism for published 'documents' when you can use PDF or the Silverlight 2 XPS Viewer, however for graphically heavy content (say... magazines, photo books) a searchable, indexable DeepZoom collection could actually be a better user experience (particularly for browsing).

Anyway, this is only half the solution - we've got images and text OUT of the Xps document with that code, but we haven't yet processed them IN to DeepZoom via the DeepZoom Composer (Seadragon/Mermaid)... stay tuned...